feat(monorepo): migrate to typescript monorepo
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Basango\IdentityAndAccess\Presentation\Console;
|
||||
|
||||
use Basango\IdentityAndAccess\Application\UseCase\Command\Register;
|
||||
use Basango\IdentityAndAccess\Domain\Model\ValueObject\Roles;
|
||||
use Basango\SharedKernel\Application\Messaging\CommandBus;
|
||||
use Basango\SharedKernel\Domain\Model\ValueObject\EmailAddress;
|
||||
use Basango\SharedKernel\Presentation\Console\AskArgumentFeature;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* Class RegisterConsole.
|
||||
*
|
||||
* @author bernard-ng <bernard@devscast.tech>
|
||||
*/
|
||||
#[AsCommand('app:user-register', 'register a new user')]
|
||||
final class RegisterConsole extends Command
|
||||
{
|
||||
use AskArgumentFeature;
|
||||
|
||||
private SymfonyStyle $io;
|
||||
|
||||
public function __construct(
|
||||
private readonly CommandBus $commandBus,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDescription('Creates users and stores them in the database')
|
||||
->addArgument('name', InputArgument::OPTIONAL, 'The name of the new user')
|
||||
->addArgument('email', InputArgument::OPTIONAL, 'The email of the new user')
|
||||
->addArgument('password', InputArgument::OPTIONAL, 'The plain password of the new user')
|
||||
->addOption('admin', null, InputOption::VALUE_NONE, 'If set, the user is created as an administrator');
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
protected function initialize(InputInterface $input, OutputInterface $output): void
|
||||
{
|
||||
$this->io = new SymfonyStyle($input, $output);
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
protected function interact(InputInterface $input, OutputInterface $output): void
|
||||
{
|
||||
if (
|
||||
$input->getArgument('name') !== null &&
|
||||
$input->getArgument('email') !== null &&
|
||||
$input->getArgument('password') !== null
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->askArgument($input, 'name');
|
||||
$this->askArgument($input, 'email');
|
||||
$this->askArgument($input, 'password', true);
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
/** @var string $name */
|
||||
$name = $input->getArgument('name');
|
||||
|
||||
/** @var string $email */
|
||||
$email = $input->getArgument('email');
|
||||
|
||||
/** @var string $password */
|
||||
$password = $input->getArgument('password');
|
||||
|
||||
/** @var bool $admin */
|
||||
$admin = $input->getOption('admin');
|
||||
|
||||
$command = new Register($name, EmailAddress::from($email), $password, $admin ? Roles::admin() : Roles::user());
|
||||
$this->commandBus->handle($command);
|
||||
$this->io->success(\sprintf('%s was created: %s', $admin ? 'ADMIN' : 'USER', $email));
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Basango\IdentityAndAccess\Presentation\Web\Controller;
|
||||
|
||||
use Basango\IdentityAndAccess\Application\UseCase\Command\ConfirmAccount;
|
||||
use Basango\IdentityAndAccess\Domain\Model\ValueObject\Secret\GeneratedToken;
|
||||
use Basango\SharedKernel\Presentation\Web\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Routing\Requirement\Requirement;
|
||||
|
||||
/**
|
||||
* Class UnlockAccountController.
|
||||
*
|
||||
* @author bernard-ng <bernard@devscast.tech>
|
||||
*/
|
||||
final class ConfirmAccountController extends AbstractController
|
||||
{
|
||||
#[Route(
|
||||
path: '/api/account/confirm/{token}',
|
||||
name: 'identity_and_access_confirm_account',
|
||||
requirements: [
|
||||
'token' => Requirement::ASCII_SLUG,
|
||||
],
|
||||
methods: ['GET']
|
||||
)]
|
||||
public function __invoke(string $token): JsonResponse
|
||||
{
|
||||
$token = new GeneratedToken($token);
|
||||
$this->handleCommand(new ConfirmAccount($token));
|
||||
|
||||
return new JsonResponse(status: 200);
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Basango\IdentityAndAccess\Presentation\Web\Controller;
|
||||
|
||||
use Basango\IdentityAndAccess\Application\UseCase\Query\GetUserProfile;
|
||||
use Basango\SharedKernel\Presentation\Web\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
/**
|
||||
* Class GetUserProfileController.
|
||||
*
|
||||
* @author bernard-ng <bernard@devscast.tech>
|
||||
*/
|
||||
final class GetUserProfileController extends AbstractController
|
||||
{
|
||||
#[Route(
|
||||
path: '/api/me',
|
||||
name: 'identity_and_access_me',
|
||||
methods: ['GET']
|
||||
)]
|
||||
public function __invoke(): JsonResponse
|
||||
{
|
||||
$security = $this->getSecurityUser();
|
||||
$data = $this->handleQuery(new GetUserProfile($security->userId));
|
||||
|
||||
return JsonResponse::fromJsonString($this->serialize($data));
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Basango\IdentityAndAccess\Presentation\Web\Controller;
|
||||
|
||||
use Basango\IdentityAndAccess\Application\UseCase\Command\Register;
|
||||
use Basango\IdentityAndAccess\Presentation\WriteModel\RegisterModel;
|
||||
use Basango\SharedKernel\Domain\Model\ValueObject\EmailAddress;
|
||||
use Basango\SharedKernel\Presentation\Web\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
/**
|
||||
* Class RegisterController.
|
||||
*
|
||||
* @author bernard-ng <bernard@devscast.tech>
|
||||
*/
|
||||
final class RegisterController extends AbstractController
|
||||
{
|
||||
#[Route(
|
||||
path: '/api/register',
|
||||
name: 'identity_and_access_register',
|
||||
methods: ['POST']
|
||||
)]
|
||||
public function __invoke(#[MapRequestPayload] RegisterModel $model): JsonResponse
|
||||
{
|
||||
$this->handleCommand(new Register(
|
||||
$model->name,
|
||||
EmailAddress::from($model->email),
|
||||
$model->password
|
||||
));
|
||||
|
||||
return new JsonResponse(status: 201);
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Basango\IdentityAndAccess\Presentation\Web\Controller;
|
||||
|
||||
use Basango\IdentityAndAccess\Application\UseCase\Command\RequestPassword;
|
||||
use Basango\IdentityAndAccess\Presentation\WriteModel\RequestPasswordModel;
|
||||
use Basango\SharedKernel\Domain\Model\ValueObject\EmailAddress;
|
||||
use Basango\SharedKernel\Presentation\Web\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
/**
|
||||
* Class RequestPasswordController.
|
||||
*
|
||||
* @author bernard-ng <bernard@devscast.tech>
|
||||
*/
|
||||
final class RequestPasswordController extends AbstractController
|
||||
{
|
||||
#[Route(
|
||||
path: '/api/password/request',
|
||||
name: 'identity_and_access_request_password',
|
||||
methods: ['POST']
|
||||
)]
|
||||
public function __invoke(#[MapRequestPayload] RequestPasswordModel $model): JsonResponse
|
||||
{
|
||||
$email = EmailAddress::from($model->email);
|
||||
$this->handleCommand(new RequestPassword($email));
|
||||
|
||||
return new JsonResponse(status: 200);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Basango\IdentityAndAccess\Presentation\Web\Controller;
|
||||
|
||||
use Basango\IdentityAndAccess\Application\UseCase\Command\ResetPassword;
|
||||
use Basango\IdentityAndAccess\Domain\Model\ValueObject\Secret\GeneratedToken;
|
||||
use Basango\IdentityAndAccess\Presentation\WriteModel\ResetPasswordModel;
|
||||
use Basango\SharedKernel\Presentation\Web\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Routing\Requirement\Requirement;
|
||||
|
||||
/**
|
||||
* Class RequestPasswordController.
|
||||
*
|
||||
* @author bernard-ng <bernard@devscast.tech>
|
||||
*/
|
||||
final class ResetPasswordController extends AbstractController
|
||||
{
|
||||
#[Route(
|
||||
path: '/api/password/reset/{token}',
|
||||
name: 'identity_and_access_reset_password',
|
||||
requirements: [
|
||||
'token' => Requirement::ASCII_SLUG,
|
||||
],
|
||||
methods: ['POST']
|
||||
)]
|
||||
public function __invoke(#[MapRequestPayload] ResetPasswordModel $model, string $token): JsonResponse
|
||||
{
|
||||
$token = new GeneratedToken($token);
|
||||
$this->handleCommand(new ResetPassword($token, $model->password));
|
||||
|
||||
return new JsonResponse(status: 200);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Basango\IdentityAndAccess\Presentation\Web\Controller;
|
||||
|
||||
use Basango\IdentityAndAccess\Application\UseCase\Command\UnlockAccount;
|
||||
use Basango\IdentityAndAccess\Domain\Model\ValueObject\Secret\GeneratedToken;
|
||||
use Basango\SharedKernel\Presentation\Web\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Routing\Requirement\Requirement;
|
||||
|
||||
/**
|
||||
* Class UnlockAccountController.
|
||||
*
|
||||
* @author bernard-ng <bernard@devscast.tech>
|
||||
*/
|
||||
final class UnlockAccountController extends AbstractController
|
||||
{
|
||||
#[Route(
|
||||
path: '/api/account/unlock/{token}',
|
||||
name: 'identity_and_access_unlock_account',
|
||||
requirements: [
|
||||
'token' => Requirement::ASCII_SLUG,
|
||||
],
|
||||
methods: ['GET']
|
||||
)]
|
||||
public function __invoke(string $token): JsonResponse
|
||||
{
|
||||
$token = new GeneratedToken($token);
|
||||
$this->handleCommand(new UnlockAccount($token));
|
||||
|
||||
return new JsonResponse(status: 200);
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Basango\IdentityAndAccess\Presentation\Web\Controller;
|
||||
|
||||
use Basango\IdentityAndAccess\Application\UseCase\Command\UpdatePassword;
|
||||
use Basango\IdentityAndAccess\Presentation\WriteModel\UpdatePasswordModel;
|
||||
use Basango\SharedKernel\Presentation\Web\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
/**
|
||||
* Class UpdatePasswordController.
|
||||
*
|
||||
* @author bernard-ng <bernard@devscast.tech>
|
||||
*/
|
||||
final class UpdatePasswordController extends AbstractController
|
||||
{
|
||||
#[Route(
|
||||
path: '/api/password/update',
|
||||
name: 'identity_and_access_update_password',
|
||||
methods: ['POST']
|
||||
)]
|
||||
public function __invoke(#[MapRequestPayload] UpdatePasswordModel $model): JsonResponse
|
||||
{
|
||||
$securityUser = $this->getSecurityUser();
|
||||
$this->handleCommand(new UpdatePassword(
|
||||
$securityUser->userId,
|
||||
$model->current,
|
||||
$model->password
|
||||
));
|
||||
|
||||
return new JsonResponse(status: 200);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Basango\IdentityAndAccess\Presentation\WriteModel;
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* Class RegisterModel.
|
||||
*
|
||||
* @author bernard-ng <bernard@devscast.tech>
|
||||
*/
|
||||
final class RegisterModel
|
||||
{
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Length(min: 3, max: 255)]
|
||||
public string $name;
|
||||
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Email]
|
||||
public string $email;
|
||||
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Length(max: 512)]
|
||||
public string $password;
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Basango\IdentityAndAccess\Presentation\WriteModel;
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* Class RequestPasswordModel.
|
||||
*
|
||||
* @author bernard-ng <bernard@devscast.tech>
|
||||
*/
|
||||
final class RequestPasswordModel
|
||||
{
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Email]
|
||||
#[Assert\Length(max: 255)]
|
||||
public string $email;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Basango\IdentityAndAccess\Presentation\WriteModel;
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* Class RequestPasswordModel.
|
||||
*
|
||||
* @author bernard-ng <bernard@devscast.tech>
|
||||
*/
|
||||
final class ResetPasswordModel
|
||||
{
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Length(max: 512)]
|
||||
#[Assert\PasswordStrength]
|
||||
public string $password;
|
||||
|
||||
#[Assert\EqualTo(
|
||||
propertyPath: 'password',
|
||||
message: 'identity_and_access.exceptions.passwords_do_not_match',
|
||||
)]
|
||||
public string $confirm;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Basango\IdentityAndAccess\Presentation\WriteModel;
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* Class RegisterModel.
|
||||
*
|
||||
* @author bernard-ng <bernard@devscast.tech>
|
||||
*/
|
||||
final class UpdatePasswordModel
|
||||
{
|
||||
#[Assert\NotBlank]
|
||||
public string $current;
|
||||
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Length(max: 512)]
|
||||
#[Assert\PasswordStrength]
|
||||
public string $password;
|
||||
|
||||
#[Assert\EqualTo(
|
||||
propertyPath: 'password',
|
||||
message: 'identity_and_access.exceptions.passwords_do_not_match',
|
||||
)]
|
||||
public string $confirm;
|
||||
}
|
||||
Reference in New Issue
Block a user