Initial commit: CloudOps infrastructure platform
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
# Workflow name:
|
||||
name: Close Pull Requests
|
||||
|
||||
# Workflow triggers:
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened]
|
||||
|
||||
# Workflow jobs:
|
||||
jobs:
|
||||
run:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: superbrothers/close-pull-request@v3
|
||||
with:
|
||||
comment: |
|
||||
Thank you for submitting a pull request. :raised_hands:
|
||||
|
||||
We greatly appreciate your willingness to submit a contribution. However, we are not accepting pull requests against this repository, as all development happens on the [main project repository](https://github.com/mautic/mautic).
|
||||
|
||||
We kindly request that you submit this pull request against the [respective directory](https://github.com/mautic/mautic/blob/head/plugins/MauticFullContactBundle) of the main repository where we'll review and provide feedback. If this is your first Mautic contribution, be sure to read the [contributing guide](https://github.com/mautic/mautic/blob/4.x/.github/CONTRIBUTING.md) which provides guidelines and instructions for submitting contributions.
|
||||
|
||||
Thank you again, and we look forward to receiving your contribution! :smiley:
|
||||
|
||||
Best,
|
||||
The Mautic team
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.1 KiB |
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* @copyright 2014 Mautic Contributors. All rights reserved
|
||||
* @author Mautic
|
||||
*
|
||||
* @link http://mautic.org
|
||||
*
|
||||
* @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*/
|
||||
|
||||
Mautic.testFullContactApi = function (btn) {
|
||||
mQuery(btn).prop('disabled', true);
|
||||
var apikey = mQuery('#integration_details_apiKeys_apikey').val();
|
||||
var d = new Date();
|
||||
var month = d.getMonth() + 1;
|
||||
var period = d.getFullYear() + '-' + ((month < 10) ? '0' + month : month);
|
||||
var months = new Array();
|
||||
months[0] = "January";
|
||||
months[1] = "February";
|
||||
months[2] = "March";
|
||||
months[3] = "April";
|
||||
months[4] = "May";
|
||||
months[5] = "June";
|
||||
months[6] = "July";
|
||||
months[7] = "August";
|
||||
months[8] = "September";
|
||||
months[9] = "October";
|
||||
months[10] = "November";
|
||||
months[11] = "December";
|
||||
var dateString = months[month - 1] + ' ' + d.getFullYear();
|
||||
var EOL = String.fromCharCode(13);
|
||||
mQuery.get('https://api.fullcontact.com/v2/stats.json?apiKey=' + apikey + '&period=' + period, function (stats) {
|
||||
var person = null;
|
||||
var company = null;
|
||||
var free = null;
|
||||
mQuery.each(stats.metrics, function (i, m) {
|
||||
if ('200' === m.metricId) {
|
||||
person = m;
|
||||
} else if ('company_200' === m.metricId) {
|
||||
company = m;
|
||||
} else if ('200_free' === m.metricId) {
|
||||
free = m;
|
||||
}
|
||||
});
|
||||
var result = 'Plan Details: ' + stats.plan + EOL + EOL +
|
||||
'Quick Usage Stats for ' + dateString + ':' + EOL;
|
||||
|
||||
if (person) {
|
||||
result += ' - Person API: ' + person.usage + ' matches used from ' + person.planLevel + ' (' + person.remaining + ' remaining)' + EOL;
|
||||
}
|
||||
|
||||
if (company) {
|
||||
result += ' - Company API: ' + company.usage + ' matches used from ' + company.planLevel + ' (' + company.remaining + ' remaining)' + EOL;
|
||||
}
|
||||
|
||||
if (free) {
|
||||
result += ' - Name/Location/Stats: ' + free.usage + ' matches used from ' + free.planLevel + ' (' + free.remaining + ' remaining)' + EOL;
|
||||
}
|
||||
|
||||
mQuery('#integration_details_apiKeys_stats').val(result);
|
||||
}).fail(function(error) {
|
||||
mQuery('#integration_details_apiKeys_stats').val((error.responseJSON && error.responseJSON.message)?error.responseJSON.message:'Error: ' + JSON.stringify(error));
|
||||
});
|
||||
mQuery(btn).prop('disabled', false);
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'name' => 'FullContact',
|
||||
'description' => 'Enables integration with FullContact for contact and company lookup',
|
||||
'version' => '1.0',
|
||||
'author' => 'Mautic',
|
||||
|
||||
'routes' => [
|
||||
'public' => [
|
||||
'mautic_plugin_fullcontact_index' => [
|
||||
'path' => '/fullcontact/callback',
|
||||
'controller' => 'MauticPlugin\MauticFullContactBundle\Controller\PublicController::callbackAction',
|
||||
],
|
||||
],
|
||||
'main' => [
|
||||
'mautic_plugin_fullcontact_action' => [
|
||||
'path' => '/fullcontact/{objectAction}/{objectId}',
|
||||
'controller' => 'MauticPlugin\MauticFullContactBundle\Controller\FullContactController::executeAction',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'services' => [
|
||||
'others' => [
|
||||
'mautic.plugin.fullcontact.lookup_helper' => [
|
||||
'class' => MauticPlugin\MauticFullContactBundle\Helper\LookupHelper::class,
|
||||
'arguments' => [
|
||||
'mautic.helper.integration',
|
||||
'mautic.helper.user',
|
||||
'monolog.logger.mautic',
|
||||
'router',
|
||||
'mautic.lead.model.lead',
|
||||
'mautic.lead.model.company',
|
||||
],
|
||||
],
|
||||
],
|
||||
'integrations' => [
|
||||
'mautic.integration.fullcontact' => [
|
||||
'class' => MauticPlugin\MauticFullContactBundle\Integration\FullContactIntegration::class,
|
||||
'arguments' => [
|
||||
'event_dispatcher',
|
||||
'mautic.helper.cache_storage',
|
||||
'doctrine.orm.entity_manager',
|
||||
'request_stack',
|
||||
'router',
|
||||
'translator',
|
||||
'monolog.logger.mautic',
|
||||
'mautic.helper.encryption',
|
||||
'mautic.lead.model.lead',
|
||||
'mautic.lead.model.company',
|
||||
'mautic.helper.paths',
|
||||
'mautic.core.model.notification',
|
||||
'mautic.lead.model.field',
|
||||
'mautic.plugin.model.integration_entity',
|
||||
'mautic.lead.model.dnc',
|
||||
'mautic.lead.field.fields_with_unique_identifier',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Mautic\CoreBundle\DependencyInjection\MauticCoreExtension;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return function (ContainerConfigurator $configurator): void {
|
||||
$services = $configurator->services()
|
||||
->defaults()
|
||||
->autowire()
|
||||
->autoconfigure()
|
||||
->public();
|
||||
|
||||
$excludes = [
|
||||
'Services',
|
||||
];
|
||||
|
||||
$services->load('MauticPlugin\\MauticFullContactBundle\\', '../')
|
||||
->exclude('../{'.implode(',', array_merge(MauticCoreExtension::DEFAULT_EXCLUDES, $excludes)).'}');
|
||||
};
|
||||
@@ -0,0 +1,520 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\Controller;
|
||||
|
||||
use Mautic\FormBundle\Controller\FormController;
|
||||
use Mautic\LeadBundle\Entity\Company;
|
||||
use Mautic\LeadBundle\Entity\Lead;
|
||||
use MauticPlugin\MauticFullContactBundle\Form\Type\BatchLookupType;
|
||||
use MauticPlugin\MauticFullContactBundle\Form\Type\LookupType;
|
||||
use MauticPlugin\MauticFullContactBundle\Helper\LookupHelper;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class FullContactController extends FormController
|
||||
{
|
||||
/**
|
||||
* @param string $objectId
|
||||
*
|
||||
* @return JsonResponse
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function lookupPersonAction(Request $request, LookupHelper $lookupHelper, $objectId = '')
|
||||
{
|
||||
if ('POST' === $request->getMethod()) {
|
||||
$data = $request->request->all()['fullcontact_lookup'] ?? [];
|
||||
$objectId = $data['objectId'];
|
||||
}
|
||||
/** @var \Mautic\LeadBundle\Model\LeadModel $model */
|
||||
$model = $this->getModel('lead');
|
||||
$lead = $model->getEntity($objectId);
|
||||
|
||||
if (!$this->security->hasEntityAccess(
|
||||
'lead:leads:editown',
|
||||
'lead:leads:editother',
|
||||
$lead->getPermissionUser()
|
||||
)
|
||||
) {
|
||||
$this->addFlashMessage(
|
||||
$this->translator->trans('mautic.plugin.fullcontact.forbidden'),
|
||||
[],
|
||||
'error'
|
||||
);
|
||||
|
||||
return new JsonResponse(
|
||||
[
|
||||
'closeModal' => true,
|
||||
'flashes' => $this->getFlashContent(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
if ('GET' === $request->getMethod()) {
|
||||
$route = $this->generateUrl(
|
||||
'mautic_plugin_fullcontact_action',
|
||||
[
|
||||
'objectAction' => 'lookupPerson',
|
||||
]
|
||||
);
|
||||
|
||||
return $this->delegateView(
|
||||
[
|
||||
'viewParameters' => [
|
||||
'form' => $this->createForm(
|
||||
LookupType::class,
|
||||
[
|
||||
'objectId' => $objectId,
|
||||
],
|
||||
[
|
||||
'action' => $route,
|
||||
]
|
||||
)->createView(),
|
||||
'lookupItem' => $lead->getEmail(),
|
||||
],
|
||||
'contentTemplate' => '@MauticFullContact/FullContact/lookup.html.twig',
|
||||
'passthroughVars' => [
|
||||
'activeLink' => '#mautic_contact_index',
|
||||
'mauticContent' => 'lead',
|
||||
'route' => $route,
|
||||
],
|
||||
]
|
||||
);
|
||||
} else {
|
||||
if ('POST' === $request->getMethod()) {
|
||||
try {
|
||||
$lookupHelper->lookupContact($lead, array_key_exists('notify', $data));
|
||||
$this->addFlashMessage(
|
||||
'mautic.lead.batch_leads_affected',
|
||||
[
|
||||
'%count%' => 1,
|
||||
]
|
||||
);
|
||||
} catch (\Exception $ex) {
|
||||
$this->addFlashMessage(
|
||||
$ex->getMessage(),
|
||||
[],
|
||||
'error'
|
||||
);
|
||||
}
|
||||
|
||||
return new JsonResponse(
|
||||
[
|
||||
'closeModal' => true,
|
||||
'flashes' => $this->getFlashContent(),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return new Response('Bad Request', 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JsonResponse
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function batchLookupPersonAction(Request $request, LookupHelper $lookupHelper)
|
||||
{
|
||||
/** @var \Mautic\LeadBundle\Model\LeadModel $model */
|
||||
$model = $this->getModel('lead');
|
||||
if ('GET' === $request->getMethod()) {
|
||||
$data = $request->query->all()['fullcontact_batch_lookup'] ?? [];
|
||||
} else {
|
||||
$data = $request->request->all()['fullcontact_batch_lookup'] ?? [];
|
||||
}
|
||||
|
||||
$entities = [];
|
||||
if (array_key_exists('ids', $data)) {
|
||||
$ids = $data['ids'];
|
||||
|
||||
if (!is_array($ids)) {
|
||||
$ids = json_decode($ids, true);
|
||||
}
|
||||
|
||||
if (is_array($ids) && count($ids)) {
|
||||
$entities = $model->getEntities(
|
||||
[
|
||||
'filter' => [
|
||||
'force' => [
|
||||
[
|
||||
'column' => 'l.id',
|
||||
'expr' => 'in',
|
||||
'value' => $ids,
|
||||
],
|
||||
],
|
||||
],
|
||||
'ignore_paginator' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$lookupEmails = [];
|
||||
if ($count = count($entities)) {
|
||||
/** @var Lead $lead */
|
||||
foreach ($entities as $lead) {
|
||||
if ($this->security->hasEntityAccess(
|
||||
'lead:leads:editown',
|
||||
'lead:leads:editother',
|
||||
$lead->getPermissionUser()
|
||||
)
|
||||
&& $lead->getEmail()
|
||||
) {
|
||||
$lookupEmails[$lead->getId()] = $lead->getEmail();
|
||||
}
|
||||
}
|
||||
|
||||
$count = count($lookupEmails);
|
||||
}
|
||||
|
||||
if (0 === $count) {
|
||||
$this->addFlashMessage(
|
||||
$this->translator->trans('mautic.plugin.fullcontact.empty'),
|
||||
[],
|
||||
'error'
|
||||
);
|
||||
|
||||
return new JsonResponse(
|
||||
[
|
||||
'closeModal' => true,
|
||||
'flashes' => $this->getFlashContent(),
|
||||
]
|
||||
);
|
||||
} else {
|
||||
if ($count > 20) {
|
||||
$this->addFlashMessage(
|
||||
$this->translator->trans('mautic.plugin.fullcontact.toomany'),
|
||||
[],
|
||||
'error'
|
||||
);
|
||||
|
||||
return new JsonResponse(
|
||||
[
|
||||
'closeModal' => true,
|
||||
'flashes' => $this->getFlashContent(),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
if ('GET' === $request->getMethod()) {
|
||||
$route = $this->generateUrl(
|
||||
'mautic_plugin_fullcontact_action',
|
||||
[
|
||||
'objectAction' => 'batchLookupPerson',
|
||||
]
|
||||
);
|
||||
|
||||
return $this->delegateView(
|
||||
[
|
||||
'viewParameters' => [
|
||||
'form' => $this->createForm(
|
||||
BatchLookupType::class,
|
||||
[],
|
||||
[
|
||||
'action' => $route,
|
||||
]
|
||||
)->createView(),
|
||||
'lookupItems' => array_values($lookupEmails),
|
||||
],
|
||||
'contentTemplate' => '@MauticFullContact/FullContact/batchLookup.html.twig',
|
||||
'passthroughVars' => [
|
||||
'activeLink' => '#mautic_contact_index',
|
||||
'mauticContent' => 'leadBatch',
|
||||
'route' => $route,
|
||||
],
|
||||
]
|
||||
);
|
||||
} else {
|
||||
if ('POST' === $request->getMethod()) {
|
||||
$notify = array_key_exists('notify', $data);
|
||||
foreach ($lookupEmails as $id => $lookupEmail) {
|
||||
if ($lead = $model->getEntity($id)) {
|
||||
try {
|
||||
$lookupHelper->lookupContact($lead, $notify);
|
||||
} catch (\Exception $ex) {
|
||||
$this->addFlashMessage(
|
||||
$ex->getMessage(),
|
||||
[],
|
||||
'error'
|
||||
);
|
||||
--$count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($count) {
|
||||
$this->addFlashMessage(
|
||||
'mautic.lead.batch_leads_affected',
|
||||
[
|
||||
'%count%' => $count,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return new JsonResponse(
|
||||
[
|
||||
'closeModal' => true,
|
||||
'flashes' => $this->getFlashContent(),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return new Response('Bad Request', 400);
|
||||
}
|
||||
|
||||
/***************** COMPANY ***********************/
|
||||
|
||||
/**
|
||||
* @param string $objectId
|
||||
*
|
||||
* @return JsonResponse
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function lookupCompanyAction(Request $request, LookupHelper $lookupHelper, $objectId = '')
|
||||
{
|
||||
if ('POST' === $request->getMethod()) {
|
||||
$data = $request->request->all()['fullcontact_lookup'] ?? [];
|
||||
$objectId = $data['objectId'];
|
||||
}
|
||||
/** @var \Mautic\LeadBundle\Model\CompanyModel $model */
|
||||
$model = $this->getModel('lead.company');
|
||||
/** @var Company $company */
|
||||
$company = $model->getEntity($objectId);
|
||||
|
||||
if ('GET' === $request->getMethod()) {
|
||||
$route = $this->generateUrl(
|
||||
'mautic_plugin_fullcontact_action',
|
||||
[
|
||||
'objectAction' => 'lookupCompany',
|
||||
]
|
||||
);
|
||||
|
||||
$website = $company->getFieldValue('companywebsite');
|
||||
|
||||
if (!$website) {
|
||||
$this->addFlashMessage(
|
||||
$this->translator->trans('mautic.plugin.fullcontact.compempty'),
|
||||
[],
|
||||
'error'
|
||||
);
|
||||
|
||||
return new JsonResponse(
|
||||
[
|
||||
'closeModal' => true,
|
||||
'flashes' => $this->getFlashContent(),
|
||||
]
|
||||
);
|
||||
}
|
||||
$parse = parse_url($website);
|
||||
|
||||
return $this->delegateView(
|
||||
[
|
||||
'viewParameters' => [
|
||||
'form' => $this->createForm(
|
||||
LookupType::class,
|
||||
[
|
||||
'objectId' => $objectId,
|
||||
],
|
||||
[
|
||||
'action' => $route,
|
||||
]
|
||||
)->createView(),
|
||||
'lookupItem' => $parse['host'],
|
||||
],
|
||||
'contentTemplate' => '@MauticFullContact/FullContact/lookup.html.twig',
|
||||
'passthroughVars' => [
|
||||
'activeLink' => '#mautic_company_index',
|
||||
'mauticContent' => 'company',
|
||||
'route' => $route,
|
||||
],
|
||||
]
|
||||
);
|
||||
} else {
|
||||
if ('POST' === $request->getMethod()) {
|
||||
try {
|
||||
$lookupHelper->lookupCompany($company, array_key_exists('notify', $data));
|
||||
$this->addFlashMessage(
|
||||
'mautic.company.batch_companies_affected',
|
||||
[
|
||||
'%count%' => 1,
|
||||
]
|
||||
);
|
||||
} catch (\Exception $ex) {
|
||||
$this->addFlashMessage(
|
||||
$ex->getMessage(),
|
||||
[],
|
||||
'error'
|
||||
);
|
||||
}
|
||||
|
||||
return new JsonResponse(
|
||||
[
|
||||
'closeModal' => true,
|
||||
'flashes' => $this->getFlashContent(),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return new Response('Bad Request', 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JsonResponse
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function batchLookupCompanyAction(Request $request, LookupHelper $lookupHelper)
|
||||
{
|
||||
/** @var \Mautic\LeadBundle\Model\CompanyModel $model */
|
||||
$model = $this->getModel('lead.company');
|
||||
if ('GET' === $request->getMethod()) {
|
||||
$data = $request->query->all()['fullcontact_batch_lookup'] ?? [];
|
||||
} else {
|
||||
$data = $request->request->all()['fullcontact_batch_lookup'] ?? [];
|
||||
}
|
||||
|
||||
$entities = [];
|
||||
if (array_key_exists('ids', $data)) {
|
||||
$ids = $data['ids'];
|
||||
|
||||
if (!is_array($ids)) {
|
||||
$ids = json_decode($ids, true);
|
||||
}
|
||||
|
||||
if (is_array($ids) && count($ids)) {
|
||||
$entities = $model->getEntities(
|
||||
[
|
||||
'filter' => [
|
||||
'force' => [
|
||||
[
|
||||
'column' => 'comp.id',
|
||||
'expr' => 'in',
|
||||
'value' => $ids,
|
||||
],
|
||||
],
|
||||
],
|
||||
'ignore_paginator' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$lookupWebsites = [];
|
||||
if ($count = count($entities)) {
|
||||
/** @var Company $company */
|
||||
foreach ($entities as $company) {
|
||||
if ($company->getFieldValue('companywebsite')) {
|
||||
$website = $company->getFieldValue('companywebsite');
|
||||
$parse = parse_url($website);
|
||||
if (!isset($parse['host'])) {
|
||||
continue;
|
||||
}
|
||||
$lookupWebsites[$company->getId()] = $parse['host'];
|
||||
}
|
||||
}
|
||||
|
||||
$count = count($lookupWebsites);
|
||||
}
|
||||
|
||||
if (0 === $count) {
|
||||
$this->addFlashMessage(
|
||||
$this->translator->trans('mautic.plugin.fullcontact.compempty'),
|
||||
[],
|
||||
'error'
|
||||
);
|
||||
|
||||
return new JsonResponse(
|
||||
[
|
||||
'closeModal' => true,
|
||||
'flashes' => $this->getFlashContent(),
|
||||
]
|
||||
);
|
||||
} else {
|
||||
if ($count > 20) {
|
||||
$this->addFlashMessage(
|
||||
$this->translator->trans('mautic.plugin.fullcontact.comptoomany'),
|
||||
[],
|
||||
'error'
|
||||
);
|
||||
|
||||
return new JsonResponse(
|
||||
[
|
||||
'closeModal' => true,
|
||||
'flashes' => $this->getFlashContent(),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
if ('GET' === $request->getMethod()) {
|
||||
$route = $this->generateUrl(
|
||||
'mautic_plugin_fullcontact_action',
|
||||
[
|
||||
'objectAction' => 'batchLookupCompany',
|
||||
]
|
||||
);
|
||||
|
||||
return $this->delegateView(
|
||||
[
|
||||
'viewParameters' => [
|
||||
'form' => $this->createForm(
|
||||
BatchLookupType::class,
|
||||
[],
|
||||
[
|
||||
'action' => $route,
|
||||
]
|
||||
)->createView(),
|
||||
'lookupItems' => array_values($lookupWebsites),
|
||||
],
|
||||
'contentTemplate' => '@MauticFullContact/FullContact/batchLookup.html.twig',
|
||||
'passthroughVars' => [
|
||||
'activeLink' => '#mautic_company_index',
|
||||
'mauticContent' => 'companyBatch',
|
||||
'route' => $route,
|
||||
],
|
||||
]
|
||||
);
|
||||
} else {
|
||||
if ('POST' === $request->getMethod()) {
|
||||
$notify = array_key_exists('notify', $data);
|
||||
foreach ($lookupWebsites as $id => $lookupWebsite) {
|
||||
if ($company = $model->getEntity($id)) {
|
||||
try {
|
||||
$lookupHelper->lookupCompany($company, $notify);
|
||||
} catch (\Exception $ex) {
|
||||
$this->addFlashMessage(
|
||||
$ex->getMessage(),
|
||||
[],
|
||||
'error'
|
||||
);
|
||||
--$count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($count) {
|
||||
$this->addFlashMessage(
|
||||
'mautic.company.batch_companies_affected',
|
||||
[
|
||||
'%count%' => $count,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return new JsonResponse(
|
||||
[
|
||||
'closeModal' => true,
|
||||
'flashes' => $this->getFlashContent(),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return new Response('Bad Request', 400);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,388 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\Controller;
|
||||
|
||||
use Mautic\FormBundle\Controller\FormController;
|
||||
use Mautic\LeadBundle\Entity\Company;
|
||||
use Mautic\LeadBundle\Entity\Lead;
|
||||
use Mautic\UserBundle\Entity\User;
|
||||
use Mautic\UserBundle\Model\UserModel;
|
||||
use MauticPlugin\MauticFullContactBundle\Helper\LookupHelper;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class PublicController extends FormController
|
||||
{
|
||||
/**
|
||||
* Write a notification.
|
||||
*
|
||||
* @param string $message Message of the notification
|
||||
* @param string $header Header for message
|
||||
* @param string $iconClass CSS class for the icon (e.g. ri-eye-line)
|
||||
* @param User|null $user User object; defaults to current user
|
||||
*/
|
||||
public function addNewNotification($message, $header, $iconClass, User $user): void
|
||||
{
|
||||
/** @var \Mautic\CoreBundle\Model\NotificationModel $notificationModel */
|
||||
$notificationModel = $this->getModel('core.notification');
|
||||
$notificationModel->addNotification($message, 'FullContact', false, $header, $iconClass, null, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function callbackAction(Request $request, LookupHelper $lookupHelper, LoggerInterface $mauticLogger)
|
||||
{
|
||||
if (!$request->request->has('result') || !$request->request->has('webhookId')) {
|
||||
return new Response('ERROR');
|
||||
}
|
||||
|
||||
$result = json_decode($request->request->all()['result'] ?? [], true);
|
||||
$oid = $request->request->get('webhookId', '');
|
||||
$validatedRequest = $lookupHelper->validateRequest($oid);
|
||||
|
||||
if (!$validatedRequest || !is_array($result)) {
|
||||
return new Response('ERROR');
|
||||
}
|
||||
|
||||
if ('company' == $validatedRequest['type']) {
|
||||
return $this->compcallbackAction($mauticLogger, $result, $validatedRequest);
|
||||
}
|
||||
|
||||
$notify = $validatedRequest['notify'];
|
||||
|
||||
try {
|
||||
/** @var \Mautic\LeadBundle\Model\LeadModel $model */
|
||||
$model = $this->getModel('lead');
|
||||
/** @var Lead $lead */
|
||||
$lead = $validatedRequest['entity'];
|
||||
$currFields = $lead->getFields(true);
|
||||
|
||||
$org = [];
|
||||
if (array_key_exists('organizations', $result)) {
|
||||
/** @var array $organizations */
|
||||
$organizations = $result['organizations'];
|
||||
foreach ($organizations as $organization) {
|
||||
if (array_key_exists('isPrimary', $organization) && !empty($organization['isPrimary'])) {
|
||||
$org = $organization;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 === count($org) && 0 !== count($result['organizations'])) {
|
||||
// primary not found, use the first one if exists
|
||||
$org = $result['organizations'][0];
|
||||
}
|
||||
}
|
||||
|
||||
$loc = [];
|
||||
if (array_key_exists('demographics', $result)
|
||||
&& array_key_exists(
|
||||
'locationDeduced',
|
||||
$result['demographics']
|
||||
)
|
||||
) {
|
||||
$loc = $result['demographics']['locationDeduced'];
|
||||
}
|
||||
|
||||
$data = [];
|
||||
/** @var array $socialProfiles */
|
||||
$socialProfiles = [];
|
||||
if (array_key_exists('socialProfiles', $result)) {
|
||||
$socialProfiles = $result['socialProfiles'];
|
||||
}
|
||||
foreach (['facebook', 'foursquare', 'instagram', 'linkedin', 'twitter'] as $p) {
|
||||
foreach ($socialProfiles as $socialProfile) {
|
||||
if (array_key_exists('type', $socialProfile) && $socialProfile['type'] === $p && empty($currFields[$p]['value'])) {
|
||||
$data[$p] = array_key_exists('url', $socialProfile) ? $socialProfile['url'] : '';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists('contactInfo', $result)) {
|
||||
if (array_key_exists(
|
||||
'familyName',
|
||||
$result['contactInfo']
|
||||
)
|
||||
&& empty($currFields['lastname']['value'])
|
||||
) {
|
||||
$data['lastname'] = $result['contactInfo']['familyName'];
|
||||
}
|
||||
|
||||
if (array_key_exists(
|
||||
'givenName',
|
||||
$result['contactInfo']
|
||||
)
|
||||
&& empty($currFields['firstname']['value'])
|
||||
) {
|
||||
$data['firstname'] = $result['contactInfo']['givenName'];
|
||||
}
|
||||
|
||||
if ((array_key_exists('websites', $result['contactInfo'])
|
||||
&& count(
|
||||
$result['contactInfo']['websites']
|
||||
))
|
||||
&& empty($currFields['website']['value'])
|
||||
) {
|
||||
$data['website'] = $result['contactInfo']['websites'][0]['url'];
|
||||
}
|
||||
|
||||
if ((array_key_exists('chats', $result['contactInfo'])
|
||||
&& array_key_exists(
|
||||
'skype',
|
||||
$result['contactInfo']['chats']
|
||||
))
|
||||
&& empty($currFields['skype']['value'])
|
||||
) {
|
||||
$data['skype'] = $result['contactInfo']['chats']['skype']['handle'];
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists('name', $org) && empty($currFields['company']['value'])) {
|
||||
$data['company'] = $org['name'];
|
||||
}
|
||||
|
||||
if (array_key_exists('title', $org) && empty($currFields['position']['value'])) {
|
||||
$data['position'] = $org['title'];
|
||||
}
|
||||
|
||||
if ((array_key_exists('city', $loc)
|
||||
&& array_key_exists(
|
||||
'name',
|
||||
$loc['city']
|
||||
))
|
||||
&& empty($currFields['city']['value'])
|
||||
) {
|
||||
$data['city'] = $loc['city']['name'];
|
||||
}
|
||||
|
||||
if ((array_key_exists('state', $loc)
|
||||
&& array_key_exists(
|
||||
'name',
|
||||
$loc['state']
|
||||
))
|
||||
&& empty($currFields['state']['value'])
|
||||
) {
|
||||
$data['state'] = $loc['state']['name'];
|
||||
}
|
||||
|
||||
if ((array_key_exists('country', $loc)
|
||||
&& array_key_exists(
|
||||
'name',
|
||||
$loc['country']
|
||||
))
|
||||
&& empty($currFields['country']['value'])
|
||||
) {
|
||||
$data['country'] = $loc['country']['name'];
|
||||
}
|
||||
|
||||
$mauticLogger->log('debug', 'SET FIELDS: '.print_r($data, true));
|
||||
|
||||
// Unset the nonce so that it's not used again
|
||||
$socialCache = $lead->getSocialCache();
|
||||
unset($socialCache['fullcontact']['nonce']);
|
||||
$lead->setSocialCache($socialCache);
|
||||
|
||||
$model->setFieldValues($lead, $data);
|
||||
$model->getRepository()->saveEntity($lead);
|
||||
|
||||
if ($notify && (!isset($lead->imported) || !$lead->imported)) {
|
||||
/** @var UserModel $userModel */
|
||||
$userModel = $this->getModel('user');
|
||||
|
||||
if ($user = $userModel->getEntity($notify)) {
|
||||
$this->addNewNotification(
|
||||
sprintf($this->translator->trans('mautic.plugin.fullcontact.contact_retrieved'), $lead->getEmail()),
|
||||
'FullContact Plugin',
|
||||
'ri-search-line',
|
||||
$user
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $ex) {
|
||||
try {
|
||||
if ($notify && $lead && (!isset($lead->imported) || !$lead->imported)) {
|
||||
/** @var UserModel $userModel */
|
||||
$userModel = $this->getModel('user');
|
||||
if ($user = $userModel->getEntity($notify)) {
|
||||
$this->addNewNotification(
|
||||
sprintf(
|
||||
$this->translator->trans('mautic.plugin.fullcontact.unable'),
|
||||
$lead->getEmail(),
|
||||
$ex->getMessage()
|
||||
),
|
||||
'FullContact Plugin',
|
||||
'ri-error-warning-line',
|
||||
$user
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $ex2) {
|
||||
$mauticLogger->log('error', 'FullContact: '.$ex2->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return new Response('OK');
|
||||
}
|
||||
|
||||
/**
|
||||
* This is only called internally.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function compcallbackAction(LoggerInterface $mauticLogger, $result, $validatedRequest): Response
|
||||
{
|
||||
$notify = $validatedRequest['notify'];
|
||||
|
||||
try {
|
||||
/** @var \Mautic\LeadBundle\Model\CompanyModel $model */
|
||||
$model = $this->getModel('lead.company');
|
||||
/** @var Company $company */
|
||||
$company = $validatedRequest['entity'];
|
||||
$currFields = $company->getFields(true);
|
||||
|
||||
$org = [];
|
||||
$loc = [];
|
||||
$phone = [];
|
||||
$fax = [];
|
||||
$email = [];
|
||||
if (array_key_exists('organization', $result)) {
|
||||
$org = $result['organization'];
|
||||
if (array_key_exists('contactInfo', $result['organization'])) {
|
||||
if (array_key_exists('addresses', $result['organization']['contactInfo'])
|
||||
&& count(
|
||||
$result['organization']['contactInfo']['addresses']
|
||||
)
|
||||
) {
|
||||
$loc = $result['organization']['contactInfo']['addresses'][0];
|
||||
}
|
||||
if (array_key_exists('emailAddresses', $result['organization']['contactInfo'])
|
||||
&& count(
|
||||
$result['organization']['contactInfo']['emailAddresses']
|
||||
)
|
||||
) {
|
||||
$email = $result['organization']['contactInfo']['emailAddresses'][0];
|
||||
}
|
||||
if (array_key_exists('phoneNumbers', $result['organization']['contactInfo'])
|
||||
&& count(
|
||||
$result['organization']['contactInfo']['phoneNumbers']
|
||||
)
|
||||
) {
|
||||
$phone = $result['organization']['contactInfo']['phoneNumbers'][0];
|
||||
foreach ($result['organization']['contactInfo']['phoneNumbers'] as $phoneNumber) {
|
||||
if (array_key_exists('label', $phoneNumber)
|
||||
&& 0 >= strpos(
|
||||
strtolower($phoneNumber['label']),
|
||||
'fax'
|
||||
)
|
||||
) {
|
||||
$fax = $phoneNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$data = [];
|
||||
|
||||
if (array_key_exists('addressLine1', $loc) && empty($currFields['companyaddress1']['value'])) {
|
||||
$data['companyaddress1'] = $loc['addressLine1'];
|
||||
}
|
||||
|
||||
if (array_key_exists('addressLine2', $loc) && empty($currFields['companyaddress2']['value'])) {
|
||||
$data['companyaddress2'] = $loc['addressLine2'];
|
||||
}
|
||||
|
||||
if (array_key_exists('value', $email) && empty($currFields['companyemail']['value'])) {
|
||||
$data['companyemail'] = $email['value'];
|
||||
}
|
||||
|
||||
if (array_key_exists('number', $phone) && empty($currFields['companyphone']['value'])) {
|
||||
$data['companyphone'] = $phone['number'];
|
||||
}
|
||||
|
||||
if (array_key_exists('locality', $loc) && empty($currFields['companycity']['value'])) {
|
||||
$data['companycity'] = $loc['locality'];
|
||||
}
|
||||
|
||||
if (array_key_exists('postalCode', $loc) && empty($currFields['companyzipcode']['value'])) {
|
||||
$data['companyzipcode'] = $loc['postalCode'];
|
||||
}
|
||||
|
||||
if (array_key_exists('region', $loc) && empty($currFields['companystate']['value'])) {
|
||||
$data['companystate'] = $loc['region']['name'];
|
||||
}
|
||||
|
||||
if (array_key_exists('country', $loc) && empty($currFields['companycountry']['value'])) {
|
||||
$data['companycountry'] = $loc['country']['name'];
|
||||
}
|
||||
|
||||
if (array_key_exists('name', $org) && empty($currFields['companydescription']['value'])) {
|
||||
$data['companydescription'] = $org['name'];
|
||||
}
|
||||
|
||||
if (array_key_exists(
|
||||
'approxEmployees',
|
||||
$org
|
||||
)
|
||||
&& empty($currFields['companynumber_of_employees']['value'])
|
||||
) {
|
||||
$data['companynumber_of_employees'] = $org['approxEmployees'];
|
||||
}
|
||||
|
||||
if (array_key_exists('number', $fax) && empty($currFields['companyfax']['value'])) {
|
||||
$data['companyfax'] = $fax['number'];
|
||||
}
|
||||
|
||||
$mauticLogger->log('debug', 'SET FIELDS: '.print_r($data, true));
|
||||
|
||||
// Unset the nonce so that it's not used again
|
||||
$socialCache = $company->getSocialCache();
|
||||
unset($socialCache['fullcontact']['nonce']);
|
||||
$company->setSocialCache($socialCache);
|
||||
|
||||
$model->setFieldValues($company, $data);
|
||||
$model->getRepository()->saveEntity($company);
|
||||
|
||||
if ($notify) {
|
||||
/** @var UserModel $userModel */
|
||||
$userModel = $this->getModel('user');
|
||||
if ($user = $userModel->getEntity($notify)) {
|
||||
$this->addNewNotification(
|
||||
sprintf($this->translator->trans('mautic.plugin.fullcontact.company_retrieved'), $company->getName()),
|
||||
'FullContact Plugin',
|
||||
'ri-search-line',
|
||||
$user
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $ex) {
|
||||
try {
|
||||
if ($notify && $company) {
|
||||
/** @var UserModel $userModel */
|
||||
$userModel = $this->getModel('user');
|
||||
if ($user = $userModel->getEntity($notify)) {
|
||||
$this->addNewNotification(
|
||||
sprintf(
|
||||
$this->translator->trans('mautic.plugin.fullcontact.unable'),
|
||||
$company->getName(),
|
||||
$ex->getMessage()
|
||||
),
|
||||
'FullContact Plugin',
|
||||
'ri-error-warning-line',
|
||||
$user
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $ex2) {
|
||||
$mauticLogger->log('error', 'FullContact: '.$ex2->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return new Response('OK');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Extension\Extension;
|
||||
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
|
||||
|
||||
class MauticFullContactExtension extends Extension
|
||||
{
|
||||
/**
|
||||
* @param mixed[] $configs
|
||||
*/
|
||||
public function load(array $configs, ContainerBuilder $container): void
|
||||
{
|
||||
$loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../Config'));
|
||||
$loader->load('services.php');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\EventListener;
|
||||
|
||||
use Mautic\CoreBundle\CoreEvents;
|
||||
use Mautic\CoreBundle\Event\CustomButtonEvent;
|
||||
use Mautic\CoreBundle\Twig\Helper\ButtonHelper;
|
||||
use Mautic\PluginBundle\Helper\IntegrationHelper;
|
||||
use MauticPlugin\MauticFullContactBundle\Integration\FullContactIntegration;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\Routing\RouterInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class ButtonSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
public function __construct(
|
||||
private IntegrationHelper $helper,
|
||||
private TranslatorInterface $translator,
|
||||
private RouterInterface $router,
|
||||
) {
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
CoreEvents::VIEW_INJECT_CUSTOM_BUTTONS => ['injectViewButtons', 0],
|
||||
];
|
||||
}
|
||||
|
||||
public function injectViewButtons(CustomButtonEvent $event): void
|
||||
{
|
||||
// get api_key from plugin settings
|
||||
/** @var FullContactIntegration $myIntegration */
|
||||
$myIntegration = $this->helper->getIntegrationObject('FullContact');
|
||||
|
||||
if (false === $myIntegration || !$myIntegration->getIntegrationSettings()->getIsPublished()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (str_starts_with($event->getRoute(), 'mautic_contact_')) {
|
||||
$event->addButton(
|
||||
[
|
||||
'attr' => [
|
||||
'class' => 'btn btn-ghost btn-sm btn-nospin',
|
||||
'data-toggle' => 'ajaxmodal',
|
||||
'data-target' => '#MauticSharedModal',
|
||||
'onclick' => 'this.href=\''.
|
||||
$this->router->generate(
|
||||
'mautic_plugin_fullcontact_action',
|
||||
['objectAction' => 'batchLookupPerson']
|
||||
).
|
||||
'?\' + mQuery.param({\'fullcontact_batch_lookup\':{\'ids\':JSON.parse(Mautic.getCheckedListIds(false, true))}});return true;',
|
||||
'data-header' => $this->translator->trans('mautic.plugin.fullcontact.button.caption'),
|
||||
],
|
||||
'btnText' => $this->translator->trans('mautic.plugin.fullcontact.button.caption'),
|
||||
'iconClass' => 'ri-search-line',
|
||||
],
|
||||
ButtonHelper::LOCATION_BULK_ACTIONS
|
||||
);
|
||||
|
||||
if ($event->getItem()) {
|
||||
$lookupContactButton = [
|
||||
'attr' => [
|
||||
'data-toggle' => 'ajaxmodal',
|
||||
'data-target' => '#MauticSharedModal',
|
||||
'data-header' => $this->translator->trans(
|
||||
'mautic.plugin.fullcontact.lookup.header',
|
||||
['%item%' => $event->getItem()->getEmail()]
|
||||
),
|
||||
'href' => $this->router->generate(
|
||||
'mautic_plugin_fullcontact_action',
|
||||
['objectId' => $event->getItem()->getId(), 'objectAction' => 'lookupPerson']
|
||||
),
|
||||
],
|
||||
'btnText' => $this->translator->trans('mautic.plugin.fullcontact.button.caption'),
|
||||
'iconClass' => 'ri-search-line',
|
||||
];
|
||||
|
||||
$event
|
||||
->addButton(
|
||||
$lookupContactButton,
|
||||
ButtonHelper::LOCATION_PAGE_ACTIONS,
|
||||
['mautic_contact_action', ['objectAction' => 'view']]
|
||||
)
|
||||
->addButton(
|
||||
$lookupContactButton,
|
||||
ButtonHelper::LOCATION_LIST_ACTIONS,
|
||||
'mautic_contact_index'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (str_starts_with($event->getRoute(), 'mautic_company_')) {
|
||||
$event->addButton(
|
||||
[
|
||||
'attr' => [
|
||||
'class' => 'btn btn-ghost btn-sm btn-nospin',
|
||||
'data-toggle' => 'ajaxmodal',
|
||||
'data-target' => '#MauticSharedModal',
|
||||
'onclick' => 'this.href=\''.
|
||||
$this->router->generate(
|
||||
'mautic_plugin_fullcontact_action',
|
||||
['objectAction' => 'batchLookupCompany']
|
||||
).
|
||||
'?\' + mQuery.param({\'fullcontact_batch_lookup\':{\'ids\':JSON.parse(Mautic.getCheckedListIds(false, true))}});return true;',
|
||||
'data-header' => $this->translator->trans(
|
||||
'mautic.plugin.fullcontact.button.caption'
|
||||
),
|
||||
],
|
||||
'btnText' => $this->translator->trans('mautic.plugin.fullcontact.button.caption'),
|
||||
'iconClass' => 'ri-search-line',
|
||||
],
|
||||
ButtonHelper::LOCATION_BULK_ACTIONS
|
||||
);
|
||||
|
||||
if ($event->getItem()) {
|
||||
$lookupCompanyButton = [
|
||||
'attr' => [
|
||||
'data-toggle' => 'ajaxmodal',
|
||||
'data-target' => '#MauticSharedModal',
|
||||
'data-header' => $this->translator->trans(
|
||||
'mautic.plugin.fullcontact.lookup.header',
|
||||
['%item%' => $event->getItem()->getName()]
|
||||
),
|
||||
'href' => $this->router->generate(
|
||||
'mautic_plugin_fullcontact_action',
|
||||
['objectId' => $event->getItem()->getId(), 'objectAction' => 'lookupCompany']
|
||||
),
|
||||
],
|
||||
'btnText' => $this->translator->trans('mautic.plugin.fullcontact.button.caption'),
|
||||
'iconClass' => 'ri-search-line',
|
||||
];
|
||||
|
||||
$event
|
||||
->addButton(
|
||||
$lookupCompanyButton,
|
||||
ButtonHelper::LOCATION_LIST_ACTIONS,
|
||||
'mautic_company_index'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\EventListener;
|
||||
|
||||
use Mautic\LeadBundle\Event\CompanyEvent;
|
||||
use Mautic\LeadBundle\Event\LeadEvent;
|
||||
use Mautic\LeadBundle\LeadEvents;
|
||||
use MauticPlugin\MauticFullContactBundle\Helper\LookupHelper;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
class LeadSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
public function __construct(
|
||||
private LookupHelper $lookupHelper,
|
||||
) {
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
LeadEvents::LEAD_POST_SAVE => ['leadPostSave', 0],
|
||||
LeadEvents::COMPANY_POST_SAVE => ['companyPostSave', 0],
|
||||
];
|
||||
}
|
||||
|
||||
public function leadPostSave(LeadEvent $event): void
|
||||
{
|
||||
$this->lookupHelper->lookupContact($event->getLead(), true, true);
|
||||
}
|
||||
|
||||
public function companyPostSave(CompanyEvent $event): void
|
||||
{
|
||||
$this->lookupHelper->lookupCompany($event->getCompany(), true, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\Exception;
|
||||
|
||||
class ApiException extends BaseException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\Exception;
|
||||
|
||||
class BaseException extends \Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\Exception;
|
||||
|
||||
class NoCreditException extends BaseException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\Exception;
|
||||
|
||||
class NotImplementedException extends BaseException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\Form\Type;
|
||||
|
||||
use Mautic\CoreBundle\Form\Type\FormButtonsType;
|
||||
use Mautic\CoreBundle\Form\Type\YesNoButtonGroupType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
/**
|
||||
* @extends AbstractType<array<string, mixed>>
|
||||
*/
|
||||
class BatchLookupType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder->add('ids', \Symfony\Component\Form\Extension\Core\Type\HiddenType::class);
|
||||
|
||||
$builder->add(
|
||||
'buttons',
|
||||
FormButtonsType::class,
|
||||
[
|
||||
'apply_text' => false,
|
||||
'save_text' => 'mautic.core.form.submit',
|
||||
'cancel_onclick' => 'javascript:void(0);',
|
||||
'cancel_attr' => [
|
||||
'data-dismiss' => 'modal',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$builder->add(
|
||||
'notify',
|
||||
YesNoButtonGroupType::class,
|
||||
[
|
||||
'label' => 'mautic.plugin.fullcontact.notify',
|
||||
'label_attr' => ['class' => 'control-label'],
|
||||
'attr' => [
|
||||
'class' => 'form-control',
|
||||
],
|
||||
'data' => true,
|
||||
'required' => false,
|
||||
]
|
||||
);
|
||||
|
||||
if (!empty($options['action'])) {
|
||||
$builder->setAction($options['action']);
|
||||
}
|
||||
}
|
||||
|
||||
public function getBlockPrefix(): string
|
||||
{
|
||||
return 'fullcontact_batch_lookup';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\Form\Type;
|
||||
|
||||
use Mautic\CoreBundle\Form\Type\FormButtonsType;
|
||||
use Mautic\CoreBundle\Form\Type\YesNoButtonGroupType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
/**
|
||||
* @extends AbstractType<array<string, mixed>>
|
||||
*/
|
||||
class LookupType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder->add(
|
||||
'objectId',
|
||||
HiddenType::class,
|
||||
[
|
||||
'attr' => [
|
||||
'value' => $options['data']['objectId'],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$builder->add(
|
||||
'buttons',
|
||||
FormButtonsType::class,
|
||||
[
|
||||
'apply_text' => false,
|
||||
'save_text' => 'mautic.core.form.submit',
|
||||
'cancel_onclick' => 'javascript:void(0);',
|
||||
'cancel_attr' => [
|
||||
'data-dismiss' => 'modal',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$builder->add(
|
||||
'notify',
|
||||
YesNoButtonGroupType::class,
|
||||
[
|
||||
'label' => 'mautic.plugin.fullcontact.notify',
|
||||
'label_attr' => ['class' => 'control-label'],
|
||||
'attr' => [
|
||||
'class' => 'form-control',
|
||||
],
|
||||
'data' => true,
|
||||
'required' => false,
|
||||
]
|
||||
);
|
||||
|
||||
if (!empty($options['action'])) {
|
||||
$builder->setAction($options['action']);
|
||||
}
|
||||
}
|
||||
|
||||
public function getBlockPrefix(): string
|
||||
{
|
||||
return 'fullcontact_lookup';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\Helper;
|
||||
|
||||
use Mautic\CoreBundle\Helper\EncryptionHelper;
|
||||
use Mautic\CoreBundle\Helper\UserHelper;
|
||||
use Mautic\LeadBundle\Entity\Company;
|
||||
use Mautic\LeadBundle\Entity\Lead;
|
||||
use Mautic\LeadBundle\Model\CompanyModel;
|
||||
use Mautic\LeadBundle\Model\LeadModel;
|
||||
use Mautic\PluginBundle\Helper\IntegrationHelper;
|
||||
use MauticPlugin\MauticFullContactBundle\Integration\FullContactIntegration;
|
||||
use MauticPlugin\MauticFullContactBundle\Services\FullContact_Company;
|
||||
use MauticPlugin\MauticFullContactBundle\Services\FullContact_Person;
|
||||
use Monolog\Logger;
|
||||
use Symfony\Bundle\FrameworkBundle\Routing\Router;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
|
||||
class LookupHelper
|
||||
{
|
||||
/**
|
||||
* @var bool|FullContactIntegration
|
||||
*/
|
||||
protected $integration;
|
||||
|
||||
public function __construct(
|
||||
IntegrationHelper $integrationHelper,
|
||||
protected UserHelper $userHelper,
|
||||
protected Logger $logger,
|
||||
protected Router $router,
|
||||
protected LeadModel $leadModel,
|
||||
protected CompanyModel $companyModel,
|
||||
) {
|
||||
$this->integration = $integrationHelper->getIntegrationObject('FullContact');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $notify
|
||||
* @param bool $checkAuto
|
||||
*/
|
||||
public function lookupContact(Lead $lead, $notify = false, $checkAuto = false): void
|
||||
{
|
||||
if (!$lead->getEmail()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var FullContact_Person $fullcontact */
|
||||
if ($fullcontact = $this->getFullContact()) {
|
||||
if (!$checkAuto || ($checkAuto && $this->integration->shouldAutoUpdate())) {
|
||||
try {
|
||||
[$cacheId, $webhookId, $cache] = $this->getCache($lead, $notify);
|
||||
|
||||
if (!array_key_exists($cacheId, $cache['fullcontact'])) {
|
||||
$fullcontact->setWebhookUrl(
|
||||
$this->router->generate(
|
||||
'mautic_plugin_fullcontact_index',
|
||||
[],
|
||||
UrlGeneratorInterface::ABSOLUTE_URL
|
||||
),
|
||||
$webhookId
|
||||
);
|
||||
$res = $fullcontact->lookupByEmail($lead->getEmail());
|
||||
// Prevent from filling up the cache
|
||||
$cache['fullcontact'] = [
|
||||
$cacheId => serialize($res),
|
||||
'nonce' => $cache['fullcontact']['nonce'],
|
||||
];
|
||||
$lead->setSocialCache($cache);
|
||||
|
||||
if ($checkAuto) {
|
||||
$this->leadModel->getRepository()->saveEntity($lead);
|
||||
} else {
|
||||
$this->leadModel->saveEntity($lead);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $ex) {
|
||||
$this->logger->log('error', 'Error while using FullContact to lookup '.$lead->getEmail().': '.$ex->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $notify
|
||||
* @param bool $checkAuto
|
||||
*/
|
||||
public function lookupCompany(Company $company, $notify = false, $checkAuto = false): void
|
||||
{
|
||||
if (!$website = $company->getFieldValue('companywebsite')) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var FullContact_Company $fullcontact */
|
||||
if ($fullcontact = $this->getFullContact(false)) {
|
||||
if (!$checkAuto || ($checkAuto && $this->integration->shouldAutoUpdate())) {
|
||||
try {
|
||||
$parse = parse_url($website);
|
||||
[$cacheId, $webhookId, $cache] = $this->getCache($company, $notify);
|
||||
|
||||
if (isset($parse['host']) && !array_key_exists($cacheId, $cache['fullcontact'])) {
|
||||
$fullcontact->setWebhookUrl(
|
||||
$this->router->generate(
|
||||
'mautic_plugin_fullcontact_index',
|
||||
[],
|
||||
UrlGeneratorInterface::ABSOLUTE_URL
|
||||
),
|
||||
$webhookId
|
||||
);
|
||||
$res = $fullcontact->lookupByDomain($parse['host']);
|
||||
// Prevent from filling up the cache
|
||||
$cache['fullcontact'] = [
|
||||
$cacheId => serialize($res),
|
||||
'nonce' => $cache['fullcontact']['nonce'],
|
||||
];
|
||||
$company->setSocialCache($cache);
|
||||
if ($checkAuto) {
|
||||
$this->companyModel->getRepository()->saveEntity($company);
|
||||
} else {
|
||||
$this->companyModel->saveEntity($company);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $ex) {
|
||||
$this->logger->log('error', 'Error while using FullContact to lookup '.$parse['host'].': '.$ex->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function validateRequest($oid)
|
||||
{
|
||||
// prefix#entityId#hour#userId#nonce
|
||||
[$w, $id, $hour, $uid, $nonce] = explode('#', $oid, 5);
|
||||
$notify = (str_contains($w, '_notify') && $uid) ? $uid : false;
|
||||
$type = (str_starts_with($w, 'fullcontactcomp')) ? 'company' : 'person';
|
||||
|
||||
switch ($type) {
|
||||
case 'person':
|
||||
$entity = $this->leadModel->getEntity($id);
|
||||
break;
|
||||
case 'company':
|
||||
$entity = $this->companyModel->getEntity($id);
|
||||
break;
|
||||
}
|
||||
|
||||
if ($entity) {
|
||||
$socialCache = $entity->getSocialCache();
|
||||
$cacheId = $w.'#'.$id.'#'.$hour;
|
||||
|
||||
if (isset($socialCache['fullcontact'][$cacheId]) && !empty($socialCache['fullcontact']['nonce']) && !empty($nonce)
|
||||
&& $socialCache['fullcontact']['nonce'] === $nonce
|
||||
) {
|
||||
return [
|
||||
'notify' => $notify,
|
||||
'entity' => $entity,
|
||||
'type' => $type,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $person
|
||||
*
|
||||
* @return bool|FullContact_Company|FullContact_Person
|
||||
*/
|
||||
protected function getFullContact($person = true)
|
||||
{
|
||||
if (!$this->integration || !$this->integration->getIntegrationSettings()->getIsPublished()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// get api_key from plugin settings
|
||||
$keys = $this->integration->getDecryptedApiKeys();
|
||||
|
||||
return ($person) ? new FullContact_Person($keys['apikey']) : new FullContact_Company($keys['apikey']);
|
||||
}
|
||||
|
||||
protected function getCache($entity, $notify): array
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $this->userHelper->getUser();
|
||||
$nonce = substr(EncryptionHelper::generateKey(), 0, 16);
|
||||
$cacheId = sprintf('fullcontact%s%s#', $entity instanceof Company ? 'comp' : '', $notify ? '_notify' : '').$entity->getId().'#'.gmdate('YmdH');
|
||||
$webhookId = $cacheId.'#'.$user->getId().'#'.$nonce;
|
||||
|
||||
$cache = $entity->getSocialCache();
|
||||
if (!isset($cache['fullcontact'])) {
|
||||
$cache['fullcontact'] = [];
|
||||
}
|
||||
|
||||
$cache['fullcontact']['nonce'] = $nonce;
|
||||
|
||||
return [$cacheId, $webhookId, $cache];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\Integration;
|
||||
|
||||
use Mautic\CoreBundle\Form\Type\YesNoButtonGroupType;
|
||||
use Mautic\PluginBundle\Integration\AbstractIntegration;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ButtonType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||
use Symfony\Component\Form\Form;
|
||||
use Symfony\Component\Form\FormBuilder;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
|
||||
class FullContactIntegration extends AbstractIntegration
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return 'FullContact';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return's authentication method such as oauth2, oauth1a, key, etc.
|
||||
*/
|
||||
public function getAuthenticationType(): string
|
||||
{
|
||||
return 'none';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array of key => label elements that will be converted to inputs to
|
||||
* obtain from the user.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function getRequiredKeyFields(): array
|
||||
{
|
||||
// Do not rename field. fullcontact.js depends on it
|
||||
return [
|
||||
'apikey' => 'mautic.integration.fullcontact.apikey',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FormBuilder|Form $builder
|
||||
* @param array $data
|
||||
* @param string $formArea
|
||||
*/
|
||||
public function appendToForm(&$builder, $data, $formArea): void
|
||||
{
|
||||
if ('keys' === $formArea) {
|
||||
$builder->add(
|
||||
'test_api',
|
||||
ButtonType::class,
|
||||
[
|
||||
'label' => 'mautic.plugin.fullcontact.test_api',
|
||||
'attr' => [
|
||||
'class' => 'btn btn-primary',
|
||||
'style' => 'margin-bottom: 10px',
|
||||
'onclick' => 'Mautic.testFullContactApi(this)',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$builder->add(
|
||||
'stats',
|
||||
TextareaType::class,
|
||||
[
|
||||
'label_attr' => ['class' => 'control-label'],
|
||||
'label' => 'mautic.plugin.fullcontact.stats',
|
||||
'required' => false,
|
||||
'attr' => [
|
||||
'class' => 'form-control',
|
||||
'rows' => '6',
|
||||
'readonly' => 'readonly',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$builder->add(
|
||||
'auto_update',
|
||||
YesNoButtonGroupType::class,
|
||||
[
|
||||
'label' => 'mautic.plugin.fullcontact.auto_update',
|
||||
'data' => isset($data['auto_update']) && (bool) $data['auto_update'],
|
||||
'attr' => [
|
||||
'tooltip' => 'mautic.plugin.fullcontact.auto_update.tooltip',
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function shouldAutoUpdate(): bool
|
||||
{
|
||||
$featureSettings = $this->getKeys();
|
||||
|
||||
return isset($featureSettings['auto_update']) && (bool) $featureSettings['auto_update'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|array
|
||||
*/
|
||||
public function getFormNotes($section)
|
||||
{
|
||||
if ('custom' === $section) {
|
||||
return [
|
||||
'template' => '@MauticFullContact/Integration/form.html.twig',
|
||||
'parameters' => [
|
||||
'mauticUrl' => $this->router->generate('mautic_plugin_fullcontact_index', [], UrlGeneratorInterface::ABSOLUTE_URL),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
return parent::getFormNotes($section);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle;
|
||||
|
||||
use Mautic\PluginBundle\Bundle\PluginBundleBase;
|
||||
|
||||
class MauticFullContactBundle extends PluginBundleBase
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# Mautic bundle for Fullcontact plugin
|
||||
|
||||
## This plugin is managed centrally in https://github.com/mautic/mautic/blob/head/plugins/MauticFullContactBundle and this is a read-only mirror repository.
|
||||
|
||||
**📣 Please make PRs and issues against Mautic Core, not here!**
|
||||
@@ -0,0 +1,23 @@
|
||||
{#
|
||||
Variables
|
||||
- form
|
||||
- lookupItems
|
||||
#}
|
||||
<div class="alert alert-info">{{ 'mautic.plugin.fullcontact.submit_items'|trans }}</div>
|
||||
<div style="margin-top: 10px">
|
||||
<ul class="list-group" style="max-height: 400px;overflow-y: auto">
|
||||
{% for item in lookupItems %}
|
||||
<li class="list-group-item">{{ item }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var ids = Mautic.getCheckedListIds(false, true);
|
||||
if (mQuery('#fullcontact_batch_lookup_ids').length) {
|
||||
mQuery('#fullcontact_batch_lookup_ids').val(ids);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
{{ form(form) }}
|
||||
@@ -0,0 +1,12 @@
|
||||
{#
|
||||
Variables
|
||||
- form
|
||||
- lookupItem
|
||||
#}
|
||||
<div class="alert alert-info">{{ 'mautic.plugin.fullcontact.submit'|trans }}</div>
|
||||
<div style="margin-top: 10px">
|
||||
<ul class="list-group" style="max-height: 400px;overflow-y: auto">
|
||||
<li class="list-group-item">{{ lookupItem }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
{{ form(form) }}
|
||||
@@ -0,0 +1,8 @@
|
||||
{{ includeScript('plugins/MauticFullContactBundle/Assets/js/fullcontact.js') }}
|
||||
<div class="well well-sm" style="margin-bottom:0 !important;">
|
||||
<p>{{ 'mautic.plugin.fullcontact.webhook'|trans }}</p>
|
||||
<div class="alert alert-warning">
|
||||
{{ 'mautic.plugin.fullcontact.public_info'|trans|purify }}
|
||||
</div>
|
||||
<input type="text" readonly="readonly" value="{{ mauticUrl }}" class="form-control" title="url"/>
|
||||
</div>
|
||||
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\Services;
|
||||
|
||||
use MauticPlugin\MauticFullContactBundle\Exception\NoCreditException;
|
||||
use MauticPlugin\MauticFullContactBundle\Exception\NotImplementedException;
|
||||
|
||||
/**
|
||||
* This class handles the actually HTTP request to the FullContact endpoint.
|
||||
*
|
||||
* @author Keith Casey <contrib@caseysoftware.com>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||
*/
|
||||
class FullContact_Base
|
||||
{
|
||||
public const REQUEST_LATENCY = 0.2;
|
||||
|
||||
public const USER_AGENT = 'caseysoftware/fullcontact-php-0.9.0';
|
||||
|
||||
private \DateTime $_next_req_time;
|
||||
|
||||
// protected $_baseUri = 'https://requestbin.fullcontact.com/1ailj6d1?';
|
||||
protected $_baseUri = 'https://api.fullcontact.com/';
|
||||
|
||||
protected $_version = 'v2';
|
||||
|
||||
protected $_resourceUri = '';
|
||||
|
||||
protected $_webhookUrl;
|
||||
|
||||
protected $_webhookId;
|
||||
|
||||
protected $_webhookJson = false;
|
||||
|
||||
protected $_supportedMethods = [];
|
||||
|
||||
public $response_obj;
|
||||
|
||||
public $response_code;
|
||||
|
||||
public $response_json;
|
||||
|
||||
/**
|
||||
* Slow down calls to the FullContact API if needed.
|
||||
*/
|
||||
private function _wait_for_rate_limit(): void
|
||||
{
|
||||
$now = new \DateTime();
|
||||
if ($this->_next_req_time->getTimestamp() > $now->getTimestamp()) {
|
||||
$t = $this->_next_req_time->getTimestamp() - $now->getTimestamp();
|
||||
sleep($t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $hdr
|
||||
*/
|
||||
private function _update_rate_limit($hdr): void
|
||||
{
|
||||
$remaining = (float) $hdr['X-Rate-Limit-Remaining'];
|
||||
$reset = (float) $hdr['X-Rate-Limit-Reset'];
|
||||
$spacing = $reset / (1.0 + $remaining);
|
||||
$delay = $spacing - self::REQUEST_LATENCY;
|
||||
$this->_next_req_time = new \DateTime('now + '.$delay.' seconds');
|
||||
}
|
||||
|
||||
/**
|
||||
* The base constructor Sets the API key available from here:
|
||||
* http://fullcontact.com/getkey.
|
||||
*
|
||||
* @param string $_apiKey
|
||||
*/
|
||||
public function __construct(
|
||||
protected $_apiKey,
|
||||
) {
|
||||
$this->_next_req_time = new \DateTime('@0');
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets the webhook url for all requests made for this service
|
||||
* instance. To unset, just use setWebhookUrl(null).
|
||||
*
|
||||
* @author David Boskovic <me@david.gs> @dboskovic
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $id
|
||||
* @param bool $json
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function setWebhookUrl($url, $id = null, $json = false)
|
||||
{
|
||||
$this->_webhookUrl = $url;
|
||||
$this->_webhookId = $id;
|
||||
$this->_webhookJson = $json;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a pretty close copy of my work on the Contactually PHP library
|
||||
* available here: http://github.com/caseysoftware/contactually-php.
|
||||
*
|
||||
* @author Keith Casey <contrib@caseysoftware.com>
|
||||
* @author David Boskovic <me@david.gs> @dboskovic
|
||||
*
|
||||
* @param array $params
|
||||
* @param array $postData
|
||||
*
|
||||
* @return object
|
||||
*
|
||||
* @throws NoCreditException
|
||||
* @throws NotImplementedException
|
||||
*/
|
||||
protected function _execute($params = [], $postData = null)
|
||||
{
|
||||
if (null === $postData && !in_array($params['method'], $this->_supportedMethods, true)) {
|
||||
throw new NotImplementedException(self::class.' does not support the ['.$params['method'].'] method');
|
||||
}
|
||||
|
||||
if (array_key_exists('method', $params)) {
|
||||
unset($params['method']);
|
||||
}
|
||||
|
||||
$this->_wait_for_rate_limit();
|
||||
|
||||
$params['apiKey'] = $this->_apiKey;
|
||||
|
||||
if ($this->_webhookUrl) {
|
||||
$params['webhookUrl'] = $this->_webhookUrl;
|
||||
}
|
||||
|
||||
if ($this->_webhookId) {
|
||||
$params['webhookId'] = $this->_webhookId;
|
||||
}
|
||||
|
||||
if ($this->_webhookJson) {
|
||||
$params['webhookBody'] = 'json';
|
||||
}
|
||||
|
||||
$fullUrl = $this->_baseUri.$this->_version.$this->_resourceUri.
|
||||
'?'.http_build_query($params);
|
||||
|
||||
// open connection
|
||||
$connection = curl_init($fullUrl);
|
||||
curl_setopt($connection, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($connection, CURLOPT_USERAGENT, self::USER_AGENT);
|
||||
curl_setopt($connection, CURLOPT_HEADER, true); // return HTTP headers with response
|
||||
|
||||
if (null !== $postData) {
|
||||
curl_setopt($connection, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
|
||||
curl_setopt($connection, CURLOPT_POSTFIELDS, json_encode($postData, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||
curl_setopt($connection, CURLOPT_POST, true);
|
||||
}
|
||||
|
||||
// execute request
|
||||
$resp = curl_exec($connection);
|
||||
|
||||
[$response_headers, $this->response_json] = explode("\r\n\r\n", $resp, 2);
|
||||
// $response_headers now has a string of the HTTP headers
|
||||
// $response_json is the body of the HTTP response
|
||||
|
||||
$headers = [];
|
||||
|
||||
foreach (explode("\r\n", $response_headers) as $i => $line) {
|
||||
if (0 === $i) {
|
||||
$headers['http_code'] = $line;
|
||||
} else {
|
||||
[$key, $value] = explode(': ', $line);
|
||||
$headers[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$this->response_code = curl_getinfo($connection, CURLINFO_HTTP_CODE);
|
||||
$this->response_obj = json_decode($this->response_json);
|
||||
|
||||
if ('403' === $this->response_code) {
|
||||
throw new NoCreditException($this->response_obj->message);
|
||||
} else {
|
||||
if ('200' === $this->response_code) {
|
||||
$this->_update_rate_limit($headers);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->response_obj;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\Services;
|
||||
|
||||
/**
|
||||
* This class handles everything related to the Company lookup API.
|
||||
*
|
||||
* @author Adam Curtis <me@alc.im>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||
*/
|
||||
class FullContact_Batch extends FullContact_Base
|
||||
{
|
||||
protected $_resourceUri = '/batch.json';
|
||||
|
||||
/**
|
||||
* @param array $requests
|
||||
*
|
||||
* @throws \MauticPlugin\MauticFullContactBundle\Exception\FullContact_Exception_NoCredit
|
||||
* @throws \MauticPlugin\MauticFullContactBundle\Exception\FullContact_Exception_NotImplemented
|
||||
*/
|
||||
public function sendRequests($requests)
|
||||
{
|
||||
$this->_execute([], ['requests' => $requests]);
|
||||
|
||||
return $this->response_obj;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\Services;
|
||||
|
||||
/**
|
||||
* This class handles everything related to the Company lookup API.
|
||||
*
|
||||
* @author Adam Curtis <me@alc.im>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||
*/
|
||||
class FullContact_Company extends FullContact_Base
|
||||
{
|
||||
/**
|
||||
* Supported lookup methods.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_supportedMethods = ['domain'];
|
||||
|
||||
protected $_resourceUri = '/company/lookup.json';
|
||||
|
||||
public function lookupByDomain($search)
|
||||
{
|
||||
$this->_execute(['domain' => $search, 'method' => 'domain']);
|
||||
|
||||
return $this->response_obj;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\Services;
|
||||
|
||||
/**
|
||||
* This class just tells us what icons we have available.
|
||||
*
|
||||
* @author Keith Casey <contrib@caseysoftware.com>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||
*/
|
||||
class FullContact_Icon extends FullContact_Base
|
||||
{
|
||||
protected $_supportedMethods = ['available'];
|
||||
|
||||
protected $_resourceUri = '/icon/';
|
||||
|
||||
public function available()
|
||||
{
|
||||
$this->_execute(['method' => 'available']);
|
||||
|
||||
return $this->response_obj;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\Services;
|
||||
|
||||
/**
|
||||
* This class handles all the Location information.
|
||||
*
|
||||
* @author Keith Casey <contrib@caseysoftware.com>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||
*/
|
||||
class FullContact_Location extends FullContact_Base
|
||||
{
|
||||
/**
|
||||
* Supported lookup methods.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_supportedMethods = ['normalizer', 'enrichment'];
|
||||
|
||||
protected $_resourceUri = '';
|
||||
|
||||
/**
|
||||
* This takes a name and breaks it into its individual parts.
|
||||
*
|
||||
* @param type $casing -> valid values are uppercase, lowercase, titlecase
|
||||
*
|
||||
* @return type
|
||||
*/
|
||||
public function normalizer($place, $includeZeroPopulation = false, $casing = 'titlecase')
|
||||
{
|
||||
$includeZeroPopulation = ($includeZeroPopulation) ? 'true' : 'false';
|
||||
|
||||
$this->_resourceUri = '/address/locationNormalizer.json';
|
||||
$this->_execute(['place' => $place, 'includeZeroPopulation' => $includeZeroPopulation,
|
||||
'method' => 'normalizer', 'casing' => $casing, ]);
|
||||
|
||||
return $this->response_obj;
|
||||
}
|
||||
|
||||
public function enrichment($place, $includeZeroPopulation = false, $casing = 'titlecase')
|
||||
{
|
||||
$includeZeroPopulation = ($includeZeroPopulation) ? 'true' : 'false';
|
||||
|
||||
$this->_resourceUri = '/address/locationEnrichment.json';
|
||||
$this->_execute(['place' => $place, 'includeZeroPopulation' => $includeZeroPopulation,
|
||||
'method' => 'enrichment', 'casing' => $casing, ]);
|
||||
|
||||
return $this->response_obj;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\Services;
|
||||
|
||||
/**
|
||||
* This class handles everything related to names that aren't person-based info lookup.
|
||||
*
|
||||
* @author Keith Casey <contrib@caseysoftware.com>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||
*/
|
||||
class FullContact_Name extends FullContact_Base
|
||||
{
|
||||
/**
|
||||
* Supported lookup methods.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_supportedMethods = ['normalizer', 'deducer', 'similarity', 'stats', 'parser'];
|
||||
|
||||
protected $_resourceUri = '';
|
||||
|
||||
/**
|
||||
* This takes a name and breaks it into its individual parts.
|
||||
*
|
||||
* @param type $name
|
||||
* @param type $casing -> valid values are uppercase, lowercase, titlecase
|
||||
*
|
||||
* @return type
|
||||
*/
|
||||
public function normalizer($name, $casing = 'titlecase')
|
||||
{
|
||||
$this->_resourceUri = '/name/normalizer.json';
|
||||
$this->_execute(['q' => $name, 'method' => 'normalizer', 'casing' => $casing]);
|
||||
|
||||
return $this->response_obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* This resolves a person's name from either their email address or a
|
||||
* username. This is basically a wrapper for the Person lookup methods.
|
||||
*
|
||||
* @param type $type -> valid values are email and username
|
||||
* @param type $casing -> valid values are uppercase, lowercase, titlecase
|
||||
*
|
||||
* @return type
|
||||
*/
|
||||
public function deducer($value, $type = 'email', $casing = 'titlecase')
|
||||
{
|
||||
$this->_resourceUri = '/name/deducer.json';
|
||||
$this->_execute([$type => $value, 'method' => 'deducer', 'casing' => $casing]);
|
||||
|
||||
return $this->response_obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* These are two names to compare.
|
||||
*
|
||||
* @param type $name1
|
||||
* @param type $name2
|
||||
* @param type $casing
|
||||
*
|
||||
* @return type
|
||||
*/
|
||||
public function similarity($name1, $name2, $casing = 'titlecase')
|
||||
{
|
||||
$this->_resourceUri = '/name/similarity.json';
|
||||
$this->_execute(['q1' => $name1, 'q2' => $name2, 'method' => 'similarity', 'casing' => $casing]);
|
||||
|
||||
return $this->response_obj;
|
||||
}
|
||||
|
||||
public function stats($value, $type = 'givenName', $casing = 'titlecase')
|
||||
{
|
||||
$this->_resourceUri = '/name/stats.json';
|
||||
$this->_execute([$type => $value, 'method' => 'stats', 'casing' => $casing]);
|
||||
|
||||
return $this->response_obj;
|
||||
}
|
||||
|
||||
public function parser($name, $casing = 'titlecase')
|
||||
{
|
||||
$this->_resourceUri = '/name/parser.json';
|
||||
$this->_execute(['q' => $name, 'method' => 'parser', 'casing' => $casing]);
|
||||
|
||||
return $this->response_obj;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace MauticPlugin\MauticFullContactBundle\Services;
|
||||
|
||||
/**
|
||||
* This class handles everything related to the Person lookup API.
|
||||
*
|
||||
* @author Keith Casey <contrib@caseysoftware.com>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||
*/
|
||||
class FullContact_Person extends FullContact_Base
|
||||
{
|
||||
/**
|
||||
* Supported lookup methods.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_supportedMethods = ['email', 'phone', 'twitter'];
|
||||
|
||||
protected $_resourceUri = '/person.json';
|
||||
|
||||
public function lookupByEmail($search)
|
||||
{
|
||||
$this->_execute(['email' => $search, 'method' => 'email']);
|
||||
|
||||
return $this->response_obj;
|
||||
}
|
||||
|
||||
public function lookupByEmailMD5($search)
|
||||
{
|
||||
$this->_execute(['emailMD5' => $search, 'method' => 'email']);
|
||||
|
||||
return $this->response_obj;
|
||||
}
|
||||
|
||||
public function lookupByPhone($search)
|
||||
{
|
||||
$this->_execute(['phone' => $search, 'method' => 'phone']);
|
||||
|
||||
return $this->response_obj;
|
||||
}
|
||||
|
||||
public function lookupByTwitter($search)
|
||||
{
|
||||
$this->_execute(['twitter' => $search, 'method' => 'twitter']);
|
||||
|
||||
return $this->response_obj;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
mautic.company.batch_companies_affected="{0} 0 companies affected|{1} 1 company affected|]1,Inf[ %count% companies affected"
|
||||
@@ -0,0 +1,21 @@
|
||||
mautic.integration.fullcontact.apikey="FullContact API Key"
|
||||
mautic.plugin.fullcontact.button.caption="Lookup using FullContact"
|
||||
mautic.plugin.fullcontact.lookup.header="FullContact - Lookup information for %item%"
|
||||
mautic.plugin.fullcontact.test_api="Test API and get Stats"
|
||||
mautic.plugin.fullcontact.stats="Test Results"
|
||||
mautic.plugin.fullcontact.toomany="You can only lookup 20 contacts at once!"
|
||||
mautic.plugin.fullcontact.comptoomany="You can only lookup 20 companies at once!"
|
||||
mautic.plugin.fullcontact.empty="There are no contacts to lookup!"
|
||||
mautic.plugin.fullcontact.compempty="There are no company domains to lookup!<br/>(Company website is empty?)"
|
||||
mautic.plugin.fullcontact.forbidden="You don't have permissions to update this contact"
|
||||
mautic.plugin.fullcontact.compforbidden="You don't have permissions to update this company"
|
||||
mautic.plugin.fullcontact.auto_update="Automatically update on save?"
|
||||
mautic.plugin.fullcontact.auto_update.tooltip="WARNING: This could easily exhaust your quota of API calls per month."
|
||||
mautic.plugin.fullcontact.notify="Show a notification when the information has been received"
|
||||
mautic.plugin.fullcontact.webhook="The plugin will use the following as the Webhook URL for FullContact:"
|
||||
mautic.plugin.fullcontact.public_info="<strong>Warning!</strong> This must be a public accessible URL for the Webhook to work."
|
||||
mautic.plugin.fullcontact.submit="Click submit to lookup the information for:"
|
||||
mautic.plugin.fullcontact.submit_items="Click submit to lookup the information for the selected item(s)."
|
||||
mautic.plugin.fullcontact.company_retrieved="The company information for %s has been retrieved"
|
||||
mautic.plugin.fullcontact.contact_retrieved="The contact information for %s has been retrieved"
|
||||
mautic.plugin.fullcontact.unable="Unable to save the information for %s: %s"
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "mautic/plugin-fullcontact",
|
||||
"description": "Full Contact Plugin",
|
||||
"type": "mautic-plugin",
|
||||
"keywords": [
|
||||
"mautic",
|
||||
"plugin",
|
||||
"integration"
|
||||
],
|
||||
"extra": {
|
||||
"install-directory-name": "MauticFullContactBundle"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"require": {
|
||||
"mautic/core-lib": "^7.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user