diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 1c6454f..191ba3a 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -13,7 +13,7 @@ security: app_user_provider: entity: class: App\Entity\User\User - property: username + property: handle firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ diff --git a/src/ApiResource/User/UserApiResource.php b/src/ApiResource/User/UserApiResource.php index 9365cb8..883074a 100644 --- a/src/ApiResource/User/UserApiResource.php +++ b/src/ApiResource/User/UserApiResource.php @@ -49,13 +49,7 @@ class UserApiResource #[Assert\NotBlank()] #[Assert\Length(min: 4, max: 30)] #[Assert\Regex('/^[a-z0-9_]+$/')] - public string $username; - - /** - * Display name chosen by the User. - */ - #[API\ApiFilter(filterClass: SearchFilter::class, strategy: 'partial')] - public string $name; + public string $handle; /** * A list of the roles assigned to this User. Admin scopped property. diff --git a/src/Benzina/UsersPump.php b/src/Benzina/UsersPump.php index 3db20c7..06d63e7 100644 --- a/src/Benzina/UsersPump.php +++ b/src/Benzina/UsersPump.php @@ -27,7 +27,7 @@ class UsersPump extends AbstractPump public function pump(mixed $record): void { $user = new User(); - $user->setUsername($this->getUsername($record)); + $user->setHandle($this->buildHandle($record)); $user->setPassword($record['password'] ?? ''); $user->setEmail($record['email']); $user->setEmailConfirmed(false); @@ -42,40 +42,40 @@ class UsersPump extends AbstractPump ++$this->userCount; } - private function normalizeUsername(string $username): ?string + private function normalizeStringForHandle(string $value): ?string { // If email remove provider - if (\str_contains($username, '@') && \preg_match('/^[\w]+[^@]/', $username, $matches)) { - $username = $matches[0]; + if (\str_contains($value, '@') && \preg_match('/^[\w]+[^@]/', $value, $matches)) { + $value = $matches[0]; } - // Only lowercase a-z, numbers and underscore in usernames - $username = \preg_replace('/[^a-z0-9_]/', '_', \strtolower($username)); + // Only lowercase a-z, numbers and underscore in user handles + $value = \preg_replace('/[^a-z0-9_]/', '_', \strtolower($value)); // Min length 4 - $username = \str_pad($username, 4, '_'); + $value = \str_pad($value, 4, '_'); // Max length 30 - $username = \substr($username, 0, 30); + $value = \substr($value, 0, 30); - if (strlen(str_replace('_', '', $username)) < 1) { + if (strlen(str_replace('_', '', $value)) < 1) { return null; } - return $username; + return $value; } - private function getUsername(array $record): string + private function buildHandle(array $record): string { - $username = $this->normalizeUsername($record['id']); + $handle = $this->normalizeStringForHandle($record['id']); - if ($username === null) { - $username = $this->normalizeUsername($record['email']); + if ($handle === null) { + $handle = $this->normalizeStringForHandle($record['email']); } $sequenceNumber = \substr($this->userCount, -2, 2); - return \sprintf('%s_%s', $username, $sequenceNumber); + return \sprintf('%s_%s', $handle, $sequenceNumber); } private function getDateCreated(array $record): \DateTime diff --git a/src/Dto/UserTokenLoginDto.php b/src/Dto/UserTokenLoginDto.php index 5befd58..4264cb4 100644 --- a/src/Dto/UserTokenLoginDto.php +++ b/src/Dto/UserTokenLoginDto.php @@ -13,7 +13,7 @@ use Symfony\Component\Validator\Constraints as Assert; final class UserTokenLoginDto { /** - * The identifier (email, username) of the User to be authenticated. + * The identifier (email, handle) of the User to be authenticated. */ #[Assert\NotBlank()] public readonly string $identifier; diff --git a/src/Entity/User/User.php b/src/Entity/User/User.php index 630fce8..67f19c2 100644 --- a/src/Entity/User/User.php +++ b/src/Entity/User/User.php @@ -30,7 +30,7 @@ use Symfony\Component\Security\Core\User\UserInterface; #[ORM\Entity(repositoryClass: UserRepository::class)] #[ORM\Index(fields: ['migratedId'])] #[UniqueEntity('email', message: 'This email address is already registered.')] -#[UniqueEntity('username', message: 'This usernames already exists.')] +#[UniqueEntity('handle', message: 'This handle is already in use.')] class User implements UserInterface, PasswordAuthenticatedUserInterface, AccountingOwnerInterface { use MigratedEntity; @@ -57,7 +57,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface, Account */ #[Gedmo\Versioned] #[ORM\Column(length: 255, unique: true)] - private ?string $username = null; + private ?string $handle = null; /** * @var list The user roles. Admin only property. @@ -130,7 +130,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface, Account */ public function getUserIdentifier(): string { - return (string) $this->username; + return (string) $this->handle; } public function getEmail(): ?string @@ -157,14 +157,14 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface, Account return $this; } - public function getUsername(): ?string + public function getHandle(): ?string { - return $this->username; + return $this->handle; } - public function setUsername(?string $username): static + public function setHandle(?string $handle): static { - $this->username = strtolower($username); + $this->handle = strtolower($handle); return $this; } diff --git a/src/Filter/UserQueryFilter.php b/src/Filter/UserQueryFilter.php index e179cb3..8aa1950 100644 --- a/src/Filter/UserQueryFilter.php +++ b/src/Filter/UserQueryFilter.php @@ -42,8 +42,7 @@ final class UserQueryFilter extends AbstractFilter $queryBuilder ->andWhere(sprintf('%s.email LIKE :%s', $rootAlias, $parameterName)) - ->orWhere(sprintf('%s.name LIKE :%s', $rootAlias, $parameterName)) - ->orWhere(sprintf('%s.username LIKE :%s', $rootAlias, $parameterName)) + ->orWhere(sprintf('%s.handle LIKE :%s', $rootAlias, $parameterName)) ->setParameter($parameterName, $value); } @@ -55,7 +54,7 @@ final class UserQueryFilter extends AbstractFilter 'property' => $property, 'type' => Type::BUILTIN_TYPE_STRING, 'required' => false, - 'description' => 'Query Users by email, name or username. Fuzzy.', + 'description' => 'Query Users by email or handle. Fuzzy.', ]; } diff --git a/src/OpenApi/OpenApiDescription.md b/src/OpenApi/OpenApiDescription.md index 3e53ec8..2417bbe 100644 --- a/src/OpenApi/OpenApiDescription.md +++ b/src/OpenApi/OpenApiDescription.md @@ -23,7 +23,7 @@ curl -X 'GET' \ UserTokens exist under an User's scope, when you obtain a token this will only grant you as much permissions as the User under which it was created. -To obtain a UserToken you must send a POST request to [/v4/user_tokens](/v4/user_tokens) with the User login credentials (username and password) in the payload. If the credentials are correct a UserToken will be created, the `token` property value of which you must include in future requests. +To obtain a UserToken you must send a POST request to [/v4/user_tokens](/v4/user_tokens) with the User login credentials (identifier and password) in the payload. If the credentials are correct a UserToken will be created, the `token` property value of which you must include in future requests. Users can delete UserTokens owned by them at any moment, revoking your application's access to the v4 API on their behalf. When a UserToken fails to authenticate a request you will receive a 401 Unauthorized response from the API, at which point your application must look to get a new UserToken from the User. diff --git a/src/Repository/User/UserRepository.php b/src/Repository/User/UserRepository.php index 6e00a27..84c3c42 100644 --- a/src/Repository/User/UserRepository.php +++ b/src/Repository/User/UserRepository.php @@ -44,14 +44,14 @@ class UserRepository extends ServiceEntityRepository implements PasswordUpgrader /** * Find an User by any of it's unique properties. * - * @param string $identifier An id, email or username + * @param string $identifier An id, email or handle */ public function findOneByIdentifier(string $identifier): ?User { return $this->createQueryBuilder('u') ->andWhere('u.id = :val') ->orWhere('u.email = :val') - ->orWhere('u.username = :val') + ->orWhere('u.handle = :val') ->setParameter('val', $identifier) ->getQuery() ->getOneOrNullResult(); diff --git a/src/Service/Auth/AuthService.php b/src/Service/Auth/AuthService.php index 8d507ee..1bd1d47 100644 --- a/src/Service/Auth/AuthService.php +++ b/src/Service/Auth/AuthService.php @@ -54,7 +54,7 @@ class AuthService } return $this->userRepository->findOneBy( - ['username' => $loggedInUser->getUserIdentifier()] + ['handle' => $loggedInUser->getUserIdentifier()] ); } }