Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,29 @@
- `onCrmContactDelete`
- Added separated methods `RemoteEventsFactory::create` and `RemoteEventsFactory::validate` for create and validate incoming
events, [see details](https://github.com/bitrix24/b24phpsdk/issues/291)
- Added comprehensive unit tests for `RemoteEventsFactory::create` and `RemoteEventsFactory::validate` methods with 14 test cases covering:
- Event creation for supported event types (CRM Contact Add, Application Install)
- Handling of unsupported events
- Request validation
- Token validation with `Bitrix24AccountInterface`
- Special handling for `OnApplicationInstall` events
- Updated `ContactPersonInterface` implementation, [see details](https://github.com/bitrix24/b24phpsdk/issues/290) with new methods:
- Added `isEmailVerified(): bool` to check email verification status
- Added `isMobilePhoneVerified(): bool` to check mobile phone verification status
- Changed `changeEmail(?string $email)` signature (removed optional `$isEmailVerified` parameter)
- Changed `changeMobilePhone(?PhoneNumber $phoneNumber)` signature (removed optional `$isMobilePhoneVerified` parameter)
- Added `getUserAgentInfo(): UserAgentInfo` to replace separate methods for user agent data
- Added comprehensive unit tests for `UTMs` class with 28 test cases covering:
- Constructor with all, partial, and default parameters
- URL parsing with various UTM parameter combinations
- Case-insensitive parameter handling
- URL encoding and special characters
- Real-world URL examples (Google Ads, Facebook, Email, Twitter, LinkedIn, etc.)
- Added comprehensive unit tests for `UserAgentInfo` class with 33 test cases covering:
- Constructor with IP addresses (IPv4, IPv6, localhost)
- Various user agent strings (Chrome, Firefox, Safari, Edge, mobile browsers)
- UTM extraction from referrer URLs
- Real-world scenarios with complete user tracking data

### Fixed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,18 @@ public function getUpdatedAt(): CarbonImmutable;
*/
public function getEmail(): ?string;

public function changeEmail(?string $email, ?bool $isEmailVerified = null): void;
public function changeEmail(?string $email): void;

/**
* @return void mark contact person email as verified (send check main)
*/
public function markEmailAsVerified(): void;

/**
* @return bool is email verified with send code or magic link
*/
public function isEmailVerified(): bool;

/**
* @return CarbonImmutable|null is contact person email verified
*/
Expand All @@ -89,10 +94,15 @@ public function getEmailVerifiedAt(): ?CarbonImmutable;
/**
* Change mobile phone for contact person
*/
public function changeMobilePhone(?PhoneNumber $phoneNumber, ?bool $isMobilePhoneVerified = null): void;
public function changeMobilePhone(?PhoneNumber $phoneNumber): void;

public function getMobilePhone(): ?PhoneNumber;

/**
* @return bool is mobile phone verified with send sms code
*/
public function isMobilePhoneVerified(): bool;

/**
* @return CarbonImmutable|null is contact person mobile phone verified
*/
Expand Down Expand Up @@ -133,18 +143,5 @@ public function getBitrix24PartnerId(): ?Uuid;
*/
public function setBitrix24PartnerId(?Uuid $uuid): void;

/**
* get user agent for contact person, use for store metadata in consent agreements facts
*/
public function getUserAgent(): ?string;

/**
* get user agent referer for contact person use for store metadata in consent agreements facts
*/
public function getUserAgentReferer(): ?string;

/**
* get user agent ip for contact person use for store metadata in consent agreements facts
*/
public function getUserAgentIp(): ?IP;
public function getUserAgentInfo(): UserAgentInfo;
}
5 changes: 2 additions & 3 deletions src/Application/Contracts/ContactPersons/Entity/FullName.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ public function __construct(
public string $name,
public ?string $surname = null,
public ?string $patronymic = null
)
{
) {
if ($surname !== null) {
$this->surname = trim($surname);
}
Expand All @@ -41,4 +40,4 @@ public function __toString(): string
{
return sprintf('%s %s %s', $this->name, $this->surname, $this->patronymic);
}
}
}
67 changes: 67 additions & 0 deletions src/Application/Contracts/ContactPersons/Entity/UTMs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

