mautic / app /bundles /LeadBundle /Tests /Controller /Api /LeadApiControllerFunctionalTest.php
chrisbryan17's picture
Upload folder using huggingface_hub
d2897cd verified
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Tests\Controller\Api;
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
use Mautic\CoreBundle\Test\Session\FixedMockFileSessionStorage;
use Mautic\LeadBundle\Entity\Company;
use Mautic\LeadBundle\Entity\DoNotContact;
use Mautic\LeadBundle\Entity\Lead;
use PHPUnit\Framework\Assert;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
class LeadApiControllerFunctionalTest extends MauticMysqlTestCase
{
protected function setUp(): void
{
// Disable API just for specific test.
$this->configParams['api_enabled'] = 'testDisabledApi' !== $this->getName();
static::getContainer()->set(
'session',
new Session(
new class() extends FixedMockFileSessionStorage {
public function start()
{
Assert::fail('Session cannot be started during API call. It must be stateless.');
}
}
)
);
parent::setUp();
}
public function testDisabledApi(): void
{
$this->client->request('POST', '/api/contacts/new', ['email' => '[email protected]']);
$clientResponse = $this->client->getResponse();
$this->assertEquals(Response::HTTP_FORBIDDEN, $clientResponse->getStatusCode(), $clientResponse->getContent());
$this->assertEquals(
'{"errors":[{"message":"API disabled. You need to enable the API in the API settings of Mautic\u0027s Configuration.","code":403,"type":"api_disabled"}]}',
$clientResponse->getContent()
);
}
public function testActivityApi(): void
{
$this->client->request('GET', '/api/contacts/activity');
Assert::assertTrue($this->client->getResponse()->isOk(), $this->client->getResponse()->getContent());
Assert::assertArrayHasKey('events', json_decode($this->client->getResponse()->getContent(), true));
Assert::assertArrayHasKey('filters', json_decode($this->client->getResponse()->getContent(), true));
Assert::assertArrayHasKey('order', json_decode($this->client->getResponse()->getContent(), true));
Assert::assertArrayHasKey('types', json_decode($this->client->getResponse()->getContent(), true));
Assert::assertArrayHasKey('total', json_decode($this->client->getResponse()->getContent(), true));
Assert::assertArrayHasKey('page', json_decode($this->client->getResponse()->getContent(), true));
Assert::assertArrayHasKey('limit', json_decode($this->client->getResponse()->getContent(), true));
Assert::assertArrayHasKey('maxPages', json_decode($this->client->getResponse()->getContent(), true));
}
public function testBatchNewEndpointDoesNotCreateDuplicates(): void
{
$companyA = $this->createCompany('CompanyA corp');
$companyB = $this->createCompany('CompanyB corp');
$payload = [
[
'email' => '[email protected]',
'firstname' => 'BatchUpdate',
'points' => 4,
'tags' => ['batchtest', 'testbatch'],
'city' => 'Houston',
'state' => 'Texas',
'country' => 'United States',
'preferred_locale' => 'es_SV',
'timezone' => 'America/Chicago',
'owner' => 1,
'company' => $companyA->getId(),
],
[
'email' => '[email protected]',
'firstname' => 'BatchUpdate2',
'tags' => ['batchtest', 'testbatch', 'batchremovetest'],
'city' => 'Boston',
'state' => 'Massachusetts',
'country' => 'United States',
'preferred_locale' => 'en_GB',
'timezone' => 'America/New_York',
],
[
'email' => '[email protected]',
'firstname' => 'BatchUpdate3',
],
];
$this->client->request(Request::METHOD_POST, '/api/contacts/batch/new', $payload);
$clientResponse = $this->client->getResponse();
Assert::assertSame(Response::HTTP_CREATED, $clientResponse->getStatusCode(), $clientResponse->getContent());
$response = json_decode($clientResponse->getContent(), true);
// Assert status codes
$this->assertEquals(Response::HTTP_CREATED, $response['statusCodes'][0]);
$contactId1 = $response['contacts'][0]['id'];
$this->assertEquals(Response::HTTP_CREATED, $response['statusCodes'][1]);
$contactId2 = $response['contacts'][1]['id'];
$this->assertEquals(Response::HTTP_CREATED, $response['statusCodes'][2]);
$contactId3 = $response['contacts'][2]['id'];
// Assert email
$this->assertEquals($payload[0]['email'], $response['contacts'][0]['fields']['all']['email']);
$this->assertEquals($payload[1]['email'], $response['contacts'][1]['fields']['all']['email']);
$this->assertEquals($payload[2]['email'], $response['contacts'][2]['fields']['all']['email']);
// Assert firstname
$this->assertEquals($payload[0]['firstname'], $response['contacts'][0]['fields']['all']['firstname']);
$this->assertEquals($payload[1]['firstname'], $response['contacts'][1]['fields']['all']['firstname']);
$this->assertEquals($payload[2]['firstname'], $response['contacts'][2]['fields']['all']['firstname']);
// Assert points while also testing empty precision as points is treated as a custom field
$this->assertSame(4, $response['contacts'][0]['points']);
$this->assertSame(4, $response['contacts'][0]['fields']['all']['points']);
$this->assertSame(0, $response['contacts'][1]['points']);
$this->assertSame(0, $response['contacts'][2]['points']);
$this->assertSame(0, $response['contacts'][2]['fields']['all']['points']);
// Assert tags
$this->assertEquals(2, count($response['contacts'][0]['tags']));
$this->assertEquals(3, count($response['contacts'][1]['tags']));
$this->assertEquals(0, count($response['contacts'][2]['tags']));
// Assert city
$this->assertEquals($payload[0]['city'], $response['contacts'][0]['fields']['all']['city']);
$this->assertEquals($payload[1]['city'], $response['contacts'][1]['fields']['all']['city']);
$this->assertEquals('', $response['contacts'][2]['fields']['all']['city']);
// Assert state
$this->assertEquals($payload[0]['state'], $response['contacts'][0]['fields']['all']['state']);
$this->assertEquals($payload[1]['state'], $response['contacts'][1]['fields']['all']['state']);
$this->assertEquals('', $response['contacts'][2]['fields']['all']['state']);
// Assert country
$this->assertEquals($payload[0]['country'], $response['contacts'][0]['fields']['all']['country']);
$this->assertEquals($payload[1]['country'], $response['contacts'][1]['fields']['all']['country']);
$this->assertEquals('', $response['contacts'][2]['fields']['all']['country']);
// Assert preferred_locale
$this->assertEquals($payload[0]['preferred_locale'], $response['contacts'][0]['fields']['all']['preferred_locale']);
$this->assertEquals($payload[1]['preferred_locale'], $response['contacts'][1]['fields']['all']['preferred_locale']);
$this->assertEquals('', $response['contacts'][2]['fields']['all']['preferred_locale']);
// Assert timezone
$this->assertEquals($payload[0]['timezone'], $response['contacts'][0]['fields']['all']['timezone']);
$this->assertEquals($payload[1]['timezone'], $response['contacts'][1]['fields']['all']['timezone']);
$this->assertEquals('', $response['contacts'][2]['fields']['all']['timezone']);
// Assert owner
$this->assertEquals($payload[0]['owner'], $response['contacts'][0]['owner']['id']);
$this->assertEquals(null, $response['contacts'][1]['owner']);
$this->assertEquals(null, $response['contacts'][2]['owner']);
// Assert company
$this->assertEquals($companyA->getId(), (int) $response['contacts'][0]['fields']['all']['company']);
$this->assertEquals(null, $response['contacts'][1]['fields']['all']['company']);
$this->assertEquals(null, $response['contacts'][2]['fields']['all']['company']);
// Emulate an unsanitized email to ensure that doesn't cause duplicates
$payload[0]['email'] = '[email protected],';
// Set first name as null - Mautic should keep the value
$payload[0]['firstname'] = null;
// Remove tags from contact 1 to see if they will stick in the database
unset($payload[0]['tags']);
// Update others
$payload[0]['city'] = 'Sunnyvale';
$payload[0]['state'] = 'California';
$payload[0]['timezone'] = 'America/Los_Angeles';
$payload[0]['preferred_locale'] = 'en_US';
$payload[0]['company'] = $companyB->getId();
// Update owner
$payload[0]['owner'] = null;
$payload[1]['owner'] = 1;
// Set some tags to contact 2 to see if tags update
$payload[1]['tags'] = ['testbatch1', 'testbatch2', '-batchremovetest'];
// Set some points to contact 2 to see if they update
$payload[1]['points'] = 3;
// Update the 3 contacts
$this->client->request(Request::METHOD_POST, '/api/contacts/batch/new', $payload);
$clientResponse = $this->client->getResponse();
Assert::assertSame(Response::HTTP_CREATED, $clientResponse->getStatusCode(), $clientResponse->getContent());
$response = json_decode($clientResponse->getContent(), true);
$this->assertEquals(Response::HTTP_OK, $response['statusCodes'][0]);
$this->assertEquals($contactId1, $response['contacts'][0]['id']);
$this->assertEquals(Response::HTTP_OK, $response['statusCodes'][1]);
$this->assertEquals($contactId2, $response['contacts'][1]['id']);
$this->assertEquals(Response::HTTP_OK, $response['statusCodes'][2]);
$this->assertEquals($contactId3, $response['contacts'][2]['id']);
// Assert email
$this->assertEquals('[email protected]', $response['contacts'][0]['fields']['all']['email']);
$this->assertEquals($payload[1]['email'], $response['contacts'][1]['fields']['all']['email']);
$this->assertEquals($payload[2]['email'], $response['contacts'][2]['fields']['all']['email']);
// Assert firstname
$this->assertEquals('BatchUpdate', $response['contacts'][0]['fields']['all']['firstname']);
$this->assertEquals($payload[1]['firstname'], $response['contacts'][1]['fields']['all']['firstname']);
$this->assertEquals($payload[2]['firstname'], $response['contacts'][2]['fields']['all']['firstname']);
// Assert points
$this->assertSame(4, $response['contacts'][0]['points']);
$this->assertSame(4, $response['contacts'][0]['fields']['all']['points']);
$this->assertSame(3, $response['contacts'][1]['points']);
$this->assertSame(3, $response['contacts'][1]['fields']['all']['points']);
$this->assertSame(0, $response['contacts'][2]['points']);
$this->assertSame(0, $response['contacts'][2]['fields']['all']['points']);
// Assert tags
$this->assertEquals(2, count($response['contacts'][0]['tags']));
$this->assertEquals(4, count($response['contacts'][1]['tags']));
$this->assertEquals(0, count($response['contacts'][2]['tags']));
// Assert city
$this->assertEquals($payload[0]['city'], $response['contacts'][0]['fields']['all']['city']);
$this->assertEquals($payload[1]['city'], $response['contacts'][1]['fields']['all']['city']);
$this->assertEquals('', $response['contacts'][2]['fields']['all']['city']);
// Assert state
$this->assertEquals($payload[0]['state'], $response['contacts'][0]['fields']['all']['state']);
$this->assertEquals($payload[1]['state'], $response['contacts'][1]['fields']['all']['state']);
$this->assertEquals('', $response['contacts'][2]['fields']['all']['state']);
// Assert country
$this->assertEquals($payload[0]['country'], $response['contacts'][0]['fields']['all']['country']);
$this->assertEquals($payload[1]['country'], $response['contacts'][1]['fields']['all']['country']);
$this->assertEquals('', $response['contacts'][2]['fields']['all']['country']);
// Assert preferred_locale
$this->assertEquals($payload[0]['preferred_locale'], $response['contacts'][0]['fields']['all']['preferred_locale']);
$this->assertEquals($payload[1]['preferred_locale'], $response['contacts'][1]['fields']['all']['preferred_locale']);
$this->assertEquals('', $response['contacts'][2]['fields']['all']['preferred_locale']);
// Assert timezone
$this->assertEquals($payload[0]['timezone'], $response['contacts'][0]['fields']['all']['timezone']);
$this->assertEquals($payload[1]['timezone'], $response['contacts'][1]['fields']['all']['timezone']);
$this->assertEquals('', $response['contacts'][2]['fields']['all']['timezone']);
// Assert owner
$this->assertEquals(null, $response['contacts'][0]['owner']);
$this->assertEquals($payload[1]['owner'], $response['contacts'][1]['owner']['id']);
$this->assertEquals(null, $response['contacts'][2]['owner']);
// Assert company
$this->assertEquals($companyB->getId(), (int) $response['contacts'][0]['fields']['all']['company']);
$this->assertEquals(null, $response['contacts'][1]['fields']['all']['company']);
$this->assertEquals(null, $response['contacts'][2]['fields']['all']['company']);
}
/**
* If there are some entities to return then the response returns a hash table (JSON object),
* So for response with no entities we must also return a JSON object because some languages
* decode it differently then emtpty array.
*/
public function testEmptyResponseReturnsJsonObject(): void
{
$this->client->request('GET', '/api/contacts?where[0][val]=unicorn&where[0][col]=email&where[0][expr]=eq');
$clientResponse = $this->client->getResponse();
$this->assertTrue($this->client->getResponse()->isOk());
$this->assertEquals('{"total":"0","contacts":{}}', $clientResponse->getContent());
}
public function testBatchEditEndpoint(): void
{
$contact = new Lead();
$contact->setEmail('[email protected]');
$this->em->persist($contact);
$this->em->flush();
$this->em->clear();
$payload = [
['email' => '[email protected]', 'id' => $contact->getId()],
];
$this->client->request('PUT', '/api/contacts/batch/edit', $payload);
$clientResponse = $this->client->getResponse();
Assert::assertSame(Response::HTTP_OK, $clientResponse->getStatusCode(), $clientResponse->getContent());
$response= json_decode($clientResponse->getContent(), true);
$this->assertEquals(Response::HTTP_OK, $response['statusCodes'][0]);
$this->assertEquals($contact->getId(), $response['contacts'][0]['id']);
$this->assertEquals('[email protected]', $response['contacts'][0]['fields']['all']['email']);
}
public function testBatchEditEndpointWithRubbishId(): void
{
$payload = [
['email' => '[email protected]', 'id' => 'rubbish'],
];
$this->client->request('PUT', '/api/contacts/batch/edit', $payload);
$clientResponse = $this->client->getResponse();
Assert::assertSame(Response::HTTP_OK, $clientResponse->getStatusCode(), $clientResponse->getContent());
$response = json_decode($clientResponse->getContent(), true);
$this->assertEquals(Response::HTTP_CREATED, $response['statusCodes'][0]);
$this->assertGreaterThanOrEqual(1, $response['contacts'][0]['id']);
$this->assertEquals('[email protected]', $response['contacts'][0]['fields']['all']['email']);
}
public function testSingleNewEndpointCreateAndUpdate(): void
{
$payload = [
'email' => '[email protected]',
'firstname' => 'API',
'lastname' => 'Update',
'points' => 4,
'tags' => ['apitest', 'testapi'],
'city' => 'Houston',
'state' => 'Texas',
'country' => 'United States',
'preferred_locale' => 'es_SV',
'timezone' => 'America/Chicago',
'owner' => 1,
];
$this->client->request(Request::METHOD_POST, '/api/contacts/new', $payload);
$clientResponse = $this->client->getResponse();
$this->assertSame(Response::HTTP_CREATED, $clientResponse->getStatusCode(), $clientResponse->getContent());
$response = json_decode($clientResponse->getContent(), true);
$contactId = $response['contact']['id'];
$this->assertEquals($payload['email'], $response['contact']['fields']['all']['email']);
$this->assertEquals($payload['firstname'], $response['contact']['fields']['all']['firstname']);
$this->assertEquals($payload['lastname'], $response['contact']['fields']['all']['lastname']);
$this->assertEquals(4, $response['contact']['points']);
$this->assertEquals(2, count($response['contact']['tags']));
$this->assertEquals($payload['city'], $response['contact']['fields']['all']['city']);
$this->assertEquals($payload['state'], $response['contact']['fields']['all']['state']);
$this->assertEquals($payload['country'], $response['contact']['fields']['all']['country']);
$this->assertEquals($payload['preferred_locale'], $response['contact']['fields']['all']['preferred_locale']);
$this->assertEquals($payload['timezone'], $response['contact']['fields']['all']['timezone']);
$this->assertEquals($payload['owner'], $response['contact']['owner']['id']);
// without overwriteWithBlank lastname is not set empty
$payload['lastname'] = '';
// Lets try to create the same contact to see that the values are not re-setted
$this->client->request(Request::METHOD_POST, '/api/contacts/new', $payload);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$this->assertEquals($contactId, $response['contact']['id']);
$this->assertEquals($payload['email'], $response['contact']['fields']['all']['email']);
$this->assertEquals($payload['firstname'], $response['contact']['fields']['all']['firstname']);
$this->assertNotEmpty($response['contact']['fields']['all']['lastname']);
$this->assertEquals(4, $response['contact']['points']);
$this->assertEquals(2, count($response['contact']['tags']));
// with overwriteWithBlank lastname is empty
$payload['overwriteWithBlank'] = true;
$payload['lastname'] = '';
// Lets try to create the same contact to see that the values are not re-setted
$this->client->request(Request::METHOD_POST, '/api/contacts/new', $payload);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$this->assertEquals($contactId, $response['contact']['id']);
$this->assertEquals($payload['email'], $response['contact']['fields']['all']['email']);
$this->assertEquals($payload['firstname'], $response['contact']['fields']['all']['firstname']);
$this->assertEmpty($response['contact']['fields']['all']['lastname']);
$this->assertSame(4, $response['contact']['points']);
$this->assertSame(4, $response['contact']['fields']['all']['points']);
$this->assertEquals(2, count($response['contact']['tags']));
$this->assertEquals($payload['city'], $response['contact']['fields']['all']['city']);
$this->assertEquals($payload['state'], $response['contact']['fields']['all']['state']);
$this->assertEquals($payload['country'], $response['contact']['fields']['all']['country']);
$this->assertEquals($payload['preferred_locale'], $response['contact']['fields']['all']['preferred_locale']);
$this->assertEquals($payload['timezone'], $response['contact']['fields']['all']['timezone']);
$this->assertEquals($payload['owner'], $response['contact']['owner']['id']);
// Lets try to create the same contact and it should merge based on unique identifier (email)
$updatedValues = [
'email' => '[email protected]',
'lastname' => 'Update',
'city' => 'Boston',
'state' => 'Massachusetts',
'owner' => 2,
];
$this->client->request(Request::METHOD_POST, '/api/contacts/new', $updatedValues);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$this->assertEquals($contactId, $response['contact']['id']);
$this->assertEquals($updatedValues['email'], $response['contact']['fields']['all']['email']);
$this->assertEquals($payload['firstname'], $response['contact']['fields']['all']['firstname']);
$this->assertEquals($updatedValues['lastname'], $response['contact']['fields']['all']['lastname']);
$this->assertSame(4, $response['contact']['points']);
$this->assertSame(4, $response['contact']['fields']['all']['points']);
$this->assertEquals(2, count($response['contact']['tags']));
$this->assertEquals($updatedValues['city'], $response['contact']['fields']['all']['city']);
$this->assertEquals($updatedValues['state'], $response['contact']['fields']['all']['state']);
$this->assertEquals($payload['country'], $response['contact']['fields']['all']['country']);
$this->assertEquals($payload['preferred_locale'], $response['contact']['fields']['all']['preferred_locale']);
$this->assertEquals($payload['timezone'], $response['contact']['fields']['all']['timezone']);
$this->assertEquals($updatedValues['owner'], $response['contact']['owner']['id']);
// test: create the same contact, merge it based on unique identifier (email) - without loosing the owner and stage
unset($updatedValues['owner']);
$this->client->request('POST', '/api/contacts/new', $updatedValues);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$this->assertEquals($contactId, $response['contact']['id']);
$this->assertEquals($updatedValues['email'], $response['contact']['fields']['all']['email']);
$this->assertEquals($payload['firstname'], $response['contact']['fields']['all']['firstname']);
$this->assertEquals($updatedValues['lastname'], $response['contact']['fields']['all']['lastname']);
$this->assertSame(4, $response['contact']['points']);
$this->assertNull($response['contact']['stage']); // stage was not set on the contact
$this->assertSame(2, $response['contact']['owner']['id']);
// set the owner again for the other tests to work
$updatedValues['owner'] = 2;
// Test getting a contact
$this->client->request(Request::METHOD_GET, '/api/contacts/'.$contactId);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$this->assertEquals($contactId, $response['contact']['id']);
$this->assertEquals($payload['email'], $response['contact']['fields']['all']['email']);
$this->assertEquals($payload['firstname'], $response['contact']['fields']['all']['firstname']);
$this->assertSame(4, $response['contact']['points']);
$this->assertSame(4, $response['contact']['fields']['all']['points']);
$this->assertEquals(2, count($response['contact']['tags']));
$this->assertEquals($updatedValues['city'], $response['contact']['fields']['all']['city']);
$this->assertEquals($updatedValues['state'], $response['contact']['fields']['all']['state']);
$this->assertEquals($payload['country'], $response['contact']['fields']['all']['country']);
$this->assertEquals($payload['preferred_locale'], $response['contact']['fields']['all']['preferred_locale']);
$this->assertEquals($payload['timezone'], $response['contact']['fields']['all']['timezone']);
$this->assertEquals($updatedValues['owner'], $response['contact']['owner']['id']);
// Test fetching the batch of contacts
$this->client->request(Request::METHOD_GET, '/api/contacts');
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$this->assertTrue(isset($response['contacts'][$contactId]));
$contact = $response['contacts'][$contactId];
$this->assertEquals($contactId, $contact['id']);
$this->assertEquals($payload['email'], $contact['fields']['all']['email']);
$this->assertEquals($payload['firstname'], $contact['fields']['all']['firstname']);
$this->assertSame(4, $contact['points']);
$this->assertSame(4, $contact['fields']['all']['points']);
$this->assertEquals(2, count($contact['tags']));
$this->assertEquals($updatedValues['city'], $contact['fields']['all']['city']);
$this->assertEquals($updatedValues['state'], $contact['fields']['all']['state']);
$this->assertEquals($payload['country'], $contact['fields']['all']['country']);
$this->assertEquals($payload['preferred_locale'], $contact['fields']['all']['preferred_locale']);
$this->assertEquals($payload['timezone'], $contact['fields']['all']['timezone']);
$this->assertEquals($updatedValues['owner'], $contact['owner']['id']);
// Test patch and values should be updated
$updatedValues = [
'email' => '[email protected]',
'city' => 'Boston',
'state' => 'Massachusetts',
'owner' => 2,
'points' => 1,
];
$this->client->request(
'PATCH',
sprintf('/api/contacts/%d/edit', $contactId),
$updatedValues
);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$this->assertEquals($contactId, $response['contact']['id']);
$this->assertEquals($updatedValues['email'], $response['contact']['fields']['all']['email']);
$this->assertEquals($payload['firstname'], $response['contact']['fields']['all']['firstname']);
$this->assertSame(1, $response['contact']['points']);
$this->assertSame(1, $response['contact']['fields']['all']['points']);
$this->assertEquals(2, count($response['contact']['tags']));
$this->assertEquals($updatedValues['city'], $response['contact']['fields']['all']['city']);
$this->assertEquals($updatedValues['state'], $response['contact']['fields']['all']['state']);
$this->assertEquals($payload['country'], $response['contact']['fields']['all']['country']);
$this->assertEquals($payload['preferred_locale'], $response['contact']['fields']['all']['preferred_locale']);
$this->assertEquals($payload['timezone'], $response['contact']['fields']['all']['timezone']);
$this->assertEquals($updatedValues['owner'], $response['contact']['owner']['id']);
}
/**
* Test creating a new contact with doNotContact information.
* The API response should include DNC information.
*/
public function testSingleNewEndpointCreateAndDeleteWithDnc(): void
{
$payload = [
'email' => '[email protected]',
'firstname' => 'API',
'lastname' => 'DNC test',
'points' => 4,
'tags' => ['apitest', 'testapi'],
'city' => 'Houston',
'state' => 'Texas',
'country' => 'United States',
'preferred_locale' => 'es_SV',
'timezone' => 'America/Chicago',
'owner' => 1,
'doNotContact' => [
[
'channel' => 'email',
'reason' => DoNotContact::BOUNCED,
],
],
];
$this->client->request(Request::METHOD_POST, '/api/contacts/new', $payload);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$contactId = $response['contact']['id'];
$this->assertEquals(1, count($response['contact']['doNotContact']));
$this->assertEquals($payload['doNotContact'][0]['channel'], $response['contact']['doNotContact'][0]['channel']);
$this->assertEquals($payload['doNotContact'][0]['reason'], $response['contact']['doNotContact'][0]['reason']);
// Remove contact
$this->client->request(Request::METHOD_DELETE, "/api/contacts/$contactId/delete");
$clientResponse = $this->client->getResponse();
$this->assertSame(Response::HTTP_OK, $clientResponse->getStatusCode());
}
public function testBatchNewEndpointCreateAndUpdate(): void
{
$payload = [
[
'email' => '[email protected]',
'firstname' => 'API',
'lastname' => 'Update',
'points' => 4,
'tags' => ['apitest', 'testapi'],
'city' => 'Houston',
'state' => 'Texas',
'country' => 'United States',
'preferred_locale' => 'es_SV',
'timezone' => 'America/Chicago',
'owner' => 1,
], [
'email' => '[email protected]',
'firstname' => 'API2',
'lastname' => 'Update2',
'points' => 3,
],
];
$this->client->request('POST', '/api/contacts/batch/new', $payload);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$contactId = $response['contacts'][0]['id'];
$this->assertEquals($payload[0]['email'], $response['contacts'][0]['fields']['all']['email']);
$this->assertEquals($payload[0]['firstname'], $response['contacts'][0]['fields']['all']['firstname']);
$this->assertEquals($payload[0]['lastname'], $response['contacts'][0]['fields']['all']['lastname']);
$this->assertSame(4, $response['contacts'][0]['points']);
$this->assertSame(4, $response['contacts'][0]['fields']['all']['points']);
$this->assertEquals(2, count($response['contacts'][0]['tags']));
$this->assertEquals($payload[0]['city'], $response['contacts'][0]['fields']['all']['city']);
$this->assertEquals($payload[0]['state'], $response['contacts'][0]['fields']['all']['state']);
$this->assertEquals($payload[0]['country'], $response['contacts'][0]['fields']['all']['country']);
$this->assertEquals($payload[0]['preferred_locale'], $response['contacts'][0]['fields']['all']['preferred_locale']);
$this->assertEquals($payload[0]['timezone'], $response['contacts'][0]['fields']['all']['timezone']);
$this->assertEquals($payload[0]['owner'], $response['contacts'][0]['owner']['id']);
// without overwriteWithBlank lastname is not set empty
$payload[0]['lastname'] = '';
// Lets try to create the same contact to see that the values are not re-setted
$this->client->request('POST', '/api/contacts/batch/new', $payload);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$this->assertEquals($contactId, $response['contacts'][0]['id']);
$this->assertEquals($payload[0]['email'], $response['contacts'][0]['fields']['all']['email']);
$this->assertEquals($payload[0]['firstname'], $response['contacts'][0]['fields']['all']['firstname']);
$this->assertNotEmpty($response['contacts'][0]['fields']['all']['lastname']);
$this->assertEquals(4, $response['contacts'][0]['points']);
$this->assertSame(4, $response['contacts'][0]['fields']['all']['points']);
$this->assertEquals(2, count($response['contacts'][0]['tags']));
$this->assertEquals($payload[0]['city'], $response['contacts'][0]['fields']['all']['city']);
$this->assertEquals($payload[0]['state'], $response['contacts'][0]['fields']['all']['state']);
$this->assertEquals($payload[0]['country'], $response['contacts'][0]['fields']['all']['country']);
$this->assertEquals($payload[0]['preferred_locale'], $response['contacts'][0]['fields']['all']['preferred_locale']);
$this->assertEquals($payload[0]['timezone'], $response['contacts'][0]['fields']['all']['timezone']);
$this->assertEquals($payload[0]['owner'], $response['contacts'][0]['owner']['id']);
// with overwriteWithBlank lastname is empty
$payload[0]['overwriteWithBlank'] = true;
$payload[0]['lastname'] = '';
// Lets try to create the same contact to see that the values are not re-setted
$this->client->request('POST', '/api/contacts/batch/new', $payload);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$this->assertEquals($contactId, $response['contacts'][0]['id']);
$this->assertEquals($payload[0]['email'], $response['contacts'][0]['fields']['all']['email']);
$this->assertEquals($payload[0]['firstname'], $response['contacts'][0]['fields']['all']['firstname']);
$this->assertEmpty($response['contacts'][0]['fields']['all']['lastname']);
$this->assertEquals(4, $response['contacts'][0]['points']);
$this->assertSame(4, $response['contacts'][0]['fields']['all']['points']);
$this->assertEquals(2, count($response['contacts'][0]['tags']));
// with overwriteWithBlank lastname is empty
$payload[0]['overwriteWithBlank'] = true;
$payload[0]['lastname'] = '';
// Lets try to create the same contact to see that the values are not re-setted
$this->client->request('POST', '/api/contacts/batch/new', $payload);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$this->assertEquals($contactId, $response['contacts'][0]['id']);
$this->assertEquals($payload[0]['email'], $response['contacts'][0]['fields']['all']['email']);
$this->assertEquals($payload[0]['firstname'], $response['contacts'][0]['fields']['all']['firstname']);
$this->assertEmpty($response['contacts'][0]['fields']['all']['lastname']);
$this->assertSame(4, $response['contacts'][0]['points']);
$this->assertSame(4, $response['contacts'][0]['fields']['all']['points']);
$this->assertEquals(2, count($response['contacts'][0]['tags']));
$this->assertEquals($payload[0]['city'], $response['contacts'][0]['fields']['all']['city']);
$this->assertEquals($payload[0]['state'], $response['contacts'][0]['fields']['all']['state']);
$this->assertEquals($payload[0]['country'], $response['contacts'][0]['fields']['all']['country']);
$this->assertEquals($payload[0]['preferred_locale'], $response['contacts'][0]['fields']['all']['preferred_locale']);
$this->assertEquals($payload[0]['timezone'], $response['contacts'][0]['fields']['all']['timezone']);
$this->assertEquals($payload[0]['owner'], $response['contacts'][0]['owner']['id']);
// Lets try to create the same contact and it should merge based on unique identifier (email)
$updatedValues = [
[
'email' => '[email protected]',
'lastname' => 'Update',
'city' => 'Boston',
'state' => 'Massachusetts',
'owner' => 2,
],
];
$this->client->request('POST', '/api/contacts/batch/new', $updatedValues);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$this->assertEquals($contactId, $response['contacts'][0]['id']);
$this->assertEquals($updatedValues[0]['email'], $response['contacts'][0]['fields']['all']['email']);
$this->assertEquals($payload[0]['firstname'], $response['contacts'][0]['fields']['all']['firstname']);
$this->assertEquals($updatedValues[0]['lastname'], $response['contacts'][0]['fields']['all']['lastname']);
$this->assertSame(4, $response['contacts'][0]['points']);
$this->assertSame(4, $response['contacts'][0]['fields']['all']['points']);
$this->assertEquals(2, count($response['contacts'][0]['tags']));
$this->assertEquals($updatedValues[0]['city'], $response['contacts'][0]['fields']['all']['city']);
$this->assertEquals($updatedValues[0]['state'], $response['contacts'][0]['fields']['all']['state']);
$this->assertEquals($payload[0]['country'], $response['contacts'][0]['fields']['all']['country']);
$this->assertEquals($payload[0]['preferred_locale'], $response['contacts'][0]['fields']['all']['preferred_locale']);
$this->assertEquals($payload[0]['timezone'], $response['contacts'][0]['fields']['all']['timezone']);
$this->assertEquals($updatedValues[0]['owner'], $response['contacts'][0]['owner']['id']);
// Test getting a contact
$this->client->request('GET', '/api/contacts/'.$contactId);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$this->assertEquals($contactId, $response['contact']['id']);
$this->assertEquals($payload[0]['email'], $response['contact']['fields']['all']['email']);
$this->assertEquals($payload[0]['firstname'], $response['contact']['fields']['all']['firstname']);
$this->assertSame(4, $response['contact']['points']);
$this->assertSame(4, $response['contact']['fields']['all']['points']);
$this->assertEquals(2, count($response['contact']['tags']));
$this->assertEquals($updatedValues[0]['city'], $response['contact']['fields']['all']['city']);
$this->assertEquals($updatedValues[0]['state'], $response['contact']['fields']['all']['state']);
$this->assertEquals($payload[0]['country'], $response['contact']['fields']['all']['country']);
$this->assertEquals($payload[0]['preferred_locale'], $response['contact']['fields']['all']['preferred_locale']);
$this->assertEquals($payload[0]['timezone'], $response['contact']['fields']['all']['timezone']);
$this->assertEquals($updatedValues[0]['owner'], $response['contact']['owner']['id']);
// Test fetching the batch of contacts
$this->client->request(
'GET', '/api/contacts');
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$this->assertTrue(isset($response['contacts'][$contactId]));
$contact = $response['contacts'][$contactId];
$this->assertEquals($contactId, $contact['id']);
$this->assertEquals($payload[0]['email'], $contact['fields']['all']['email']);
$this->assertEquals($payload[0]['firstname'], $contact['fields']['all']['firstname']);
$this->assertSame(4, $contact['points']);
$this->assertSame(4, $contact['fields']['all']['points']);
$this->assertEquals(2, count($contact['tags']));
$this->assertEquals($updatedValues[0]['city'], $contact['fields']['all']['city']);
$this->assertEquals($updatedValues[0]['state'], $contact['fields']['all']['state']);
$this->assertEquals($payload[0]['country'], $contact['fields']['all']['country']);
$this->assertEquals($payload[0]['preferred_locale'], $contact['fields']['all']['preferred_locale']);
$this->assertEquals($payload[0]['timezone'], $contact['fields']['all']['timezone']);
$this->assertEquals($updatedValues[0]['owner'], $contact['owner']['id']);
// Test patch and values should be updated
$updatedValues = [
[
'id' => $contactId,
'email' => '[email protected]',
'city' => 'Boston',
'state' => 'Massachusetts',
'firstname' => '', // This will be ignored because overwriteWithBlank is false by default.
'owner' => 2,
'points' => 1,
],
];
$this->client->request('PATCH', '/api/contacts/batch/edit', $updatedValues);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$this->assertEquals($contactId, $response['contacts'][0]['id']);
$this->assertEquals($updatedValues[0]['email'], $response['contacts'][0]['fields']['all']['email']);
$this->assertEquals($payload[0]['firstname'], $response['contacts'][0]['fields']['all']['firstname']);
$this->assertSame(1, $response['contacts'][0]['points']);
$this->assertSame(1, $response['contacts'][0]['fields']['all']['points']);
$this->assertEquals(2, count($response['contacts'][0]['tags']));
$this->assertEquals($updatedValues[0]['city'], $response['contacts'][0]['fields']['all']['city']);
$this->assertEquals($updatedValues[0]['state'], $response['contacts'][0]['fields']['all']['state']);
$this->assertEquals($payload[0]['country'], $response['contacts'][0]['fields']['all']['country']);
$this->assertEquals($payload[0]['preferred_locale'], $response['contacts'][0]['fields']['all']['preferred_locale']);
$this->assertEquals($payload[0]['timezone'], $response['contacts'][0]['fields']['all']['timezone']);
$this->assertEquals($updatedValues[0]['owner'], $response['contacts'][0]['owner']['id']);
// with overwriteWithBlank lastname is empty
$updatedValues = [
[
'id' => $contactId,
'lastname' => '',
'overwriteWithBlank' => true,
],
];
$this->client->request('PATCH', '/api/contacts/batch/edit', $updatedValues);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$this->assertEquals($contactId, $response['contacts'][0]['id']);
$this->assertEquals($payload[0]['email'], $response['contacts'][0]['fields']['all']['email']);
$this->assertEquals($payload[0]['firstname'], $response['contacts'][0]['fields']['all']['firstname']);
$this->assertEmpty($response['contacts'][0]['fields']['all']['lastname']);
}
public function testBatchDncAddAndRemove(): void
{
// Create contact
$emailAddress = uniqid('', false).'@mautic.com';
$payload = [
'id' => 80,
'email' => $emailAddress,
];
$this->client->request(Request::METHOD_POST, '/api/contacts/new', $payload);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$contactId = $response['contact']['id'];
// Batch update contact with new DNC record
$payload = [
[
'id' => $contactId,
'email' => $emailAddress,
'doNotContact' => [
[
'reason' => DoNotContact::MANUAL,
'comments' => 'manually',
'channel' => 'email',
'channelId' => null,
],
],
],
];
$this->client->request(Request::METHOD_PUT, '/api/contacts/batch/edit', $payload);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$this->assertSame(3, $response['contacts'][0]['doNotContact'][0]['reason']);
// Batch update contact and remove DNC record
$payload = [
[
'id' => $contactId,
'email' => $emailAddress,
'doNotContact' => [
[
'reason' => DoNotContact::IS_CONTACTABLE,
'comments' => 'manually',
'channel' => 'email',
'channelId' => null,
],
],
],
];
$this->client->request(Request::METHOD_PUT, '/api/contacts/batch/edit', $payload);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$this->assertEmpty($response['contacts'][0]['doNotContact']);
// Remove contact
$this->client->request(Request::METHOD_DELETE, "/api/contacts/$contactId/delete");
$clientResponse = $this->client->getResponse();
$this->assertSame(Response::HTTP_OK, $clientResponse->getStatusCode());
}
public function testAddAndRemoveDncToExistingContact(): void
{
// Create contact
$payload = ['email' => '[email protected]'];
$this->client->request(Request::METHOD_POST, '/api/contacts/new', $payload);
$clientResponse = $this->client->getResponse();
$response = json_decode($clientResponse->getContent(), true);
$contactId = $response['contact']['id'];
// Ensure that doNotContact is empty after creating the contact
$this->assertSame([], $response['contact']['doNotContact']);
// Check with a DNC payload that has an empty reasoncode in it, this should throw a 400 Bad Request error
$dncPayload = ['reason' => 0];
$dncChannel = 'email';
$this->client->request(Request::METHOD_POST, "/api/contacts/$contactId/dnc/$dncChannel/add", $dncPayload);
$clientResponse = $this->client->getResponse();
$this->assertSame(Response::HTTP_BAD_REQUEST, $clientResponse->getStatusCode());
// Leave the DNC payload empty to ensure it takes default values for channel and reason.
$dncPayload = [];
// Add DNC to the contact.
$this->client->request(Request::METHOD_POST, "/api/contacts/$contactId/dnc/$dncChannel/add", $dncPayload);
$clientResponse = $this->client->getResponse();
$dncResponse = json_decode($clientResponse->getContent(), true);
// MANUAL (3) is the default value according to the dev docs: https://developer.mautic.org/#add-do-not-contact
$this->assertSame(DoNotContact::MANUAL, $dncResponse['contact']['doNotContact'][0]['reason']);
$this->assertSame($dncChannel, $dncResponse['contact']['doNotContact'][0]['channel']);
// Check DNC is recorded in the contact activity.
$this->client->request('GET', "/api/contacts/{$contactId}/activity");
$clientResponse = $this->client->getResponse();
self::assertSame(Response::HTTP_OK, $clientResponse->getStatusCode(), $clientResponse->getContent());
$activityResponse = json_decode($clientResponse->getContent(), true);
Assert::assertCount(2, $activityResponse['events']); // identified and dnc added events
$dncEvents = array_values(array_filter($activityResponse['events'], fn ($event) => 'lead.donotcontact' === $event['event']));
Assert::assertCount(1, $dncEvents);
Assert::assertSame('Email', $dncEvents[0]['eventLabel']);
Assert::assertSame('Contact was manually set as do not contact for this channel.', $dncEvents[0]['details']['dnc']['reason']);
// Remove DNC from the contact.
$this->client->request(Request::METHOD_POST, "/api/contacts/$contactId/dnc/$dncChannel/remove");
$clientResponse = $this->client->getResponse();
self::assertSame(Response::HTTP_OK, $clientResponse->getStatusCode());
$dncRemoveResponse = json_decode($clientResponse->getContent(), true);
$this->assertArrayHasKey('contact', $dncRemoveResponse, $clientResponse->getContent());
$this->assertSame([], $dncRemoveResponse['contact']['doNotContact']);
// Remove the contact.
$this->client->request(Request::METHOD_DELETE, "/api/contacts/$contactId/delete");
$clientResponse = $this->client->getResponse();
$this->assertSame(Response::HTTP_OK, $clientResponse->getStatusCode());
}
private function createCompany(string $name): Company
{
$company = new Company();
$company->setName($name);
$this->em->persist($company);
$this->em->flush();
return $company;
}
}