generated from flo/template-backend
default functions
This commit is contained in:
parent
9237801bc1
commit
6d97fc24c4
@ -201,8 +201,8 @@ use Psr\\Http\\Server\\RequestHandlerInterface;
|
||||
class {$apiHandlerName} implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly {$cqrsHandlerName} \${$cqrsHandlerVariableName},
|
||||
private readonly {$cqrsBuilderName} \${$cqrsBuilderVariableName},
|
||||
private readonly {$cqrsHandlerName} \$handler,
|
||||
private readonly {$cqrsBuilderName} \$builder,
|
||||
private readonly {$apiResponseFormatterName} \$responseFormatter,
|
||||
) {
|
||||
}
|
||||
@ -211,10 +211,10 @@ class {$apiHandlerName} implements RequestHandlerInterface
|
||||
{
|
||||
\$data = \$request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
|
||||
|
||||
\${$cqrsVariableName} = \$this->{$cqrsBuilderVariableName}->build(
|
||||
\${$cqrsVariableName} = \$this->builder->build(
|
||||
\$data
|
||||
);
|
||||
\$result = \$this->{$cqrsHandlerVariableName}->execute(\${$cqrsVariableName});
|
||||
\$result = \$this->handler->execute(\${$cqrsVariableName});
|
||||
|
||||
return new SuccessResponse(\$this->responseFormatter->format(\$result));
|
||||
}
|
||||
@ -251,10 +251,10 @@ namespace {$cqrsHandlerNamespace};
|
||||
class {$cqrsName}
|
||||
{
|
||||
public function __construct(
|
||||
#TODO
|
||||
) {
|
||||
#TODO
|
||||
) {
|
||||
}
|
||||
|
||||
|
||||
#TODO
|
||||
}
|
||||
";
|
||||
@ -270,14 +270,12 @@ class {$cqrsHandlerName}
|
||||
{
|
||||
public function __construct(
|
||||
#TODO
|
||||
) {
|
||||
) {
|
||||
}
|
||||
|
||||
|
||||
public function execute({$cqrsName} \${$cqrsVariableName}): {$cqrsResultName}
|
||||
{
|
||||
return new {$cqrsResultName}(
|
||||
|
||||
);
|
||||
return new {$cqrsResultName}();
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
BIN
data/mails/reset-password/assets/icon.png
Normal file
BIN
data/mails/reset-password/assets/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
63
data/mails/reset-password/template.latte
Normal file
63
data/mails/reset-password/template.latte
Normal file
@ -0,0 +1,63 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Passwort zurücksetzen</title>
|
||||
<style>
|
||||
body {
|
||||
}
|
||||
.message-block {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
margin-top: 20px;
|
||||
padding: 20px;
|
||||
}
|
||||
.header {
|
||||
background-color: rgb(255, 199, 44);
|
||||
width: 100%;
|
||||
height: 15%;
|
||||
text-align: center;
|
||||
}
|
||||
.title {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.wrapper {
|
||||
display: inline-block;
|
||||
}
|
||||
.quote {
|
||||
font-style: italic;
|
||||
font-size: x-small;
|
||||
color: slategray;
|
||||
}
|
||||
img {
|
||||
margin: 1rem;
|
||||
}
|
||||
h1 {
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header" class="header">
|
||||
<div class="wrapper">
|
||||
<div id="title" class="title">
|
||||
<img src="assets/icon.png" />
|
||||
<h1>Beekeeper</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="message-block" class="message-block">
|
||||
<p>Hallo {$username},</p>
|
||||
<br />
|
||||
<p>Dein Passwort wurde zurückgesetzt.</p>
|
||||
<p>Bitte klicke auf <a href="{$passwordResetLink}">diesen Link</a> um ein neues Passwort zu vergeben.</p>
|
||||
<br />
|
||||
<p>Wenn du dein Passwort nicht zurückgesetzt hast, kannst du diese Nachricht ignorieren!</p>
|
||||
<br />
|
||||
<p>Mit fleißigen Grüßen,</p>
|
||||
<p>Der Beekeeper</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
37
data/migrations/business/Version20240827155813.php
Normal file
37
data/migrations/business/Version20240827155813.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Bee\Migrations\Bee;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20240827155813 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return "Create Table 'user_password_token'";
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$sql = "CREATE TABLE user_password_token (
|
||||
id binary(16) NOT NULL,
|
||||
user_id binary(16) NOT NULL,
|
||||
updated_at datetime NOT NULL,
|
||||
created_at datetime NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);";
|
||||
|
||||
$this->addSql($sql);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql("DROP TABLE user_password_token;");
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,11 @@
|
||||
<?php
|
||||
|
||||
use Bee\API\External\Authentication\Handler\ConfirmRegistrationHandler;
|
||||
use Bee\API\External\Authentication\Handler\ForgotPasswordHandler;
|
||||
use Bee\API\External\Authentication\Handler\LoginUserHandler;
|
||||
use Bee\API\External\Authentication\Handler\LogoutUserHandler;
|
||||
use Bee\API\External\Authentication\Handler\RegisterUserHandler;
|
||||
use Bee\API\External\Authentication\Handler\ResetPasswordHandler;
|
||||
use Bee\Infrastructure\Session\Middleware\LoggedInUserMiddleware;
|
||||
|
||||
return [
|
||||
@ -40,4 +42,20 @@ return [
|
||||
RegisterUserHandler::class
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'auth.forgot-password',
|
||||
'path' => '/api/auth/forgot-password',
|
||||
'allowed_methods' => ['POST'],
|
||||
'middleware' => [
|
||||
ForgotPasswordHandler::class,
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'auth.reset-password',
|
||||
'path' => '/api/auth/reset-password',
|
||||
'allowed_methods' => ['POST'],
|
||||
'middleware' => [
|
||||
ResetPasswordHandler::class,
|
||||
],
|
||||
],
|
||||
];
|
||||
@ -3,9 +3,13 @@
|
||||
use Bee\API\External\Authentication\Formatter\ConfirmRegistrationFormatter;
|
||||
use Bee\API\External\Authentication\Formatter\LoginUserFormatter;
|
||||
use Bee\API\External\Authentication\Handler\ConfirmRegistrationHandler;
|
||||
use Bee\API\External\Authentication\Handler\ForgotPasswordHandler;
|
||||
use Bee\API\External\Authentication\Handler\LoginUserHandler;
|
||||
use Bee\API\External\Authentication\Handler\LogoutUserHandler;
|
||||
use Bee\API\External\Authentication\Handler\RegisterUserHandler;
|
||||
use Bee\API\External\Authentication\Handler\ResetPasswordHandler;
|
||||
use Bee\API\External\Authentication\ResponseFormatter\ForgotPasswordResponseFormatter;
|
||||
use Bee\API\External\Authentication\ResponseFormatter\ResetPasswordResponseFormatter;
|
||||
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
|
||||
|
||||
return [
|
||||
@ -13,11 +17,15 @@ return [
|
||||
// Formatter
|
||||
ConfirmRegistrationFormatter::class => AutoWiringFactory::class,
|
||||
LoginUserFormatter::class => AutoWiringFactory::class,
|
||||
ForgotPasswordResponseFormatter::class => AutoWiringFactory::class,
|
||||
ResetPasswordResponseFormatter::class => AutoWiringFactory::class,
|
||||
|
||||
// Handler
|
||||
LoginUserHandler::class => AutoWiringFactory::class,
|
||||
LogoutUserHandler::class => AutoWiringFactory::class,
|
||||
ConfirmRegistrationHandler::class => AutoWiringFactory::class,
|
||||
RegisterUserHandler::class => AutoWiringFactory::class
|
||||
RegisterUserHandler::class => AutoWiringFactory::class,
|
||||
ForgotPasswordHandler::class => AutoWiringFactory::class,
|
||||
ResetPasswordHandler::class => AutoWiringFactory::class,
|
||||
],
|
||||
];
|
||||
|
||||
39
src/ApiDomain/External/Authentication/src/Handler/ForgotPasswordHandler.php
vendored
Normal file
39
src/ApiDomain/External/Authentication/src/Handler/ForgotPasswordHandler.php
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Bee\API\External\Authentication\Handler;
|
||||
|
||||
use Bee\API\External\Authentication\ResponseFormatter\ForgotPasswordResponseFormatter;
|
||||
use Bee\Handling\User\Handler\Command\ForgotPassword\ForgotPasswordCommandBuilder;
|
||||
use Bee\Handling\User\Handler\Command\ForgotPassword\ForgotPasswordCommandHandler;
|
||||
use Bee\Infrastructure\Request\Middleware\AnalyzeBodyMiddleware;
|
||||
use Bee\Infrastructure\Request\Middleware\AnalyzeHeaderMiddleware;
|
||||
use Bee\Infrastructure\Response\SuccessResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class ForgotPasswordHandler implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ForgotPasswordCommandHandler $forgotPasswordCommandHandler,
|
||||
private readonly ForgotPasswordCommandBuilder $forgotPasswordCommandBuilder,
|
||||
private readonly ForgotPasswordResponseFormatter $responseFormatter,
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$host = $request->getAttribute(AnalyzeHeaderMiddleware::HOST_ATTRIBUTE);
|
||||
$data = $request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
|
||||
|
||||
$forgotPasswordCommand = $this->forgotPasswordCommandBuilder->build(
|
||||
domain: $host,
|
||||
mail: $data['mail'],
|
||||
);
|
||||
$result = $this->forgotPasswordCommandHandler->execute($forgotPasswordCommand);
|
||||
|
||||
return new SuccessResponse($this->responseFormatter->format($result));
|
||||
}
|
||||
}
|
||||
45
src/ApiDomain/External/Authentication/src/Handler/ResetPasswordHandler.php
vendored
Normal file
45
src/ApiDomain/External/Authentication/src/Handler/ResetPasswordHandler.php
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Bee\API\External\Authentication\Handler;
|
||||
|
||||
use Bee\API\External\Authentication\ResponseFormatter\ResetPasswordResponseFormatter;
|
||||
use Bee\Handling\User\Exception\UserPasswordConfirmationMismatchException;
|
||||
use Bee\Handling\User\Exception\UserPasswordTokenNotFoundByIdException;
|
||||
use Bee\Handling\User\Handler\Command\ResetPassword\ResetPasswordCommandBuilder;
|
||||
use Bee\Handling\User\Handler\Command\ResetPassword\ResetPasswordCommandHandler;
|
||||
use Bee\Infrastructure\Request\Middleware\AnalyzeBodyMiddleware;
|
||||
use Bee\Infrastructure\Response\SuccessResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
|
||||
class ResetPasswordHandler implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ResetPasswordCommandHandler $handler,
|
||||
private readonly ResetPasswordCommandBuilder $builder,
|
||||
private readonly ResetPasswordResponseFormatter $responseFormatter,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UserPasswordConfirmationMismatchException
|
||||
* @throws UserPasswordTokenNotFoundByIdException
|
||||
*/
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$data = $request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
|
||||
|
||||
$resetPasswordCommand = $this->builder->build(
|
||||
Uuid::fromString($data['passwordToken']),
|
||||
$data['newPassword'],
|
||||
$data['passwordConfirmation'],
|
||||
);
|
||||
$result = $this->handler->execute($resetPasswordCommand);
|
||||
|
||||
return new SuccessResponse($this->responseFormatter->format($result));
|
||||
}
|
||||
}
|
||||
17
src/ApiDomain/External/Authentication/src/ResponseFormatter/ForgotPasswordResponseFormatter.php
vendored
Normal file
17
src/ApiDomain/External/Authentication/src/ResponseFormatter/ForgotPasswordResponseFormatter.php
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Bee\API\External\Authentication\ResponseFormatter;
|
||||
|
||||
use Bee\Handling\User\Handler\Command\ForgotPassword\ForgotPasswordCommandResult;
|
||||
|
||||
class ForgotPasswordResponseFormatter
|
||||
{
|
||||
public function format(ForgotPasswordCommandResult $forgotPasswordCommandResult): array
|
||||
{
|
||||
return [
|
||||
|
||||
];
|
||||
}
|
||||
}
|
||||
17
src/ApiDomain/External/Authentication/src/ResponseFormatter/ResetPasswordResponseFormatter.php
vendored
Normal file
17
src/ApiDomain/External/Authentication/src/ResponseFormatter/ResetPasswordResponseFormatter.php
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Bee\API\External\Authentication\ResponseFormatter;
|
||||
|
||||
use Bee\Handling\User\Handler\Command\ResetPassword\ResetPasswordCommandResult;
|
||||
|
||||
class ResetPasswordResponseFormatter
|
||||
{
|
||||
public function format(ResetPasswordCommandResult $resetPasswordCommandResult): array
|
||||
{
|
||||
return [
|
||||
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -32,6 +32,7 @@ class ChangePasswordHandler implements RequestHandlerInterface
|
||||
$user,
|
||||
$data['password'],
|
||||
$data['newPassword'],
|
||||
$data['newPasswordConfirmation'],
|
||||
);
|
||||
$this->handler->execute($query);
|
||||
|
||||
|
||||
@ -14,8 +14,6 @@ return [
|
||||
'doctrine.entity_manager.orm_bee' => [BaseEntityManagerFactory::class, 'orm_bee'],
|
||||
'doctrine.configuration.orm_bee' => [ConfigurationFactory::class, 'orm_bee'],
|
||||
'doctrine.connection.orm_bee' => [ConnectionFactory::class, 'orm_bee'],
|
||||
EntityManager::class => EntityManagerFactory::class,
|
||||
|
||||
UserRepository::class => [AutowireRepositoryFactory::class, EntityManager::class, User::class],
|
||||
EntityManager::class => EntityManagerFactory::class
|
||||
],
|
||||
];
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
namespace Bee\Data\Business\Entity;
|
||||
|
||||
use DateTime;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Bee\Infrastructure\UuidGenerator\UuidGenerator;
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
@ -39,6 +40,9 @@ class User {
|
||||
/** @ORM\OneToOne(targetEntity="Bee\Data\Business\Entity\UserSession", mappedBy="user") */
|
||||
private ?UserSession $session;
|
||||
|
||||
/* @ORM\OneToMany(targetEntity="Bee\Data\Business\Entity\UserPasswordToken", mappedBy="user") */
|
||||
private Collection $passwordTokens;
|
||||
|
||||
/** @ORM\Column(name="last_login_at", type="datetime", nullable=true) */
|
||||
private DateTime $lastLoginAt;
|
||||
|
||||
|
||||
91
src/DataDomain/Business/src/Entity/UserPasswordToken.php
Normal file
91
src/DataDomain/Business/src/Entity/UserPasswordToken.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Bee\Data\Business\Entity;
|
||||
|
||||
use DateTime;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Bee\Infrastructure\UuidGenerator\UuidGenerator;
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass="Bee\Data\Business\Repository\UserPasswordTokenRepository")
|
||||
* @ORM\Table(name="user_password_token")
|
||||
*/
|
||||
class UserPasswordToken {
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(name="id", type="uuid_binary_ordered_time")
|
||||
*/
|
||||
private UuidInterface $id;
|
||||
|
||||
/** @ORM\Column(name="user_id", type="uuid_binary_ordered_time", nullable=false) */
|
||||
private UuidInterface $userId;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Bee\Data\Business\Entity\User", inversedBy="session")
|
||||
* @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=true)
|
||||
*/
|
||||
private User $user;
|
||||
|
||||
/** @ORM\Column(name="created_at", type="datetime") */
|
||||
private DateTime $createdAt;
|
||||
|
||||
/** @ORM\Column(name="updated_at", type="datetime") */
|
||||
private DateTime $updatedAt;
|
||||
|
||||
|
||||
public function __construct() {
|
||||
$this->id = UuidGenerator::generate();
|
||||
|
||||
$now = new DateTime();
|
||||
$this->setCreatedAt($now);
|
||||
$this->setUpdatedAt($now);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ORM\PrePersist
|
||||
* @ORM\PreUpdate
|
||||
*/
|
||||
public function updateTimestamps(): void {
|
||||
$now = new DateTime();
|
||||
$this->setUpdatedAt($now);
|
||||
}
|
||||
|
||||
|
||||
public function getId(): UuidInterface {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getUserId(): UuidInterface {
|
||||
return $this->userId;
|
||||
}
|
||||
|
||||
public function setUserId(UuidInterface $userId): void {
|
||||
$this->userId = $userId;
|
||||
}
|
||||
|
||||
public function getUser(): User {
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
public function setUser(User $user): void {
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): DateTime {
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
public function setCreatedAt(DateTime $createdAt): void {
|
||||
$this->createdAt = $createdAt;
|
||||
}
|
||||
|
||||
public function getUpdatedAt(): DateTime {
|
||||
return $this->updatedAt;
|
||||
}
|
||||
|
||||
public function setUpdatedAt(DateTime $updatedAt): void {
|
||||
$this->updatedAt = $updatedAt;
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,4 @@ namespace Bee\Data\Business\Repository;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
class PermissionRepository extends EntityRepository {
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Bee\Data\Business\Repository;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
class ProductRepository extends EntityRepository {
|
||||
}
|
||||
|
||||
?>
|
||||
@ -6,5 +6,3 @@ use Doctrine\ORM\EntityRepository;
|
||||
|
||||
class RoleRepository extends EntityRepository {
|
||||
}
|
||||
|
||||
?>
|
||||
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Bee\Data\Business\Repository;
|
||||
|
||||
use Bee\Data\Business\Entity\User;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Bee\Data\Business\Entity\UserSession;
|
||||
|
||||
class UserPasswordTokenRepository extends EntityRepository {
|
||||
}
|
||||
@ -22,5 +22,3 @@ class UserRepository extends EntityRepository {
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@ -7,16 +7,4 @@ use Doctrine\ORM\EntityRepository;
|
||||
use Bee\Data\Business\Entity\UserSession;
|
||||
|
||||
class UserSessionRepository extends EntityRepository {
|
||||
public function findByUser(User $user) : ?UserSession {
|
||||
$queryBuilder = $this->createQueryBuilder('us');
|
||||
$queryBuilder
|
||||
->where("us.userId = :userId")
|
||||
->setParameter('userId', $user->getId());
|
||||
|
||||
/** @var ?UserSession $userSession */
|
||||
$userSession = $queryBuilder->getQuery()->execute()[0] ?? null;
|
||||
return $userSession;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
||||
@ -41,6 +41,7 @@ class SendMailStep implements TaskInterface
|
||||
)
|
||||
],
|
||||
recipient: $command->getMail(),
|
||||
sender: 'beekeeper@stack-up.de',
|
||||
senderName: "Beekeeper"
|
||||
);
|
||||
|
||||
|
||||
@ -1,12 +1,17 @@
|
||||
<?php
|
||||
|
||||
use Bee\Handling\User\Builder\UserBuilder;
|
||||
use Bee\Handling\User\Builder\UserPasswordTokenBuilder;
|
||||
use Bee\Handling\User\Handler\Command\ChangePassword\ChangePasswordCommandBuilder;
|
||||
use Bee\Handling\User\Handler\Command\ChangePassword\ChangePasswordCommandHandler;
|
||||
use Bee\Handling\User\Handler\Command\ChangeUsername\ChangeUsernameCommandBuilder;
|
||||
use Bee\Handling\User\Handler\Command\ChangeUsername\ChangeUsernameCommandHandler;
|
||||
use Bee\Handling\User\Handler\Command\CreateUser\CreateUserCommandBuilder;
|
||||
use Bee\Handling\User\Handler\Command\CreateUser\CreateUserCommandHandler;
|
||||
use Bee\Handling\User\Handler\Command\ForgotPassword\ForgotPasswordCommandBuilder;
|
||||
use Bee\Handling\User\Handler\Command\ForgotPassword\ForgotPasswordCommandHandler;
|
||||
use Bee\Handling\User\Handler\Command\ResetPassword\ResetPasswordCommandBuilder;
|
||||
use Bee\Handling\User\Handler\Command\ResetPassword\ResetPasswordCommandHandler;
|
||||
use Bee\Handling\User\Rule\UserPasswordMatchRule;
|
||||
use Bee\Handling\User\Rule\UserWithIdentifierAlreadyExistsRule;
|
||||
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
|
||||
@ -18,6 +23,7 @@ return [
|
||||
|
||||
/// Builder
|
||||
UserBuilder::class => InjectionFactory::class,
|
||||
UserPasswordTokenBuilder::class => AutoWiringFactory::class,
|
||||
|
||||
/// Rule
|
||||
UserWithIdentifierAlreadyExistsRule::class => InjectionFactory::class,
|
||||
@ -27,13 +33,17 @@ return [
|
||||
// Create User
|
||||
CreateUserCommandHandler::class => AutoWiringFactory::class,
|
||||
CreateUserCommandBuilder::class => AutoWiringFactory::class,
|
||||
|
||||
// Change Password
|
||||
ChangePasswordCommandHandler::class => AutoWiringFactory::class,
|
||||
ChangePasswordCommandBuilder::class => AutoWiringFactory::class,
|
||||
|
||||
// Change Username
|
||||
ChangeUsernameCommandHandler::class => AutoWiringFactory::class,
|
||||
ChangeUsernameCommandBuilder::class => AutoWiringFactory::class,
|
||||
// Forgot Password
|
||||
ForgotPasswordCommandHandler::class => InjectionFactory::class,
|
||||
ForgotPasswordCommandBuilder::class => AutoWiringFactory::class,
|
||||
// Reset Password
|
||||
ResetPasswordCommandHandler::class => InjectionFactory::class,
|
||||
ResetPasswordCommandBuilder::class => AutoWiringFactory::class,
|
||||
],
|
||||
];
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Bee\Handling\User\Builder;
|
||||
|
||||
use Bee\Data\Business\Entity\Role;
|
||||
use Bee\Data\Business\Entity\User;
|
||||
use Bee\Data\Business\Entity\UserPasswordToken;
|
||||
use Bee\Data\Business\Repository\RoleRepository;
|
||||
use Bee\Handling\Role\Exception\RoleNotFoundByIdentifierException;
|
||||
use Bee\Infrastructure\Encryption\Client\EncryptionClient;
|
||||
use Reinfi\DependencyInjection\Annotation\Inject;
|
||||
use Reinfi\DependencyInjection\Annotation\InjectDoctrineRepository;
|
||||
|
||||
class UserPasswordTokenBuilder
|
||||
{
|
||||
public function build(
|
||||
User $user
|
||||
): UserPasswordToken
|
||||
{
|
||||
$userPasswordToken = new UserPasswordToken();
|
||||
$userPasswordToken->setUser($user);
|
||||
|
||||
return $userPasswordToken;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Bee\Handling\User\Exception;
|
||||
|
||||
use Bee\Infrastructure\Exception\ErrorCode;
|
||||
use Bee\Infrastructure\Exception\ErrorDomain;
|
||||
use Bee\Infrastructure\Exception\Exception\Exception;
|
||||
|
||||
class UserNotFoundByMailException extends Exception {
|
||||
|
||||
private const MESSAGE = 'The user with the mail %s was not found!';
|
||||
|
||||
public function __construct(string $identifier)
|
||||
{
|
||||
parent::__construct(
|
||||
sprintf(
|
||||
self::MESSAGE,
|
||||
$identifier
|
||||
),
|
||||
ErrorDomain::User,
|
||||
ErrorCode::NotFound
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Bee\Handling\User\Exception;
|
||||
|
||||
use Bee\Infrastructure\Exception\ErrorCode;
|
||||
use Bee\Infrastructure\Exception\ErrorDomain;
|
||||
use Bee\Infrastructure\Exception\Exception\Exception;
|
||||
|
||||
class UserPasswordConfirmationMismatchException extends Exception {
|
||||
|
||||
private const MESSAGE = 'The two passwordConfirmation does not match the newPassword';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(
|
||||
self::MESSAGE,
|
||||
ErrorDomain::UserPassword,
|
||||
ErrorCode::Mismatch,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Bee\Handling\User\Exception;
|
||||
|
||||
use Bee\Infrastructure\Exception\ErrorCode;
|
||||
use Bee\Infrastructure\Exception\ErrorDomain;
|
||||
use Bee\Infrastructure\Exception\Exception\Exception;
|
||||
|
||||
class UserPasswordTokenNotFoundByIdException extends Exception {
|
||||
|
||||
private const MESSAGE = 'User password token with the id %s was not found!';
|
||||
|
||||
public function __construct(
|
||||
string $identification
|
||||
)
|
||||
{
|
||||
parent::__construct(
|
||||
sprintf(
|
||||
self::MESSAGE,
|
||||
$identification
|
||||
),
|
||||
ErrorDomain::UserPassword,
|
||||
ErrorCode::Mismatch,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,7 @@ class ChangePasswordCommand
|
||||
private readonly User $user,
|
||||
private readonly string $password,
|
||||
private readonly string $newPassword,
|
||||
private readonly string $newPasswordConfirmation,
|
||||
) {
|
||||
}
|
||||
|
||||
@ -24,4 +25,9 @@ class ChangePasswordCommand
|
||||
public function getPassword(): string {
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
public function getNewPasswordConfirmation(): string
|
||||
{
|
||||
return $this->newPasswordConfirmation;
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,12 +10,14 @@ class ChangePasswordCommandBuilder
|
||||
User $user,
|
||||
string $password,
|
||||
string $newPassword,
|
||||
string $newPasswordConfirmation,
|
||||
): ChangePasswordCommand
|
||||
{
|
||||
return new ChangePasswordCommand(
|
||||
$user,
|
||||
$password,
|
||||
$newPassword,
|
||||
$newPasswordConfirmation,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ use Bee\Data\Business\Entity\User;
|
||||
use Bee\Data\Business\Repository\RoleRepository;
|
||||
use Bee\Data\Business\Repository\UserRepository;
|
||||
use Bee\Handling\User\Exception\UserNotFoundByIdentifierException;
|
||||
use Bee\Handling\User\Exception\UserPasswordConfirmationMismatchException;
|
||||
use Bee\Handling\User\Exception\UserWrongPasswordException;
|
||||
use Bee\Data\Business\Manager\EntityManager;
|
||||
use Bee\Infrastructure\Encryption\Client\EncryptionClient;
|
||||
@ -20,6 +21,10 @@ class ChangePasswordCommandHandler
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UserWrongPasswordException
|
||||
* @throws UserPasswordConfirmationMismatchException
|
||||
*/
|
||||
public function execute(ChangePasswordCommand $command): void
|
||||
{
|
||||
$user = $command->getUser();
|
||||
@ -28,6 +33,10 @@ class ChangePasswordCommandHandler
|
||||
throw new UserWrongPasswordException();
|
||||
}
|
||||
|
||||
if ($command->getNewPassword() !== $command->getNewPasswordConfirmation()) {
|
||||
throw new UserPasswordConfirmationMismatchException();
|
||||
}
|
||||
|
||||
$encryptedPassword = $this->encryptionClient->encrypt(
|
||||
$command->getNewPassword()
|
||||
);
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Bee\Handling\User\Handler\Command\ForgotPassword;
|
||||
|
||||
class ForgotPasswordCommand
|
||||
{
|
||||
public function __construct(
|
||||
private readonly string $domain,
|
||||
private readonly string $mail
|
||||
) {
|
||||
}
|
||||
|
||||
public function getDomain(): string
|
||||
{
|
||||
return $this->domain;
|
||||
}
|
||||
|
||||
public function getMail(): string
|
||||
{
|
||||
return $this->mail;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Bee\Handling\User\Handler\Command\ForgotPassword;
|
||||
|
||||
class ForgotPasswordCommandBuilder
|
||||
{
|
||||
public function build(
|
||||
string $domain,
|
||||
string $mail
|
||||
): ForgotPasswordCommand {
|
||||
return new ForgotPasswordCommand(
|
||||
$domain,
|
||||
$mail
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Bee\Handling\User\Handler\Command\ForgotPassword;
|
||||
|
||||
use Bee\Data\Business\Entity\User;
|
||||
use Bee\Data\Business\Manager\EntityManager;
|
||||
use Bee\Data\Business\Repository\UserRepository;
|
||||
use Bee\Handling\User\Builder\UserPasswordTokenBuilder;
|
||||
use Bee\Handling\User\Exception\UserNotFoundByMailException;
|
||||
use Bee\Infrastructure\Mail\Service\MailService;
|
||||
use Reinfi\DependencyInjection\Annotation\Inject;
|
||||
use Reinfi\DependencyInjection\Annotation\InjectDoctrineRepository;
|
||||
|
||||
class ForgotPasswordCommandHandler
|
||||
{
|
||||
private const RESET_PASSWORD_LINK = "https://%s/auth/reset-password/%s";
|
||||
|
||||
/**
|
||||
* @InjectDoctrineRepository(
|
||||
* entityManager="Bee\Data\Business\Manager\EntityManager",
|
||||
* entity="Bee\Data\Business\Entity\User"
|
||||
* )
|
||||
* @Inject("Bee\Handling\User\Builder\UserPasswordTokenBuilder")
|
||||
* @Inject("Bee\Infrastructure\Mail\Service\MailService")
|
||||
* @Inject("Bee\Data\Business\Manager\EntityManager")
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly UserRepository $userRepository,
|
||||
private readonly UserPasswordTokenBuilder $passwordTokenBuilder,
|
||||
private readonly MailService $mailService,
|
||||
private readonly EntityManager $entityManager,
|
||||
) {
|
||||
}
|
||||
|
||||
public function execute(ForgotPasswordCommand $forgotPasswordCommand): ForgotPasswordCommandResult
|
||||
{
|
||||
$mail = $forgotPasswordCommand->getMail();
|
||||
|
||||
/** @var User $user */
|
||||
$user = $this->userRepository->findOneBy(['mail' => $mail]);
|
||||
|
||||
if ($user === null) {
|
||||
throw new UserNotFoundByMailException($mail);
|
||||
}
|
||||
|
||||
$passwordToken = $this->passwordTokenBuilder->build($user);
|
||||
|
||||
$this->entityManager->persist($passwordToken);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->mailService->send(
|
||||
'reset-password',
|
||||
templateData: [
|
||||
'username' => $user->getUsername(),
|
||||
'passwordResetLink' => sprintf(
|
||||
self::RESET_PASSWORD_LINK,
|
||||
$forgotPasswordCommand->getDomain(),
|
||||
$passwordToken->getId()->toString()
|
||||
)
|
||||
],
|
||||
recipient: $mail,
|
||||
sender: 'beekeeper@stack-up.de',
|
||||
senderName: 'Beekeeper'
|
||||
);
|
||||
|
||||
return new ForgotPasswordCommandResult();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Bee\Handling\User\Handler\Command\ForgotPassword;
|
||||
|
||||
class ForgotPasswordCommandResult
|
||||
{
|
||||
public function __construct(
|
||||
) {
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Bee\Handling\User\Handler\Command\ResetPassword;
|
||||
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
|
||||
class ResetPasswordCommand
|
||||
{
|
||||
public function __construct(
|
||||
private UuidInterface $passwordTokenUuid,
|
||||
private string $newPassword,
|
||||
private string $passwordConfirmation
|
||||
) {
|
||||
}
|
||||
|
||||
public function getPasswordTokenUuid(): UuidInterface
|
||||
{
|
||||
return $this->passwordTokenUuid;
|
||||
}
|
||||
|
||||
public function getNewPassword(): string
|
||||
{
|
||||
return $this->newPassword;
|
||||
}
|
||||
|
||||
public function getPasswordConfirmation(): string
|
||||
{
|
||||
return $this->passwordConfirmation;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Bee\Handling\User\Handler\Command\ResetPassword;
|
||||
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
|
||||
class ResetPasswordCommandBuilder
|
||||
{
|
||||
public function build(
|
||||
UuidInterface $passwordTokenUuid,
|
||||
string $newPassword,
|
||||
string $passwordConfirmation
|
||||
): ResetPasswordCommand {
|
||||
return new ResetPasswordCommand(
|
||||
$passwordTokenUuid,
|
||||
$newPassword,
|
||||
$passwordConfirmation
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Bee\Handling\User\Handler\Command\ResetPassword;
|
||||
|
||||
use Bee\Data\Business\Entity\UserPasswordToken;
|
||||
use Bee\Data\Business\Manager\EntityManager;
|
||||
use Bee\Data\Business\Repository\UserPasswordTokenRepository;
|
||||
use Bee\Handling\User\Exception\UserPasswordConfirmationMismatchException;
|
||||
use Bee\Handling\User\Exception\UserPasswordTokenNotFoundByIdException;
|
||||
use Bee\Infrastructure\Encryption\Client\EncryptionClient;
|
||||
use Reinfi\DependencyInjection\Annotation\Inject;
|
||||
use Reinfi\DependencyInjection\Annotation\InjectDoctrineRepository;
|
||||
|
||||
class ResetPasswordCommandHandler
|
||||
{
|
||||
/**
|
||||
* @InjectDoctrineRepository(
|
||||
* entityManager="Bee\Data\Business\Manager\EntityManager",
|
||||
* entity="Bee\Data\Business\Entity\UserPasswordToken"
|
||||
* )
|
||||
* @Inject("Bee\Infrastructure\Encryption\Client\EncryptionClient")
|
||||
* @Inject("Bee\Data\Business\Manager\EntityManager")
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly UserPasswordTokenRepository $repository,
|
||||
private readonly EncryptionClient $encryptionClient,
|
||||
private readonly EntityManager $entityManager,
|
||||
) {
|
||||
}
|
||||
|
||||
public function execute(ResetPasswordCommand $resetPasswordCommand): ResetPasswordCommandResult
|
||||
{
|
||||
$passwordTokenId = $resetPasswordCommand->getPasswordTokenUuid();
|
||||
|
||||
// Load and check password token
|
||||
/** @var ?UserPasswordToken $passwordToken */
|
||||
$passwordToken = $this->repository->findOneBy(['id' => $passwordTokenId]);
|
||||
if ($passwordToken === null) {
|
||||
throw new UserPasswordTokenNotFoundByIdException($passwordTokenId->toString());
|
||||
}
|
||||
|
||||
if ($resetPasswordCommand->getNewPassword() !== $resetPasswordCommand->getPasswordConfirmation()) {
|
||||
throw new UserPasswordConfirmationMismatchException();
|
||||
}
|
||||
|
||||
// Update Password
|
||||
$user = $passwordToken->getUser();
|
||||
$user->setPassword($this->encryptionClient->encrypt($resetPasswordCommand->getNewPassword()));
|
||||
|
||||
// Save to DB
|
||||
$this->entityManager->remove($passwordToken);
|
||||
$this->entityManager->persist($user);
|
||||
if ($user->getSession() !== null) {
|
||||
$this->entityManager->remove($user->getSession());
|
||||
}
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
||||
return new ResetPasswordCommandResult();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Bee\Handling\User\Handler\Command\ResetPassword;
|
||||
|
||||
class ResetPasswordCommandResult
|
||||
{
|
||||
public function __construct(
|
||||
#TODO
|
||||
) {
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Bee\Infrastructure\Database;
|
||||
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Roave\PsrContainerDoctrine\AbstractFactory;
|
||||
|
||||
class AutowireRepositoryFactory extends AbstractFactory
|
||||
{
|
||||
protected function createWithConfig(ContainerInterface $container, string $configKey)
|
||||
{
|
||||
/** @var EntityManager $em */
|
||||
$em = $container->get(EntityManager::class);
|
||||
return $em->getRepository($configKey);
|
||||
}
|
||||
|
||||
protected function getDefaultConfig(string $configKey): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Bee\Infrastructure\Database;
|
||||
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use Laminas\ServiceManager\Factory\FactoryInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
class AutowireRepositoryFactory implements FactoryInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly string $entityManagerClass,
|
||||
private readonly string $entityClass,
|
||||
) {
|
||||
var_dump($this->entityClass, $this->entityClass);
|
||||
}
|
||||
|
||||
public function __invoke(
|
||||
ContainerInterface $container,
|
||||
$requestedName,
|
||||
?array $options = null
|
||||
): ObjectRepository|EntityRepository
|
||||
{
|
||||
/** @var EntityManager $em */
|
||||
$em = $container->get($this->entityManagerClass);
|
||||
|
||||
return $em->getRepository($this->entityClass);
|
||||
}
|
||||
}
|
||||
@ -13,6 +13,4 @@ class UuidGenerator {
|
||||
$factory->setCodec($codec);
|
||||
return $factory->uuid1();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
||||
Reference in New Issue
Block a user