/**
* This file is part of the bitrix24-php-sdk package.
*
* © Maksim Mesilov <mesilov.maxim@gmail.com>
*
* For the full copyright and license information, please view the MIT-LICENSE.txt
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Bitrix24\SDK\Application\Contracts\ContactPersons\Entity;

use function parse_url;
use function parse_str;

readonly class UTMs
{
public function __construct(
/**
* Identifies which site sent the traffic (google, facebook, twitter, etc.)
*/
public ?string $source = null,
/**
* Identifies what type of link was used (cpc, banner, email, etc.)
*/
public ?string $medium = null,
/**
* Identifies a specific product promotion or strategic campaign
*/
public ?string $campaign = null,
/**
* Identifies search terms used by paid search campaigns
*/
public ?string $term = null,
/**
* Identifies what specifically was clicked to bring the user to the site (banner ad, text link, etc.)
*/
public ?string $content = null,
) {
}

/**
* Create UTMs object from URL string
*/
public static function fromUrl(string $url): self
{
$query = parse_url($url, PHP_URL_QUERY);
if ($query === null || $query === false) {
return new self();
}

$query = strtolower($query);
parse_str($query, $params);

return new self(
$params['utm_source'] ?? null,
$params['utm_medium'] ?? null,
$params['utm_campaign'] ?? null,
$params['utm_term'] ?? null,
$params['utm_content'] ?? null
);
}

}
36 changes: 36 additions & 0 deletions src/Application/Contracts/ContactPersons/Entity/UserAgentInfo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

