default functions

This commit is contained in:
Flo 2024-08-27 20:49:35 +00:00
parent 9237801bc1
commit 6d97fc24c4
40 changed files with 769 additions and 84 deletions

View File

@ -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));
}
@ -275,9 +275,7 @@ class {$cqrsHandlerName}
public function execute({$cqrsName} \${$cqrsVariableName}): {$cqrsResultName}
{
return new {$cqrsResultName}(
);
return new {$cqrsResultName}();
}
}
";

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View 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>

View 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;");
}
}

View File

@ -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,
],
],
];

View File

@ -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,
],
];

View 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));
}
}

View 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));
}
}

View 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 [
];
}
}

View 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 [
];
}
}

View File

@ -32,6 +32,7 @@ class ChangePasswordHandler implements RequestHandlerInterface
$user,
$data['password'],
$data['newPassword'],
$data['newPasswordConfirmation'],
);
$this->handler->execute($query);

View File

@ -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
],
];

View File

@ -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;

View 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;
}
}

View File

@ -6,5 +6,3 @@ use Doctrine\ORM\EntityRepository;
class PermissionRepository extends EntityRepository {
}
?>

View File

@ -1,10 +0,0 @@
<?php
namespace Bee\Data\Business\Repository;
use Doctrine\ORM\EntityRepository;
class ProductRepository extends EntityRepository {
}
?>

View File

@ -6,5 +6,3 @@ use Doctrine\ORM\EntityRepository;
class RoleRepository extends EntityRepository {
}
?>

View File

@ -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 {
}

View File

@ -22,5 +22,3 @@ class UserRepository extends EntityRepository {
return $user;
}
}
?>

View File

@ -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;
}
}
?>

View File

@ -41,6 +41,7 @@ class SendMailStep implements TaskInterface
)
],
recipient: $command->getMail(),
sender: 'beekeeper@stack-up.de',
senderName: "Beekeeper"
);

View File

@ -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,
],
];

View File

@ -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;
}
}

View File

@ -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
);
}
}

View File

@ -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,
);
}
}

View File

@ -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,
);
}
}

View File

@ -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;
}
}

View File

@ -10,12 +10,14 @@ class ChangePasswordCommandBuilder
User $user,
string $password,
string $newPassword,
string $newPasswordConfirmation,
): ChangePasswordCommand
{
return new ChangePasswordCommand(
$user,
$password,
$newPassword,
$newPasswordConfirmation,
);
}
}

View File

@ -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()
);

View File

@ -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;
}
}

View File

@ -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
);
}
}

View File

@ -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();
}
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace Bee\Handling\User\Handler\Command\ForgotPassword;
class ForgotPasswordCommandResult
{
public function __construct(
) {
}
}

View File

@ -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;
}
}

View File

@ -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
);
}
}

View File

@ -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();
}
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Bee\Handling\User\Handler\Command\ResetPassword;
class ResetPasswordCommandResult
{
public function __construct(
#TODO
) {
}
}

View File

@ -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 [];
}
}

View File

@ -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);
}
}

View File

@ -14,5 +14,3 @@ class UuidGenerator {
return $factory->uuid1();
}
}
?>