feat: normalize email addresses to lowercase on write
This commit is contained in:
@@ -39,7 +39,9 @@ class Communication
|
||||
|
||||
public function setEmail(?string $email): static
|
||||
{
|
||||
$this->email = $email;
|
||||
// BusPro compares addresses case-insensitively; normalize on the way in so the DTO
|
||||
// carries the same shape the entities store.
|
||||
$this->email = null === $email ? null : mb_strtolower(trim($email));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ class Contact
|
||||
|
||||
public function setEmail(string $email): static
|
||||
{
|
||||
$this->email = $email;
|
||||
$this->email = mb_strtolower(trim($email));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ class Communication
|
||||
|
||||
public function setEmail(?string $email): static
|
||||
{
|
||||
$this->email = $email;
|
||||
$this->email = null === $email ? null : mb_strtolower(trim($email));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ class BpnAuthenticator extends AbstractLoginFormAuthenticator implements Authent
|
||||
|
||||
public function authenticate(Request $request): Passport
|
||||
{
|
||||
$email = trim($request->request->getString('_username'));
|
||||
$email = mb_strtolower(trim($request->request->getString('_username')));
|
||||
$passwordPlain = trim($request->request->getString('_password'));
|
||||
|
||||
// Very lame hashing applied here as required by BPN
|
||||
|
||||
@@ -200,6 +200,37 @@ class UserDataHandlerTest extends TestCase
|
||||
$this->assertSame(['team' => ['selected' => true]], $teamer->getCrmSelections());
|
||||
}
|
||||
|
||||
/**
|
||||
* BusPro compares addresses case-insensitively and MyE&P lowercases them on login, so a
|
||||
* mixed-case address coming back from the API must land lowercased on both the user and
|
||||
* the teamer - otherwise the login identity and the mailing address drift apart.
|
||||
*/
|
||||
public function testUpdateLocalUserNormalizesTheAddressBusProReports(): void
|
||||
{
|
||||
$user = (new User())
|
||||
->setFirstName('Old')
|
||||
->setLastName('Name')
|
||||
->setEmail('[email protected]')
|
||||
->setBusProAddressId(1)
|
||||
->setBusProPersonId(2)
|
||||
;
|
||||
|
||||
$teamer = (new Teamer())
|
||||
->setCommunication((new Communication())->setEmail('[email protected]'))
|
||||
;
|
||||
$user->setTeamer($teamer);
|
||||
|
||||
$profileResponse = $this->createProfileResponse()
|
||||
->setCommunication((new BusProCommunication())->setEmail('[email protected]'))
|
||||
;
|
||||
|
||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||
$handler->updateLocalUser($user, $profileResponse, true, [], ['ROLE_TEAMER'], []);
|
||||
|
||||
$this->assertSame('[email protected]', $user->getEmail());
|
||||
$this->assertSame('[email protected]', $teamer->getCommunication()?->getEmail());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider pendingRolesProvider
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Entity;
|
||||
|
||||
use App\Entity\Contact;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ContactTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Office contacts are normalized the same way User::setEmail() normalizes, so that every
|
||||
* stored address has one shape regardless of which form wrote it.
|
||||
*/
|
||||
public function testSetEmailNormalizesCaseAndSurroundingWhitespace(): void
|
||||
{
|
||||
$contact = (new Contact())->setEmail(' [email protected] ');
|
||||
|
||||
$this->assertSame('[email protected]', $contact->getEmail());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Entity\Embeddable;
|
||||
|
||||
use App\Entity\Embeddable\Communication;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Pins the lowercasing of the teamer's contact address. This is the address the profile form
|
||||
* writes and the one toPayload() pushes back to BusPro, so a mixed-case value entered here
|
||||
* would otherwise diverge from the login identity stored in User::email.
|
||||
*/
|
||||
class CommunicationTest extends TestCase
|
||||
{
|
||||
public function testSetEmailNormalizesCaseAndSurroundingWhitespace(): void
|
||||
{
|
||||
$communication = (new Communication())->setEmail(' [email protected] ');
|
||||
|
||||
$this->assertSame('[email protected]', $communication->getEmail());
|
||||
}
|
||||
|
||||
public function testSetEmailKeepsNull(): void
|
||||
{
|
||||
$communication = (new Communication())->setEmail(null);
|
||||
|
||||
$this->assertNull($communication->getEmail());
|
||||
}
|
||||
|
||||
/**
|
||||
* The outbound BusPro payload must carry the normalized form, not the raw input.
|
||||
*/
|
||||
public function testPayloadCarriesTheNormalizedAddress(): void
|
||||
{
|
||||
$communication = (new Communication())
|
||||
->setEmail('[email protected]')
|
||||
->setMobile('0170 1234567')
|
||||
;
|
||||
|
||||
$this->assertSame('[email protected]', $communication->toPayload()['email']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user