/**
* This file is part of the bitrix24-php-sdk package.
*
* © Maksim Mesilov <mesilov.maxim@gmail.com>
*
* For the full copyright and license information, please view the MIT-LICENSE.txt
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Bitrix24\SDK\Application\Contracts\ContactPersons\Entity;

use Darsyn\IP\Version\Multi as IP;

readonly class UserAgentInfo
{
public function __construct(
public ?IP $ip,
public ?string $userAgent = null,
public ?string $referrer = null,
public ?string $fingerprint = null,
) {
}

public function getUTMs(): UTMs
{
if ($this->referrer === null) {
return new UTMs();
}

return UTMs::fromUrl($this->referrer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -444,20 +444,6 @@ final public function testChangeEmail(
$contactPerson->changeEmail($newEmail);
$this->assertEquals($newEmail, $contactPerson->getEmail());
$this->assertNull($contactPerson->getEmailVerifiedAt());

$newEmail = DemoDataGenerator::getEmail();
$contactPerson->changeEmail($newEmail, true);
$this->assertEquals($newEmail, $contactPerson->getEmail());
$this->assertNotNull($contactPerson->getEmailVerifiedAt());
$newEmail = DemoDataGenerator::getEmail();
$contactPerson->changeEmail($newEmail);
$this->assertEquals($newEmail, $contactPerson->getEmail());
$this->assertNull($contactPerson->getEmailVerifiedAt());

$newEmail = DemoDataGenerator::getEmail();
$contactPerson->changeEmail($newEmail, false);
$this->assertEquals($newEmail, $contactPerson->getEmail());
$this->assertNull($contactPerson->getEmailVerifiedAt());
}

#[Test]
Expand Down Expand Up @@ -552,14 +538,6 @@ final public function testChangeMobilePhone(
$phone = DemoDataGenerator::getMobilePhone();
$contactPerson->changeMobilePhone($phone);
$this->assertNull($contactPerson->getMobilePhoneVerifiedAt());

$phone = DemoDataGenerator::getMobilePhone();
$contactPerson->changeMobilePhone($phone, false);
$this->assertNull($contactPerson->getMobilePhoneVerifiedAt());

$phone = DemoDataGenerator::getMobilePhone();
$contactPerson->changeMobilePhone($phone, true);
$this->assertNotNull($contactPerson->getMobilePhoneVerifiedAt());
}

#[Test]
Expand Down Expand Up @@ -590,7 +568,10 @@ final public function testGetMobilePhoneVerifiedAt(
$this->assertEquals($phoneNumber, $contactPerson->getMobilePhone());

$phone = DemoDataGenerator::getMobilePhone();
$contactPerson->changeMobilePhone($phone, true);
$contactPerson->changeMobilePhone($phone);
$this->assertNull($contactPerson->getMobilePhoneVerifiedAt());

$contactPerson->markMobilePhoneAsVerified();
$this->assertNotNull($contactPerson->getMobilePhoneVerifiedAt());
}

Expand Down Expand Up @@ -830,8 +811,8 @@ final public function testSetBitrix24PartnerId(

#[Test]
#[DataProvider('contactPersonDataProvider')]
#[TestDox('test getUserAgent method')]
final public function testGetUserAgent(
#[TestDox('test isEmailVerified method')]
final public function testIsEmailVerified(
Uuid $uuid,
CarbonImmutable $createdAt,
CarbonImmutable $updatedAt,
Expand All @@ -853,13 +834,27 @@ final public function testGetUserAgent(
): void
{
$contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp);
$this->assertEquals($userAgent, $contactPerson->getUserAgent());

if ($emailVerifiedAt !== null) {
$this->assertTrue($contactPerson->isEmailVerified());
} else {
$this->assertFalse($contactPerson->isEmailVerified());
}

// Change email should reset verification
$newEmail = DemoDataGenerator::getEmail();
$contactPerson->changeEmail($newEmail);
$this->assertFalse($contactPerson->isEmailVerified());

// Mark as verified
$contactPerson->markEmailAsVerified();
$this->assertTrue($contactPerson->isEmailVerified());
}

#[Test]
#[DataProvider('contactPersonDataProvider')]
#[TestDox('test getUserAgentReferer method')]
final public function testGetUserAgentReferer(
#[TestDox('test isMobilePhoneVerified method')]
final public function testIsMobilePhoneVerified(
Uuid $uuid,
CarbonImmutable $createdAt,
CarbonImmutable $updatedAt,
Expand All @@ -881,13 +876,27 @@ final public function testGetUserAgentReferer(
): void
{
$contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp);
$this->assertEquals($userAgentReferer, $contactPerson->getUserAgentReferer());

if ($mobilePhoneVerifiedAt !== null) {
$this->assertTrue($contactPerson->isMobilePhoneVerified());
} else {
$this->assertFalse($contactPerson->isMobilePhoneVerified());
}

// Change phone should reset verification
$newPhone = DemoDataGenerator::getMobilePhone();
$contactPerson->changeMobilePhone($newPhone);
$this->assertFalse($contactPerson->isMobilePhoneVerified());

// Mark as verified
$contactPerson->markMobilePhoneAsVerified();
$this->assertTrue($contactPerson->isMobilePhoneVerified());
}

#[Test]
#[DataProvider('contactPersonDataProvider')]
#[TestDox('test getUserAgentIp method')]
final public function testGetUserAgentIp(
#[TestDox('test getUserAgentInfo method')]
final public function testGetUserAgentInfo(
Uuid $uuid,
CarbonImmutable $createdAt,
CarbonImmutable $updatedAt,
Expand All @@ -909,7 +918,11 @@ final public function testGetUserAgentIp(
): void
{
$contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp);
$this->assertEquals($userAgentIp, $contactPerson->getUserAgentIp());
$userAgentInfo = $contactPerson->getUserAgentInfo();

$this->assertEquals($userAgent, $userAgentInfo->userAgent);
$this->assertEquals($userAgentReferer, $userAgentInfo->referrer);
$this->assertEquals($userAgentIp, $userAgentInfo->ip);
}

public static function contactPersonDataProvider(): Generator
Expand Down
Loading