$participants
- */
- $participants = $this->participantService->findActiveParticipantByEvent($event->id);
-
- $data = [
- 'id' => $event->id,
- 'owner' => $this->userService->findById($event->userId)->name,
- 'title' => $event->title,
- 'description' => $event->description,
- 'eventText' => $event->eventText,
- 'createdAt' => $event->createdAt->format('Y-m-d H:i'),
- 'startedAt' => $event->startedAt->format('Y-m-d H:i'),
- 'duration' => $event->duration,
- 'status' => $event->status,
- 'ratingCompleted' => $event->ratingCompleted,
- ];
-
- if ($user instanceof User) {
- $participantData = [];
- foreach ($participants as $participant) {
- $user = $this->userService->findById($participant->userId);
- $project = $this->projectService->findByParticipantId($participant->id);
- $entry = [
- 'id' => $participant->id,
- 'username' => $user->name,
- 'userUuid' => $user->uuid,
- 'requestedAt' => $participant->requestedAt->format('Y-m-d H:i'),
- 'projectId' => $project?->id,
- 'projectTitle' => $project?->title,
- ];
-
- $participantData[] = $entry;
- }
-
- $data['participants'] = $participantData;
- }
-
- $topic = $this->topicPoolService->findByEventId($event->id);
-
- if ($topic instanceof Topic) {
- $topicData = [
- 'title' => $topic->topic,
- 'description' => $topic->description,
- ];
-
- $data['topic'] = $topicData;
- }
-
- return new JsonResponse($data, HTTP::STATUS_OK);
- }
-}
diff --git a/src/App/Handler/Event/EventListHandler.php b/src/App/Handler/Event/EventListHandler.php
deleted file mode 100644
index a75c54c1..00000000
--- a/src/App/Handler/Event/EventListHandler.php
+++ /dev/null
@@ -1,47 +0,0 @@
-
- Options: ID|OWNER|TITLE|DESCRIPTION|DURATION|STARTEDAT|STATUS',
- in: 'query',
- required: false,
- schema: new OA\Schema(type: 'string'),
- example: 'startedAt',
- )]
- #[OA\QueryParameter(
- name: 'sort',
- description: 'determines the display order of the events
- Options: ASC|DESC',
- in: 'query',
- required: false,
- schema: new OA\Schema(type: 'string'),
- example: 'DESC',
- )]
- #[OA\Response(
- response: HTTP::STATUS_OK,
- description: 'Success',
- content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: EventDto::class)),
- )]
- public function handle(ServerRequestInterface $request): ResponseInterface
- {
- /** @var EventListDto $events */
- $events = $request->getAttribute(EventListDto::class);
-
- return new JsonResponse($events, HTTP::STATUS_OK);
- }
-}
diff --git a/src/App/Handler/Event/EventNameHandler.php b/src/App/Handler/Event/EventNameHandler.php
deleted file mode 100644
index 8730357c..00000000
--- a/src/App/Handler/Event/EventNameHandler.php
+++ /dev/null
@@ -1,27 +0,0 @@
-getAttribute(Event::class);
-
- $data = [
- 'eventId' => $event->id,
- ];
-
- return new JsonResponse($data, HTTP::STATUS_OK);
- }
-}
diff --git a/src/App/Handler/Event/EventParticipantSubscribeHandler.php b/src/App/Handler/Event/EventParticipantSubscribeHandler.php
deleted file mode 100644
index e1da6b66..00000000
--- a/src/App/Handler/Event/EventParticipantSubscribeHandler.php
+++ /dev/null
@@ -1,53 +0,0 @@
-getAttribute('participantCreateStatus');
-
- if (!$participantCreateStatus) {
- return new JsonResponse(
- ['Status' => 'Benutzer konnte der Teilnehmerliste nicht hinzugefügt werden'],
- HTTP::STATUS_METHOD_NOT_ALLOWED
- );
- }
-
- /**
- * @var User $user
- */
- $user = $request->getAttribute(User::AUTHENTICATED_USER);
- $eventId = (int)$request->getAttribute('eventId');
-
- $participant = $this->participantService->findByUserIdAndEventId($user->id, $eventId);
- $project = $this->projectService->findByParticipantId($participant->id);
-
- $participantData = [
- 'id' => $participant->id,
- 'username' => $user->name,
- 'userUuid' => $user->uuid,
- 'requestedAt' => $participant->requestedAt->format('Y-m-d H:i'),
- 'projectId' => $project?->id,
- 'projectTitle' => $project?->title,
- ];
-
- return new JsonResponse($participantData, HTTP::STATUS_OK);
- }
-}
diff --git a/src/App/Handler/Event/EventParticipantUnsubscribeHandler.php b/src/App/Handler/Event/EventParticipantUnsubscribeHandler.php
deleted file mode 100644
index d0747b0c..00000000
--- a/src/App/Handler/Event/EventParticipantUnsubscribeHandler.php
+++ /dev/null
@@ -1,22 +0,0 @@
-getAttribute('participantRemoveStatus');
-
- if (!$participantRemoveStatus) {
- return new JsonResponse(['Status' => 'Benutzer konnte der Teilnehmerliste nicht entfernt werden'], HTTP::STATUS_METHOD_NOT_ALLOWED);
- }
- return new JsonResponse(['Status' => 'OK'], HTTP::STATUS_OK);
- }
-}
diff --git a/src/App/Handler/System/PingHandler.php b/src/App/Handler/PingHandler.php
similarity index 72%
rename from src/App/Handler/System/PingHandler.php
rename to src/App/Handler/PingHandler.php
index 74b9ec0a..be50fa47 100644
--- a/src/App/Handler/System/PingHandler.php
+++ b/src/App/Handler/PingHandler.php
@@ -1,10 +1,12 @@
value,
content: [
new OA\JsonContent(
properties: [
new OA\Property(
property: 'ack',
- description: 'actually time',
- type: 'string'
+ description: 'actually request time',
+ type: DataType::STRING->value,
),
]
),
]
),
- ],
- deprecated: true
+ ]
)]
public function handle(ServerRequestInterface $request): ResponseInterface
{
diff --git a/src/App/Handler/SwaggerUIHandler.php b/src/App/Handler/SwaggerUIHandler.php
new file mode 100644
index 00000000..f114ab17
--- /dev/null
+++ b/src/App/Handler/SwaggerUIHandler.php
@@ -0,0 +1,57 @@
+ []], ['Client-Identification-String' => []], ['refreshToken' => []]]
+)]
+readonly class SwaggerUIHandler implements RequestHandlerInterface
+{
+ public function handle(ServerRequestInterface $request): ResponseInterface
+ {
+ $indexFile = ROOT_DIR . 'public/docs/index.html';
+
+ if (file_exists($indexFile)) {
+ return new HtmlResponse(file_get_contents($indexFile));
+ }
+
+ return new JsonResponse([], HTTP::STATUS_NO_CONTENT);
+ }
+}
diff --git a/src/App/Handler/System/ApiMeHandler.php b/src/App/Handler/System/ApiMeHandler.php
deleted file mode 100644
index 60378705..00000000
--- a/src/App/Handler/System/ApiMeHandler.php
+++ /dev/null
@@ -1,57 +0,0 @@
- []]],
-)]
-readonly class ApiMeHandler implements RequestHandlerInterface
-{
- #[OA\Get(
- path: '/api/user/me',
- summary: 'Returns minimal information for a logged-in user or empty',
- tags: ['User Control'],
- deprecated: true,
- )]
- #[OA\Response(
- response: HTTP::STATUS_OK,
- description: 'Success',
- content: new OA\JsonContent(ref: ApiMeDto::class)
- )]
- #[OA\Response(
- response: HTTP::STATUS_UNAUTHORIZED,
- description: 'Incorrect authorization or expired',
- content: new OA\JsonContent(ref: SimpleMessageDto::class)
- )]
- public function handle(ServerRequestInterface $request): ResponseInterface
- {
- $user = $request->getAttribute(User::AUTHENTICATED_USER);
-
- if (!($user instanceof User)) {
- return new JsonResponse([], HTTP::STATUS_OK);
- }
-
- return new JsonResponse(new ApiMeDto($user), HTTP::STATUS_OK);
- }
-}
diff --git a/src/App/Handler/System/TestMailHandler.php b/src/App/Handler/System/TestMailHandler.php
deleted file mode 100644
index 97ff1d0a..00000000
--- a/src/App/Handler/System/TestMailHandler.php
+++ /dev/null
@@ -1,32 +0,0 @@
-from('hello@example.com')
- ->to('you@example.com')
- ->subject('Time for Symfony Mailer!')
- ->text('Sending emails is fun again!')
- ->html('See Twig integration for better HTML integration!
');
-
- $this->mailer->send($email);
- return new JsonResponse(['message' => 'You have a Mail'], HTTP::STATUS_CREATED);
- }
-}
diff --git a/src/App/Handler/Topic/TopicCreateHandler.php b/src/App/Handler/Topic/TopicCreateHandler.php
deleted file mode 100644
index 012d432e..00000000
--- a/src/App/Handler/Topic/TopicCreateHandler.php
+++ /dev/null
@@ -1,59 +0,0 @@
-getAttribute(Topic::class);
-
- $this->mailService->send($topic);
-
- $topic = new TopicCreateResponseDto($topic);
-
- return new JsonResponse($topic, HTTP::STATUS_CREATED);
- }
-}
diff --git a/src/App/Handler/Topic/TopicListAvailableHandler.php b/src/App/Handler/Topic/TopicListAvailableHandler.php
deleted file mode 100644
index c1ceba35..00000000
--- a/src/App/Handler/Topic/TopicListAvailableHandler.php
+++ /dev/null
@@ -1,38 +0,0 @@
- $data */
- $data = $request->getAttribute(TopicListDto::class);
-
- return new JsonResponse($data, HTTP::STATUS_OK);
- }
-}
diff --git a/src/App/Hydrator/AccountAccessAuthHydrator.php b/src/App/Hydrator/AccountAccessAuthHydrator.php
new file mode 100644
index 00000000..882507c4
--- /dev/null
+++ b/src/App/Hydrator/AccountAccessAuthHydrator.php
@@ -0,0 +1,68 @@
+hydrate($entity);
+ }
+
+ return $collection;
+ }
+
+ public function extract(AccountAccessAuthInterface $object): array
+ {
+ return [
+ 'id' => $object->id,
+ 'accountId' => $object->accountId,
+ 'label' => $object->label,
+ 'refreshToken' => $object->refreshToken,
+ 'userAgent' => $object->userAgent,
+ 'clientIdentHash' => $object->clientIdentHash,
+ 'createdAt' => $object->createdAt->format(DateTimeFormat::DEFAULT->value),
+ ];
+ }
+
+ public function extractCollection(AccountAccessAuthCollectionInterface $collection): array
+ {
+ $data = [];
+
+ foreach ($collection as $entity) {
+ $data[] = $this->extract($entity);
+ }
+
+ return $data;
+ }
+}
diff --git a/src/App/Hydrator/AccountAccessAuthHydratorInterface.php b/src/App/Hydrator/AccountAccessAuthHydratorInterface.php
new file mode 100644
index 00000000..1b16b3f7
--- /dev/null
+++ b/src/App/Hydrator/AccountAccessAuthHydratorInterface.php
@@ -0,0 +1,14 @@
+uuid->fromString($data['token']),
+ createdAt: new DateTimeImmutable($data['createdAt']),
+ );
+ }
+
+ public function hydrateCollection(array $data): AccountActivationCollectionInterface
+ {
+ $collection = new AccountActivationCollection();
+
+ foreach ($data as $entity) {
+ $collection[] = $this->hydrate($entity);
+ }
+
+ return $collection;
+ }
+
+ public function extract(AccountActivationInterface $object): array
+ {
+ return [
+ 'id' => $object->id,
+ 'email' => $object->email->toString(),
+ 'token' => $object->token->getHex(),
+ 'createdAt' => $object->createdAt->format(DateTimeFormat::DEFAULT->value),
+ ];
+ }
+
+ public function extractCollection(AccountActivationCollectionInterface $collection): array
+ {
+ $data = [];
+
+ foreach ($collection as $entity) {
+ $data[] = $this->extract($entity);
+ }
+
+ return $data;
+ }
+}
diff --git a/src/App/Hydrator/AccountActivationHydratorInterface.php b/src/App/Hydrator/AccountActivationHydratorInterface.php
new file mode 100644
index 00000000..aad28f48
--- /dev/null
+++ b/src/App/Hydrator/AccountActivationHydratorInterface.php
@@ -0,0 +1,14 @@
+uuid->fromString($data['uuid']),
+ name: $data['name'],
+ password: $data['password'],
+ email: new Email($data['email']),
+ registeredAt: new DateTimeImmutable($data['registeredAt']),
+ lastActionAt: new DateTimeImmutable($data['lastActionAt']),
+ );
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function hydrateCollection(array $data): AccountCollectionInterface
+ {
+ $collection = new AccountCollection();
+
+ foreach ($data as $entity) {
+ $collection[] = $this->hydrate($entity);
+ }
+
+ return $collection;
+ }
+
+ public function extract(AccountInterface $object): array
+ {
+ return [
+ 'id' => $object->id,
+ 'uuid' => $object->uuid->getHex()->toString(),
+ 'name' => $object->name,
+ 'password' => $object->password,
+ 'email' => $object->email->toString(),
+ 'registeredAt' => $object->registeredAt->format(DateTimeFormat::DEFAULT->value),
+ 'lastActionAt' => $object->lastActionAt->format(DateTimeFormat::DEFAULT->value),
+ ];
+ }
+
+ public function extractCollection(AccountCollectionInterface $collection): array
+ {
+ $data = [];
+
+ foreach ($collection as $entity) {
+ $data[] = $this->extract($entity);
+ }
+
+ return $data;
+ }
+}
diff --git a/src/App/Hydrator/AccountHydratorInterface.php b/src/App/Hydrator/AccountHydratorInterface.php
new file mode 100644
index 00000000..3379238b
--- /dev/null
+++ b/src/App/Hydrator/AccountHydratorInterface.php
@@ -0,0 +1,14 @@
+uuid->fromString($data['token']),
+ createdAt: new DateTimeImmutable($data['createdAt']),
+ );
+ }
+
+ public function hydrateCollection(array $data): TokenCollectionInterface
+ {
+ $collection = new TokenCollection();
+
+ foreach ($data as $entity) {
+ $collection[] = $this->hydrate($entity);
+ }
+
+ return $collection;
+ }
+
+ public function extract(TokenInterface $object): array
+ {
+ return [
+ 'id' => $object->id,
+ 'accountId' => $object->accountId,
+ 'tokenType' => $object->tokenType->value,
+ 'token' => $object->token->getHex(),
+ 'createdAt' => $object->createdAt->format(DateTimeFormat::DEFAULT->value),
+ ];
+ }
+
+ public function extractCollection(TokenCollectionInterface $collection): array
+ {
+ $data = [];
+
+ foreach ($collection as $entity) {
+ $data[] = $this->extract($entity);
+ }
+
+ return $data;
+ }
+}
diff --git a/src/App/Hydrator/TokenHydratorInterface.php b/src/App/Hydrator/TokenHydratorInterface.php
new file mode 100644
index 00000000..c1ac0358
--- /dev/null
+++ b/src/App/Hydrator/TokenHydratorInterface.php
@@ -0,0 +1,14 @@
+getAttribute('token');
+
+ /** @var AccountRegistration $accountData */
+ $accountData = $request->getAttribute(AccountRegistration::class);
+
+ if ($activationToken === null) {
+ throw new HttpInvalidArgumentException(
+ LogMessage::ACTIVATION_TOKEN_MISSING,
+ StatusMessage::TOKEN_INVALID,
+ [
+ 'Token:' => $activationToken,
+ ]
+ );
+ }
+
+ /** @var null|AccountActivationInterface $persistActivationToken */
+ $persistActivationToken = $this->accountActivationRepository->findByToken($activationToken);
+
+ if ($persistActivationToken === null) {
+ throw new HttpInvalidArgumentException(
+ LogMessage::ACTIVATION_TOKEN_MISSING,
+ StatusMessage::TOKEN_INVALID,
+ [
+ 'Invalid activation token:' => $activationToken,
+ ]
+ );
+ }
+
+ $account = new Account(
+ id: null,
+ uuid: $this->uuid->uuid7(),
+ name: $accountData->accountName,
+ password: password_hash($accountData->password, PASSWORD_BCRYPT),
+ email: $persistActivationToken->email,
+ registeredAt: new DateTimeImmutable(),
+ lastActionAt: new DateTimeImmutable()
+ );
+
+ try {
+ $this->accountRepository->insert($account);
+ } catch (DuplicateEntryException $e) {
+ throw new HttpDuplicateEntryException(
+ LogMessage::ACCOUNT_ALREADY_EXISTS,
+ StatusMessage::INVALID_DATA,
+ [
+ 'E-Mail' => $account->email->toString(),
+ 'Exception Message:' => $e->getMessage(),
+ ]
+ );
+ }
+
+ $this->accountActivationRepository->deleteById($persistActivationToken->id);
+
+ return $handler->handle($request);
+ }
+}
diff --git a/src/App/Middleware/Account/LastAktivityUpdaterMiddleware.php b/src/App/Middleware/Account/LastAktivityUpdaterMiddleware.php
new file mode 100644
index 00000000..9a533b97
--- /dev/null
+++ b/src/App/Middleware/Account/LastAktivityUpdaterMiddleware.php
@@ -0,0 +1,35 @@
+getAttribute(AccountInterface::AUTHENTICATED);
+
+ if (!($account instanceof AccountInterface)) {
+ return $handler->handle($request);
+ }
+
+ $account = $account->with(lastActionAt: new DateTimeImmutable());
+
+ $this->accountRepository->update($account);
+
+ return $handler->handle($request->withAttribute(AccountInterface::AUTHENTICATED, $account));
+ }
+}
diff --git a/src/App/Middleware/Account/LoginAuthentication/AuthenticationConditionsMiddleware.php b/src/App/Middleware/Account/LoginAuthentication/AuthenticationConditionsMiddleware.php
new file mode 100644
index 00000000..c804b372
--- /dev/null
+++ b/src/App/Middleware/Account/LoginAuthentication/AuthenticationConditionsMiddleware.php
@@ -0,0 +1,30 @@
+hasHeader('Authentication') || $request->hasHeader('Authorization')) {
+ throw new HttpUnauthorizedException(
+ LogMessage::LOGIN_DENIED_AUTH_HEADER_ALREADY_PRESENT,
+ StatusMessage::ACCOUNT_ALREADY_AUTHENTICATED,
+ [
+ 'uri' => (string)$request->getUri(),
+ 'ip' => $request->getServerParams()['REMOTE_ADDR'] ?? 'unknown',
+ ]
+ );
+ }
+
+ return $handler->handle($request);
+ }
+}
diff --git a/src/App/Middleware/Account/LoginAuthentication/AuthenticationMiddleware.php b/src/App/Middleware/Account/LoginAuthentication/AuthenticationMiddleware.php
new file mode 100644
index 00000000..bfc41663
--- /dev/null
+++ b/src/App/Middleware/Account/LoginAuthentication/AuthenticationMiddleware.php
@@ -0,0 +1,72 @@
+getParsedBody();
+
+ if (!array_key_exists('email', $data)) {
+ throw new HttpUnauthorizedException(
+ LogMessage::REQUIRED_EMAIL_MISSING,
+ StatusMessage::INVALID_DATA
+ );
+ }
+
+ $email = new Email($data['email']);
+
+ $account = $this->accountRepository->findByEmail($email);
+
+ if (!($account instanceof AccountInterface)) {
+ throw new HttpUnauthorizedException(
+ LogMessage::ACCOUNT_NOT_FOUND,
+ StatusMessage::INVALID_DATA,
+ [
+ 'E-Mail:' => $email->toString(),
+ ],
+ Level::Warning
+ );
+ }
+
+ if (!$this->service->isPasswordMatch($data['password'], $account->password)) {
+ throw new HttpUnauthorizedException(
+ LogMessage::PASSWORD_INCORRECT,
+ StatusMessage::INVALID_DATA,
+ [
+ 'E-Mail:' => $email->toString(),
+ ],
+ Level::Warning
+ );
+ }
+
+ $account = $account->with(lastActionAt: new DateTimeImmutable());
+
+ $this->accountRepository->update($account);
+
+ return $handler->handle($request->withAttribute(AccountInterface::AUTHENTICATED, $account));
+ }
+}
diff --git a/src/App/Middleware/Account/LoginAuthentication/AuthenticationValidationMiddleware.php b/src/App/Middleware/Account/LoginAuthentication/AuthenticationValidationMiddleware.php
new file mode 100644
index 00000000..9291538e
--- /dev/null
+++ b/src/App/Middleware/Account/LoginAuthentication/AuthenticationValidationMiddleware.php
@@ -0,0 +1,40 @@
+getParsedBody();
+
+ $this->validator->setData($data);
+
+ if (!$this->validator->isValid()) {
+ throw new HttpUnauthorizedException(
+ LogMessage::EMAIL_INVALID,
+ StatusMessage::INVALID_DATA,
+ [
+ 'E-Mail:' => $data['email'] ?? null,
+ 'Validator-Message:' => $this->validator->getMessages(),
+ ]
+ );
+ }
+
+ return $handler->handle($request->withParsedBody($this->validator->getValues()));
+ }
+}
diff --git a/src/App/Middleware/Account/LoginAuthentication/PersistAuthenticationMiddleware.php b/src/App/Middleware/Account/LoginAuthentication/PersistAuthenticationMiddleware.php
new file mode 100644
index 00000000..25155700
--- /dev/null
+++ b/src/App/Middleware/Account/LoginAuthentication/PersistAuthenticationMiddleware.php
@@ -0,0 +1,79 @@
+getAttribute(AccountInterface::AUTHENTICATED);
+
+ /** @var ClientIdentification $clientIdent */
+ $clientIdent = $request->getAttribute(ClientIdentification::class);
+
+ /** @var RefreshToken $refreshToken */
+ $refreshToken = $request->getAttribute(RefreshToken::class);
+
+ // @phpstan-ignore-next-line
+ if ($account === null || $clientIdent === null || $refreshToken === null) {
+ throw new HttpUnauthorizedException(
+ LogMessage::AUTHENTICATION_PERSISTENCE_ERROR,
+ StatusMessage::INVALID_DATA,
+ [
+ // @phpstan-ignore-next-line
+ 'Account:' => $account?->email,
+ // @phpstan-ignore-next-line
+ 'Client ID:' => $clientIdent?->identificationHash,
+ 'Refresh Token:' => $refreshToken ? 'placed' : null,
+ ]
+ );
+ }
+
+ $accountAccessAuth = new AccountAccessAuth(
+ 1,
+ $account->id,
+ 'default',
+ $refreshToken->refreshToken,
+ $clientIdent->clientIdentificationData->userAgent,
+ $clientIdent->identificationHash,
+ new DateTimeImmutable()
+ );
+ try {
+ $this->repository->insert($accountAccessAuth);
+ } catch (DuplicateEntryException $e) {
+ throw new HttpDuplicateEntryException(
+ LogMessage::DUPLICATE_SOURCE_LOGIN,
+ StatusMessage::INVALID_DATA,
+ [
+ 'Account' => $account->name,
+ 'ClientID' => $clientIdent->identificationHash,
+ 'ErrorMessage' => $e->getMessage(),
+ ],
+ );
+ }
+
+ return $handler->handle($request);
+ }
+}
diff --git a/src/App/Middleware/Account/LogoutMiddleware.php b/src/App/Middleware/Account/LogoutMiddleware.php
new file mode 100644
index 00000000..ad9d9d46
--- /dev/null
+++ b/src/App/Middleware/Account/LogoutMiddleware.php
@@ -0,0 +1,63 @@
+getAttribute(AccountInterface::AUTHENTICATED);
+
+ if (!($account instanceof AccountInterface)) {
+ throw new HttpUnauthorizedException(
+ LogMessage::LOGOUT_REQUIRES_AUTHENTICATION,
+ StatusMessage::UNAUTHORIZED_ACCESS,
+ [],
+ Level::Warning
+ );
+ }
+
+ /** @var ClientIdentification $clientId */
+ $clientId = $request->getAttribute(ClientIdentification::class);
+
+ $accountAccessAuth = $this->authRepository->findByAccountIdAndClientIdHash(
+ $account->id,
+ $clientId->identificationHash
+ );
+
+ if (!($accountAccessAuth instanceof AccountAccessAuthInterface)) {
+ throw new HttpUnauthorizedException(
+ LogMessage::LOGOUT_CLIENT_IDENTITY_MISMATCH,
+ StatusMessage::UNAUTHORIZED_ACCESS,
+ [
+ 'accountId' => $account->id,
+ 'clientIdentificationHash' => $clientId->identificationHash,
+ ],
+ Level::Warning
+ );
+ }
+
+ $this->authRepository->deleteById($accountAccessAuth->id);
+
+ return $handler->handle($request);
+ }
+}
diff --git a/src/App/Middleware/Account/PasswordChangeMiddleware.php b/src/App/Middleware/Account/PasswordChangeMiddleware.php
new file mode 100644
index 00000000..31013d8d
--- /dev/null
+++ b/src/App/Middleware/Account/PasswordChangeMiddleware.php
@@ -0,0 +1,68 @@
+getAttribute('token');
+ $password = $request->getParsedBody()['password'];
+
+ if ($token === null) {
+ return $this->errorResponse(LogMessage::PASSWORD_CHANGE_TOKEN_MISSING, $token);
+ }
+
+ $persistedToken = $this->tokenRepository->findByToken($token);
+
+ if (!($persistedToken instanceof TokenInterface) || $persistedToken->tokenType !== TokenType::EMail) {
+ return $this->errorResponse(LogMessage::PASSWORD_CHANGE_TOKEN_INVALID, $token);
+ }
+
+ $account = $this->accountRepository->findById($persistedToken->accountId);
+
+ if (!($account instanceof Account)) {
+ return $this->errorResponse(LogMessage::PASSWORD_CHANGE_TOKEN_ACCOUNT_NOT_FOUND, $token);
+ }
+
+ $hashedPassword = $this->accountService->cryptPassword($password);
+ $account = $account->with(password: $hashedPassword);
+
+ $this->accountRepository->update($account);
+ $this->tokenRepository->deleteById($persistedToken->id);
+
+ return $handler->handle($request);
+ }
+
+ private function errorResponse(LogMessage $logMessage, ?string $token): ResponseInterface
+ {
+ throw new HttpInvalidArgumentException(
+ $logMessage,
+ StatusMessage::TOKEN_INVALID,
+ [
+ 'Token:' => $token,
+ ]
+ );
+ }
+}
diff --git a/src/App/Middleware/Account/PasswordForgottenMiddleware.php b/src/App/Middleware/Account/PasswordForgottenMiddleware.php
new file mode 100644
index 00000000..f72db6be
--- /dev/null
+++ b/src/App/Middleware/Account/PasswordForgottenMiddleware.php
@@ -0,0 +1,42 @@
+getAttribute(Email::class);
+
+ if (!$this->accountService->isEmailAvailable($email)) {
+ $this->accountService->sendTokenForPasswordChange($email);
+ return $handler->handle($request);
+ }
+
+ throw new HttpHandledInvalidArgumentAsSuccessException(
+ LogMessage::PASSWORD_REQUEST_MISSING_ACCOUNT,
+ StatusMessage::INVALID_DATA,
+ [
+ 'email:' => $email->toString(),
+ ],
+ Level::Alert
+ );
+ }
+}
diff --git a/src/App/Middleware/Account/RegisterMiddleware.php b/src/App/Middleware/Account/RegisterMiddleware.php
new file mode 100644
index 00000000..3a9e16b9
--- /dev/null
+++ b/src/App/Middleware/Account/RegisterMiddleware.php
@@ -0,0 +1,58 @@
+getAttribute(Email::class);
+
+ if (!$this->accountService->isEmailAvailable($email)) {
+ $this->logger->warning(LogMessage::ACCOUNT_ALREADY_EXISTS->value, [
+ 'email:' => $email->toString(),
+ ]);
+
+ $this->accountService->sendTokenForPasswordChange($email);
+
+ return $handler->handle($request);
+ }
+
+ $activation = new AccountActivation(
+ id: null,
+ email: $email,
+ token: $this->uuid->uuid7(),
+ createdAt: new DateTimeImmutable()
+ );
+
+ $this->accountActivationRepository->insert($activation);
+
+ $this->activationTokenService->sendEmail($activation);
+
+ return $handler->handle($request);
+ }
+}
diff --git a/src/App/Middleware/Account/RequestAuthenticationMiddleware.php b/src/App/Middleware/Account/RequestAuthenticationMiddleware.php
new file mode 100644
index 00000000..6330b90f
--- /dev/null
+++ b/src/App/Middleware/Account/RequestAuthenticationMiddleware.php
@@ -0,0 +1,76 @@
+getHeaderLine('Authorization');
+
+ if (strlen($authorization) === 0) {
+ $this->logger->info('Guest call', [
+ 'uri' => (string)$request->getUri(),
+ ]);
+
+ return $handler->handle($request);
+ }
+
+ if (!$this->accessTokenService->isValid($authorization)) {
+ throw new HttpUnauthorizedException(
+ LogMessage::ACCESS_TOKEN_EXPIRED,
+ StatusMessage::TOKEN_EXPIRED,
+ [
+ 'uri' => (string)$request->getUri(),
+ 'ip' => $request->getServerParams()['REMOTE_ADDR'] ?? 'unknown',
+ ]
+ );
+ }
+
+ $authorization = $this->accessTokenService->decode($authorization);
+ $uuid = $this->uuid->fromString($authorization->uuid);
+ $account = $this->accountRepository->findByUuid($uuid);
+ if (!($account instanceof AccountInterface)) {
+ throw new HttpUnauthorizedException(
+ LogMessage::ACCESS_TOKEN_ACCOUNT_NOT_FOUND,
+ StatusMessage::TOKEN_INVALID,
+ [
+ 'uri' => (string)$request->getUri(),
+ 'uuid' => $authorization->uuid,
+ ],
+ Level::Warning
+ );
+ }
+
+ $this->logger->info('Authenticated user call.', [
+ 'Account' => $account->name,
+ 'uri' => (string)$request->getUri(),
+ ]);
+
+ return $handler->handle($request->withAttribute(AccountInterface::AUTHENTICATED, $account));
+ }
+}
diff --git a/src/App/Middleware/Account/Validation/ActivationInputValidatorMiddleware.php b/src/App/Middleware/Account/Validation/ActivationInputValidatorMiddleware.php
new file mode 100644
index 00000000..7c87bcd2
--- /dev/null
+++ b/src/App/Middleware/Account/Validation/ActivationInputValidatorMiddleware.php
@@ -0,0 +1,45 @@
+getParsedBody();
+
+ $this->validator->setData($data);
+
+ if (!$this->validator->isValid()) {
+ throw new HttpInvalidArgumentException(
+ LogMessage::ACCOUNT_NAME_INVALID,
+ StatusMessage::INVALID_DATA,
+ [
+ 'Account Name:' => $data['accountName'] ?? null,
+ 'Validator-Message:' => $this->validator->getMessages(),
+ ]
+ );
+ }
+
+ $data = $this->validator->getValues();
+
+ $response = AccountRegistration::fromString($data['accountName'], $data['password']);
+
+ return $handler->handle($request->withAttribute(AccountRegistration::class, $response));
+ }
+}
diff --git a/src/App/Middleware/Account/Validation/EmailInputValidatorMiddleware.php b/src/App/Middleware/Account/Validation/EmailInputValidatorMiddleware.php
new file mode 100644
index 00000000..0913cf04
--- /dev/null
+++ b/src/App/Middleware/Account/Validation/EmailInputValidatorMiddleware.php
@@ -0,0 +1,47 @@
+getParsedBody();
+
+ $this->mailValidator->setData($data);
+
+ if (!$this->mailValidator->isValid()) {
+ throw new HttpInvalidArgumentException(
+ LogMessage::EMAIL_INVALID,
+ StatusMessage::INVALID_DATA,
+ [
+ 'E-Mail:' => $data['email'] ?? null,
+ 'Validator Message:' => $this->mailValidator->getMessages(),
+ ]
+ );
+ }
+
+ $email = new Email($data['email']);
+
+ return $handler->handle($request->withAttribute(Email::class, $email));
+ }
+}
diff --git a/src/App/Middleware/Account/Validation/PasswordInputValidatorMiddleware.php b/src/App/Middleware/Account/Validation/PasswordInputValidatorMiddleware.php
new file mode 100644
index 00000000..8cea3ba0
--- /dev/null
+++ b/src/App/Middleware/Account/Validation/PasswordInputValidatorMiddleware.php
@@ -0,0 +1,39 @@
+getParsedBody();
+
+ $this->validator->setData($data);
+
+ if (!$this->validator->isValid()) {
+ throw new HttpInvalidArgumentException(
+ LogMessage::PASSWORD_INVALID,
+ StatusMessage::INVALID_DATA,
+ [
+ 'Validator Message:' => $this->validator->getMessages(),
+ ]
+ );
+ }
+
+ return $handler->handle($request);
+ }
+}
diff --git a/src/App/Middleware/ClientIdentification/ClientIdentificationMiddleware.php b/src/App/Middleware/ClientIdentification/ClientIdentificationMiddleware.php
new file mode 100644
index 00000000..a251414a
--- /dev/null
+++ b/src/App/Middleware/ClientIdentification/ClientIdentificationMiddleware.php
@@ -0,0 +1,31 @@
+getHeaderLine('x-ident');
+ $userAgent = $request->getHeaderLine('user-agent');
+
+ $clientIdentificationData = ClientIdentificationData::create($clientIdent, $userAgent);
+ $identificationHash = $this->clientIdentification->getClientIdentificationHash($clientIdentificationData);
+ $clientIdentification = ClientIdentification::create($clientIdentificationData, $identificationHash);
+
+ return $handler->handle($request->withAttribute(ClientIdentification::class, $clientIdentification));
+ }
+}
diff --git a/src/App/Middleware/Event/EventCreateMiddleware.php b/src/App/Middleware/Event/EventCreateMiddleware.php
deleted file mode 100644
index a5bfb842..00000000
--- a/src/App/Middleware/Event/EventCreateMiddleware.php
+++ /dev/null
@@ -1,44 +0,0 @@
-getAttribute(User::AUTHENTICATED_USER);
-
- $data = $request->getParsedBody();
- $data['userId'] = $user->id;
-
- $event = $this->hydrator->hydrate($data, Event::class);
-
- if (!$this->eventService->create($event)) {
- return new JsonResponse([
- 'message' => 'Event already exists',
- ], HTTP::STATUS_NOT_FOUND);
- }
-
- return $handler->handle($request);
- }
-}
diff --git a/src/App/Middleware/Event/EventCreateMiddlewareFactory.php b/src/App/Middleware/Event/EventCreateMiddlewareFactory.php
deleted file mode 100644
index 96d8247a..00000000
--- a/src/App/Middleware/Event/EventCreateMiddlewareFactory.php
+++ /dev/null
@@ -1,42 +0,0 @@
-get(EventService::class);
-
- /** @var ReflectionHydrator $hydrator */
- $hydrator = clone $container->get(ReflectionHydrator::class);
-
- /** @var DateTimeFormatterStrategy $strategy */
- $strategy = $container->get(DateTimeFormatterStrategy::class);
-
- $hydrator->addStrategy(
- 'createdAt',
- $strategy,
- );
-
- $hydrator->addStrategy(
- 'startedAt',
- $strategy,
- );
-
- $hydrator->addStrategy(
- 'event',
- new HydratorStrategy($container->get(ReflectionHydrator::class), Event::class)
- );
-
- return new EventCreateMiddleware($service, $hydrator);
- }
-}
diff --git a/src/App/Middleware/Event/EventCreateValidationMiddleware.php b/src/App/Middleware/Event/EventCreateValidationMiddleware.php
deleted file mode 100644
index 3d136eb6..00000000
--- a/src/App/Middleware/Event/EventCreateValidationMiddleware.php
+++ /dev/null
@@ -1,35 +0,0 @@
-getParsedBody();
-
- $this->validator->setData($data);
-
- if (!$this->validator->isValid()) {
- return new JsonResponse([
- 'message' => 'Validation fault',
- 'data' => $this->validator->getMessages(),
- ], HTTP::STATUS_NOT_FOUND);
- }
-
- return $handler->handle($request->withParsedBody($this->validator->getValues()));
- }
-}
diff --git a/src/App/Middleware/Event/EventListMiddleware.php b/src/App/Middleware/Event/EventListMiddleware.php
deleted file mode 100644
index 466b77fb..00000000
--- a/src/App/Middleware/Event/EventListMiddleware.php
+++ /dev/null
@@ -1,67 +0,0 @@
-getQueryParams();
-
- $sort = match (strtoupper($params['sort'] ?? '')) {
- 'ASC' => 'ASC',
- default => 'DESC',
- };
-
- $order = match (strtoupper($params['order'] ?? '')) {
- 'ID' => 'id',
- 'OWNER' => 'owner',
- 'TITLE' => 'title',
- 'DESCRIPTION' => 'description',
- 'DURATION' => 'duration',
- 'STATUS' => 'status',
- default => 'startedAt',
- };
-
- /** @var array $events */
- $events = $this->eventService->findAll($order, $sort);
-
- $eventList = [];
-
- foreach ($events as $event) {
- $entry = new EventDto(
- $event->id,
- $this->userService->findById($event->userId)->name,
- $event->title,
- $event->description,
- $event->duration,
- $event->createdAt->format('Y-m-d H:i'),
- $event->status,
- );
-
- $eventList[] = $entry;
- }
-
- $eventList = new EventListDto($eventList);
-
- return $handler->handle($request->withAttribute(EventListDto::class, $eventList));
- }
-}
diff --git a/src/App/Middleware/Event/EventMiddleware.php b/src/App/Middleware/Event/EventMiddleware.php
deleted file mode 100644
index 4dfc01ef..00000000
--- a/src/App/Middleware/Event/EventMiddleware.php
+++ /dev/null
@@ -1,27 +0,0 @@
-getAttribute('eventId');
-
- $event = $this->eventService->findById($eventId);
-
- return $handler->handle($request->withAttribute(Event::class, $event));
- }
-}
diff --git a/src/App/Middleware/Event/EventNameMiddleware.php b/src/App/Middleware/Event/EventNameMiddleware.php
deleted file mode 100644
index a9d3258c..00000000
--- a/src/App/Middleware/Event/EventNameMiddleware.php
+++ /dev/null
@@ -1,32 +0,0 @@
-getAttribute('eventName');
-
- $event = $this->eventService->findByTitle($eventName);
-
- if (!$event instanceof Event) {
- throw new InvalidArgumentException('Could not find Event', 400);
- }
-
- return $handler->handle($request->withAttribute(Event::class, $event));
- }
-}
diff --git a/src/App/Middleware/Event/EventParticipantSubscribeMiddleware.php b/src/App/Middleware/Event/EventParticipantSubscribeMiddleware.php
deleted file mode 100644
index 0d76d5a2..00000000
--- a/src/App/Middleware/Event/EventParticipantSubscribeMiddleware.php
+++ /dev/null
@@ -1,50 +0,0 @@
-getAttribute('eventId');
- $event = $this->eventService->findById($eventId);
-
- if ($event->status->value >= EventStatus::RUNNING->value) {
- return $handler->handle($request->withAttribute('participantCreateStatus', false));
- }
-
- /**
- * @var User $user
- */
- $user = $request->getAttribute(User::AUTHENTICATED_USER);
-
- $participant = new Participant(
- 1,
- $user->id,
- $eventId,
- new DateTimeImmutable(),
- true,
- false
- );
- $participantCreateStatus = $this->participantService->create($participant);
-
- return $handler->handle($request->withAttribute('participantCreateStatus', $participantCreateStatus));
- }
-}
diff --git a/src/App/Middleware/Event/EventParticipantUnsubscribeMiddleware.php b/src/App/Middleware/Event/EventParticipantUnsubscribeMiddleware.php
deleted file mode 100644
index 6072ffb4..00000000
--- a/src/App/Middleware/Event/EventParticipantUnsubscribeMiddleware.php
+++ /dev/null
@@ -1,42 +0,0 @@
-getAttribute(User::AUTHENTICATED_USER);
- $eventId = (int)$request->getAttribute('eventId');
-
- $event = $this->eventService->findById($eventId);
-
- if ($event->status->value >= EventStatus::RUNNING->value) {
- return $handler->handle($request->withAttribute('participantRemoveStatus', false));
- }
-
- $participant = $this->participantService->findByUserIdAndEventId($user->id, $eventId);
-
- $participantRemoveStatus = $this->participantService->remove($participant);
-
- return $handler->handle($request->withAttribute('participantRemoveStatus', $participantRemoveStatus));
- }
-}
diff --git a/src/App/Middleware/Project/ProjectMiddleware.php b/src/App/Middleware/Project/ProjectMiddleware.php
deleted file mode 100644
index 39bddb68..00000000
--- a/src/App/Middleware/Project/ProjectMiddleware.php
+++ /dev/null
@@ -1,27 +0,0 @@
-getAttribute('projectId');
-
- $project = $this->projectService->findById($projectId);
-
- return $handler->handle($request->withAttribute(Project::class, $project));
- }
-}
diff --git a/src/App/Middleware/Project/ProjectOwnerMiddleware.php b/src/App/Middleware/Project/ProjectOwnerMiddleware.php
deleted file mode 100644
index 16779bb4..00000000
--- a/src/App/Middleware/Project/ProjectOwnerMiddleware.php
+++ /dev/null
@@ -1,30 +0,0 @@
-getAttribute(Participant::class);
-
- $projectOwner = $this->userService->findById($participant->userId);
-
- return $handler->handle($request->withAttribute('projectOwner', $projectOwner));
- }
-}
diff --git a/src/App/Middleware/Project/ProjectParticipantMiddleware.php b/src/App/Middleware/Project/ProjectParticipantMiddleware.php
deleted file mode 100644
index 9182cd33..00000000
--- a/src/App/Middleware/Project/ProjectParticipantMiddleware.php
+++ /dev/null
@@ -1,31 +0,0 @@
-getAttribute(Project::class);
-
- $participant = $this->participantService->findById($project->participantId);
-
- return $handler->handle($request->withAttribute(Participant::class, $participant));
- }
-}
diff --git a/src/App/Middleware/Token/AccessTokenValidationMiddleware.php b/src/App/Middleware/Token/AccessTokenValidationMiddleware.php
new file mode 100644
index 00000000..747eb58d
--- /dev/null
+++ b/src/App/Middleware/Token/AccessTokenValidationMiddleware.php
@@ -0,0 +1,47 @@
+getHeaderLine('Authorization');
+
+ if (empty($accessToken)) {
+ throw new HttpUnauthorizedException(
+ LogMessage::ACCESS_TOKEN_MISSING,
+ StatusMessage::ACCOUNT_UNAUTHORIZED,
+ [],
+ Level::Warning
+ );
+ }
+
+ if (!$this->tokenService->isValid($accessToken)) {
+ throw new HttpUnauthorizedException(
+ LogMessage::ACCESS_TOKEN_EXPIRED,
+ StatusMessage::TOKEN_EXPIRED,
+ [
+ 'Access Token:' => $accessToken,
+ ],
+ );
+ }
+
+ return $handler->handle($request);
+ }
+}
diff --git a/src/App/Middleware/Token/GenerateAccessTokenMiddleware.php b/src/App/Middleware/Token/GenerateAccessTokenMiddleware.php
new file mode 100644
index 00000000..3c94050c
--- /dev/null
+++ b/src/App/Middleware/Token/GenerateAccessTokenMiddleware.php
@@ -0,0 +1,31 @@
+getAttribute(AccountInterface::AUTHENTICATED);
+
+ $accessToken = $this->accessTokenService->generate($account->uuid);
+
+ $accessToken = AccessToken::fromString($accessToken);
+
+ return $handler->handle($request->withAttribute(AccessToken::class, $accessToken));
+ }
+}
diff --git a/src/App/Middleware/Token/GenerateRefreshTokenMiddleware.php b/src/App/Middleware/Token/GenerateRefreshTokenMiddleware.php
new file mode 100644
index 00000000..bbbc10cc
--- /dev/null
+++ b/src/App/Middleware/Token/GenerateRefreshTokenMiddleware.php
@@ -0,0 +1,30 @@
+getAttribute(ClientIdentification::class);
+
+ $refreshToken = $this->tokenService->generate($clientIdentification);
+
+ $refreshToken = RefreshToken::fromString($refreshToken);
+
+ return $handler->handle($request->withAttribute(RefreshToken::class, $refreshToken));
+ }
+}
diff --git a/src/App/Middleware/Token/RefreshTokenAccountMiddleware.php b/src/App/Middleware/Token/RefreshTokenAccountMiddleware.php
new file mode 100644
index 00000000..428ea70c
--- /dev/null
+++ b/src/App/Middleware/Token/RefreshTokenAccountMiddleware.php
@@ -0,0 +1,46 @@
+getAttribute(AccountAccessAuthInterface::class);
+
+ /** @var null|AccountInterface $account */
+ $account = $this->accountRepository->findById($accountAccessAuth->accountId);
+
+ if ($account === null) {
+ throw new HttpUnauthorizedException(
+ LogMessage::REFRESH_TOKEN_ACCOUNT_NOT_FOUND,
+ StatusMessage::TOKEN_INVALID,
+ [
+ 'AccessAuth ID:' => $accountAccessAuth->id,
+ 'Account ID:' => $accountAccessAuth->accountId,
+ ],
+ Level::Warning
+ );
+ }
+ return $handler->handle($request->withAttribute(AccountInterface::AUTHENTICATED, $account));
+ }
+}
diff --git a/src/App/Middleware/Token/RefreshTokenDatabaseExistenceMiddleware.php b/src/App/Middleware/Token/RefreshTokenDatabaseExistenceMiddleware.php
new file mode 100644
index 00000000..b2883911
--- /dev/null
+++ b/src/App/Middleware/Token/RefreshTokenDatabaseExistenceMiddleware.php
@@ -0,0 +1,43 @@
+getAttribute(RefreshToken::class);
+
+ $persistToken = $this->accessAuthRepository->findByRefreshToken($refreshToken->refreshToken);
+ if (!($persistToken instanceof AccountAccessAuthInterface)) {
+ throw new HttpUnauthorizedException(
+ LogMessage::REFRESH_TOKEN_NOT_FOUND,
+ StatusMessage::TOKEN_NOT_PERSISTENT,
+ [
+ 'Refresh Token:' => $refreshToken,
+ ],
+ Level::Warning
+ );
+ }
+
+ return $handler->handle($request->withAttribute(AccountAccessAuthInterface::class, $persistToken));
+ }
+}
diff --git a/src/App/Middleware/Token/RefreshTokenMatchClientIdentificationMiddleware.php b/src/App/Middleware/Token/RefreshTokenMatchClientIdentificationMiddleware.php
new file mode 100644
index 00000000..265b1a93
--- /dev/null
+++ b/src/App/Middleware/Token/RefreshTokenMatchClientIdentificationMiddleware.php
@@ -0,0 +1,43 @@
+getAttribute(AccountAccessAuthInterface::class);
+
+ /** @var ClientIdentification $clientIdentification */
+ $clientIdentification = $request->getAttribute(ClientIdentification::class);
+
+ if ($accountAccessAuth->clientIdentHash !== $clientIdentification->identificationHash) {
+ throw new HttpUnauthorizedException(
+ LogMessage::REFRESH_TOKEN_CLIENT_MISMATCH,
+ StatusMessage::CLIENT_UNEXPECTED,
+ [
+ 'expected:' => $accountAccessAuth->clientIdentHash,
+ 'expected UserAgent' => $accountAccessAuth->userAgent,
+ 'current:' => $clientIdentification->identificationHash,
+ 'current UserAgent:' => $clientIdentification->clientIdentificationData->userAgent,
+ ],
+ Level::Warning
+ );
+ }
+
+ return $handler->handle($request);
+ }
+}
diff --git a/src/App/Middleware/Token/RefreshTokenValidationMiddleware.php b/src/App/Middleware/Token/RefreshTokenValidationMiddleware.php
new file mode 100644
index 00000000..0ccdc0cf
--- /dev/null
+++ b/src/App/Middleware/Token/RefreshTokenValidationMiddleware.php
@@ -0,0 +1,40 @@
+getHeaderLine('Authentication');
+
+ if (!$this->tokenService->isValid($refreshToken)) {
+ throw new HttpUnauthorizedException(
+ LogMessage::REFRESH_TOKEN_INVALID,
+ StatusMessage::TOKEN_INVALID,
+ [
+ 'Refresh Token:' => $refreshToken,
+ ],
+ );
+ }
+
+ $refreshToken = RefreshToken::fromString($refreshToken);
+
+ return $handler->handle($request->withAttribute(RefreshToken::class, $refreshToken));
+ }
+}
diff --git a/src/App/Middleware/Topic/TopicCreateSubmitMiddleware.php b/src/App/Middleware/Topic/TopicCreateSubmitMiddleware.php
deleted file mode 100644
index 3d1589ce..00000000
--- a/src/App/Middleware/Topic/TopicCreateSubmitMiddleware.php
+++ /dev/null
@@ -1,46 +0,0 @@
-getParsedBody();
-
- $topic = $this->hydrator->hydrate($data, Topic::class);
-
- $existTopic = $this->topicPoolService->findByTopic($topic->topic);
-
- if ($existTopic instanceof Topic) {
- throw new DuplicateNameHttpException(['topic' => ['topic' => 'The Topic is already present']]);
- }
-
- $topic = $topic->with(uuid: $this->uuid);
-
- $this->topicPoolService->insert($topic);
-
- return $handler->handle($request->withAttribute(Topic::class, $topic));
- }
-}
diff --git a/src/App/Middleware/Topic/TopicCreateValidationMiddleware.php b/src/App/Middleware/Topic/TopicCreateValidationMiddleware.php
deleted file mode 100644
index 9d2ac799..00000000
--- a/src/App/Middleware/Topic/TopicCreateValidationMiddleware.php
+++ /dev/null
@@ -1,34 +0,0 @@
-getParsedBody();
-
- $this->validator->setData($data);
-
- if (!$this->validator->isValid()) {
- throw new InvalidArgumentHttpException($this->validator->getMessages());
- }
-
- return $handler->handle($request->withParsedBody($this->validator->getValues()));
- }
-}
diff --git a/src/App/Middleware/Topic/TopicEntryStatisticMiddleware.php b/src/App/Middleware/Topic/TopicEntryStatisticMiddleware.php
deleted file mode 100644
index 3008b7f0..00000000
--- a/src/App/Middleware/Topic/TopicEntryStatisticMiddleware.php
+++ /dev/null
@@ -1,24 +0,0 @@
-topicPoolService->getEntriesStatistic();
-
- return $handler->handle($request->withAttribute('topicEntriesStatistic', $data));
- }
-}
diff --git a/src/App/Middleware/Topic/TopicListAvailableMiddleware.php b/src/App/Middleware/Topic/TopicListAvailableMiddleware.php
deleted file mode 100644
index f5249469..00000000
--- a/src/App/Middleware/Topic/TopicListAvailableMiddleware.php
+++ /dev/null
@@ -1,26 +0,0 @@
-topicPoolService->findAvailable();
- $topics = new TopicListDto($topics);
-
- return $handler->handle($request->withAttribute(TopicListDto::class, $topics));
- }
-}
diff --git a/src/App/Repository/AccountAccessAuthRepository.php b/src/App/Repository/AccountAccessAuthRepository.php
new file mode 100644
index 00000000..ae69bc9c
--- /dev/null
+++ b/src/App/Repository/AccountAccessAuthRepository.php
@@ -0,0 +1,71 @@
+store->insert($accountAccessAuth);
+ }
+
+ public function update(AccountAccessAuthInterface $accountAccessAuth): true
+ {
+ return $this->store->update($accountAccessAuth);
+ }
+
+ public function deleteById(int $id): true
+ {
+ return $this->store->deleteById($id);
+ }
+
+ public function findById(int $id): ?AccountAccessAuthInterface
+ {
+ return $this->store->findById($id);
+ }
+
+ public function findByAccountId(int $accountId): AccountAccessAuthCollectionInterface
+ {
+ return $this->store->findByAccountId($accountId);
+ }
+
+ public function findByAccountIdAndClientIdHash(int $accountId, string $clientHash): ?AccountAccessAuthInterface
+ {
+ return $this->store->findByAccountIdAndClientIdHash($accountId, $clientHash);
+ }
+
+ public function findByLabel(string $label): AccountAccessAuthCollectionInterface
+ {
+ return $this->store->findByLabel($label);
+ }
+
+ public function findByRefreshToken(string $refreshToken): ?AccountAccessAuthInterface
+ {
+ return $this->store->findByRefreshToken($refreshToken);
+ }
+
+ public function findByUserAgent(string $userAgent): AccountAccessAuthCollectionInterface
+ {
+ return $this->store->findByUserAgent($userAgent);
+ }
+
+ public function findByClientIdentHash(string $clientIdentHash): ?AccountAccessAuthInterface
+ {
+ return $this->store->findByClientIdentHash($clientIdentHash);
+ }
+
+ public function findAll(): AccountAccessAuthCollectionInterface
+ {
+ return $this->store->findAll();
+ }
+}
diff --git a/src/App/Repository/AccountActivationRepository.php b/src/App/Repository/AccountActivationRepository.php
new file mode 100644
index 00000000..a87a19e0
--- /dev/null
+++ b/src/App/Repository/AccountActivationRepository.php
@@ -0,0 +1,57 @@
+store->insert($data);
+ }
+
+ public function update(AccountActivationInterface $data): true
+ {
+ return $this->store->update($data);
+ }
+
+ public function findById(int $id): ?AccountActivationInterface
+ {
+ return $this->store->findById($id);
+ }
+
+ public function findEmail(Email $email): AccountActivationCollectionInterface
+ {
+ return $this->store->findByEmail($email);
+ }
+
+ public function findByToken(string $token): ?AccountActivationInterface
+ {
+ return $this->store->findByToken($token);
+ }
+
+ public function findAll(): AccountActivationCollectionInterface
+ {
+ return $this->store->findAll();
+ }
+
+ public function deleteById(int $id): true
+ {
+ return $this->store->deleteById($id);
+ }
+
+ public function deleteByEmail(Email $email): true
+ {
+ return $this->store->deleteByEmail($email);
+ }
+}
diff --git a/src/App/Repository/AccountRepository.php b/src/App/Repository/AccountRepository.php
new file mode 100644
index 00000000..1fbe69e4
--- /dev/null
+++ b/src/App/Repository/AccountRepository.php
@@ -0,0 +1,58 @@
+store->insert($data);
+ }
+
+ public function update(AccountInterface $data): true
+ {
+ return $this->store->update($data);
+ }
+
+ public function deleteById(int $id): true
+ {
+ return $this->store->deleteById($id);
+ }
+
+ public function findById(int $id): ?AccountInterface
+ {
+ return $this->store->findById($id);
+ }
+
+ public function findByUuid(UuidInterface $uuid): ?AccountInterface
+ {
+ return $this->store->findByUuid($uuid);
+ }
+
+ public function findByName(string $name): ?AccountInterface
+ {
+ return $this->store->findByName($name);
+ }
+
+ public function findByEmail(Email $email): ?AccountInterface
+ {
+ return $this->store->findByEmail($email);
+ }
+
+ public function findAll(): AccountCollectionInterface
+ {
+ return $this->store->findAll();
+ }
+}
diff --git a/src/App/Repository/EventRepository.php b/src/App/Repository/EventRepository.php
deleted file mode 100644
index 2c0a69dc..00000000
--- a/src/App/Repository/EventRepository.php
+++ /dev/null
@@ -1,21 +0,0 @@
-store->insert($data);
+ }
+
+ public function update(TokenInterface $data): true
+ {
+ return $this->store->update($data);
+ }
+
+ public function findById(int $id): ?TokenInterface
+ {
+ return $this->store->findById($id);
+ }
+
+ public function findByAccountId(int $accountId): TokenCollectionInterface
+ {
+ return $this->store->findByAccountId($accountId);
+ }
+
+ public function findByToken(string $token): ?TokenInterface
+ {
+ return $this->store->findByToken($token);
+ }
+
+ public function findAll(): TokenCollectionInterface
+ {
+ return $this->store->findAll();
+ }
+
+ public function deleteById(int $id): true
+ {
+ return $this->store->deleteById($id);
+ }
+
+ public function deleteByAccountId(int $accountId): true
+ {
+ return $this->store->deleteByAccountId($accountId);
+ }
+}
diff --git a/src/App/Repository/TopicPoolRepository.php b/src/App/Repository/TopicPoolRepository.php
deleted file mode 100644
index e5e19714..00000000
--- a/src/App/Repository/TopicPoolRepository.php
+++ /dev/null
@@ -1,27 +0,0 @@
-accountRepository->findByEmail($email);
+ $token = $this->createPasswordChangeTokenForUserId($account->id);
+ $this->tokenRepository->insert($token);
+ $this->tokenService->sendEmail($email, $token);
+ }
+
+ public function isEmailAvailable(Email $email): bool
+ {
+ $account = $this->accountRepository->findByEmail($email);
+
+ return $account === null;
+ }
+
+ public function createPasswordChangeTokenForUserId(int $userId): TokenInterface
+ {
+ return new Token(
+ id: null,
+ accountId: $userId,
+ tokenType: TokenType::EMail,
+ token: $this->uuid->uuid7(),
+ createdAt: new DateTimeImmutable()
+ );
+ }
+
+ public function cryptPassword(string $password): string
+ {
+ return password_hash($password, PASSWORD_BCRYPT);
+ }
+}
diff --git a/src/App/Service/Authentication/AuthenticationService.php b/src/App/Service/Authentication/AuthenticationService.php
new file mode 100644
index 00000000..bf48bac5
--- /dev/null
+++ b/src/App/Service/Authentication/AuthenticationService.php
@@ -0,0 +1,11 @@
+getIdentificationHash($clientIdentificationData);
+ }
+
+ private function getIdentificationHash(ClientIdentificationData $clientIdentificationData): string
+ {
+ return hash('sha512', serialize($clientIdentificationData));
+ }
+}
diff --git a/src/App/Service/EMail/EMailServiceInterface.php b/src/App/Service/EMail/EMailServiceInterface.php
deleted file mode 100644
index 1ae4f642..00000000
--- a/src/App/Service/EMail/EMailServiceInterface.php
+++ /dev/null
@@ -1,10 +0,0 @@
-topic);
- $text = sprintf(
- "Check the new topic and approve it if necessary\r\n\r\nTitle:\r\n%s\r\n\r\nDescription:\r\n%s\r\n\r\nLink:\r\n%s/topic/%s",
- $topic->topic,
- $topic->description,
- $this->projectUri,
- $topic->uuid,
- );
-
- $email = (new Email())
- ->from($this->mailSender)
- ->to('hackathon@exdrals.de')
- ->subject($subject)
- ->text($text);
-
- $this->mailer->send($email);
- }
-}
diff --git a/src/App/Service/EMail/TopicCreateEMailServiceFactory.php b/src/App/Service/EMail/TopicCreateEMailServiceFactory.php
deleted file mode 100644
index b231a896..00000000
--- a/src/App/Service/EMail/TopicCreateEMailServiceFactory.php
+++ /dev/null
@@ -1,20 +0,0 @@
-get(Mailer::class);
-
- $mailSender = $container->get('config')['mailer']['from'];
- $projectUri = $container->get('config')['project']['uri'];
-
- return new TopicCreateEMailService($mailer, $mailSender, $projectUri);
- }
-}
diff --git a/src/App/Service/Event/EventService.php b/src/App/Service/Event/EventService.php
deleted file mode 100644
index cd685c3c..00000000
--- a/src/App/Service/Event/EventService.php
+++ /dev/null
@@ -1,94 +0,0 @@
-isEventExist($event->title)) {
- return false;
- }
-
- $this->repository->insert($event);
-
- return true;
- }
-
- public function findById(int $id): Event
- {
- $event = $this->repository->findById($id);
-
- if ($event === []) {
- throw new InvalidArgumentException(
- sprintf('Could not find Event with id %d', $id),
- HTTP::STATUS_NOT_FOUND
- );
- }
-
- return $this->hydrator->hydrate($event, Event::class);
- }
-
- public function findByTitle(string $topic): ?Event
- {
- $event = $this->repository->findByTitle($topic);
-
- return $this->hydrator->hydrate($event, Event::class);
- }
-
- /**
- * @return array
- */
- public function findAll(string $order = 'startedAt', string $sort = 'DESC'): array
- {
- $events = $this->repository->findAll($order, $sort);
-
- return $this->hydrator->hydrateList($events, Event::class);
- }
-
- /**
- * @return array|null
- */
- public function findAllActive(): ?array
- {
- $events = $this->repository->findAllActive();
-
- return $this->hydrator->hydrateList($events, Event::class);
- }
-
- /**
- * @return array|null
- */
- public function findAllNotActive(): ?array
- {
- $events = $this->repository->findAllInactive();
-
- return $this->hydrator->hydrateList($events, Event::class);
- }
-
- public function isRatingCompleted(int $id): bool
- {
- $event = $this->findById($id);
-
- return $event->ratingCompleted;
- }
-
- public function isEventExist(string $topic): bool
- {
- $event = $this->findByTitle($topic);
-
- return $event instanceof Event;
- }
-}
diff --git a/src/App/Service/Event/EventServiceFactory.php b/src/App/Service/Event/EventServiceFactory.php
deleted file mode 100644
index 2efb2f32..00000000
--- a/src/App/Service/Event/EventServiceFactory.php
+++ /dev/null
@@ -1,48 +0,0 @@
-get(EventRepository::class);
-
- /** @var ReflectionHydrator $hydrator */
- $hydrator = clone $container->get(ReflectionHydrator::class);
-
- /** @var DateTimeFormatterStrategy $strategy */
- $strategy = $container->get(DateTimeFormatterStrategy::class);
-
- $hydrator->addStrategy(
- 'createdAt',
- $strategy,
- );
-
- $hydrator->addStrategy(
- 'startedAt',
- $strategy,
- );
-
- $hydrator->addStrategy(
- 'status',
- new BackedEnumStrategy(EventStatus::class)
- );
-
- $hydrator->addStrategy(
- 'uuid',
- new UuidStrategy()
- );
-
- return new EventService($repository, $hydrator);
- }
-}
diff --git a/src/App/Service/Participant/ParticipantService.php b/src/App/Service/Participant/ParticipantService.php
deleted file mode 100644
index f1ce23d1..00000000
--- a/src/App/Service/Participant/ParticipantService.php
+++ /dev/null
@@ -1,77 +0,0 @@
-isParticipantInEventExist($participant->userId, $participant->eventId)) {
- return false;
- }
-
- return $this->repository->insert($participant) !== 0;
- }
-
- public function remove(Participant $participant): bool
- {
- return (int)$this->repository->remove($participant) !== 0;
- }
-
- public function findById(int $id): Participant
- {
- $participant = $this->repository->findById($id);
-
- if ($participant === []) {
- throw new InvalidArgumentException(
- sprintf('Could not find Participant with id %d', $id),
- HTTP::STATUS_NOT_FOUND
- );
- }
-
- return $this->hydrator->hydrate($participant, Participant::class);
- }
-
- public function findByUserId(int $userId): ?Participant
- {
- $participant = $this->repository->findByUserId($userId);
-
- return $this->hydrator->hydrate($participant, Participant::class);
- }
-
- public function findByUserIdAndEventId(int $userId, int $eventId): ?Participant
- {
- $participant = $this->repository->findUserForAnEvent($userId, $eventId);
-
- return $this->hydrator->hydrate($participant, Participant::class);
- }
-
- /**
- * @return array|null
- */
- public function findActiveParticipantByEvent(int $eventId): ?array
- {
- $participants = $this->repository->findActiveParticipantsByEvent($eventId);
-
- return $this->hydrator->hydrateList($participants, Participant::class);
- }
-
- private function isParticipantInEventExist(int $userId, int $eventId): bool
- {
- $participant = $this->findByUserIdAndEventId($userId, $eventId);
-
- return $participant instanceof Participant;
- }
-}
diff --git a/src/App/Service/Participant/ParticipantServiceFactory.php b/src/App/Service/Participant/ParticipantServiceFactory.php
deleted file mode 100644
index eb8e157a..00000000
--- a/src/App/Service/Participant/ParticipantServiceFactory.php
+++ /dev/null
@@ -1,30 +0,0 @@
-get(ParticipantRepository::class);
-
- /** @var ReflectionHydrator $hydrator */
- $hydrator = clone $container->get(ReflectionHydrator::class);
-
- /** @var DateTimeFormatterStrategy $strategy */
- $strategy = $container->get(DateTimeFormatterStrategy::class);
-
- $hydrator->addStrategy(
- 'requestTime',
- $strategy,
- );
-
- return new ParticipantService($repository, $hydrator);
- }
-}
diff --git a/src/App/Service/Project/ProjectService.php b/src/App/Service/Project/ProjectService.php
deleted file mode 100644
index f340cb6d..00000000
--- a/src/App/Service/Project/ProjectService.php
+++ /dev/null
@@ -1,41 +0,0 @@
-repository->findById($id);
-
- if ($project === []) {
- throw new InvalidArgumentException(
- sprintf('Project with id %d not found', $id),
- HTTP::STATUS_NOT_FOUND
- );
- }
-
- return $this->hydrator->hydrate($project, Project::class);
- }
-
- public function findByParticipantId(int $id): ?Project
- {
- $project = $this->repository->findByParticipantId($id);
-
- return $this->hydrator->hydrate($project, Project::class);
- }
-}
diff --git a/src/App/Service/Project/ProjectServiceFactory.php b/src/App/Service/Project/ProjectServiceFactory.php
deleted file mode 100644
index 784ded97..00000000
--- a/src/App/Service/Project/ProjectServiceFactory.php
+++ /dev/null
@@ -1,36 +0,0 @@
-get(ProjectRepository::class);
-
- /** @var ReflectionHydrator $hydrator */
- $hydrator = clone $container->get(ReflectionHydrator::class);
-
- /** @var DateTimeFormatterStrategy $strategy */
- $strategy = $container->get(DateTimeFormatterStrategy::class);
-
- $hydrator->addStrategy(
- 'createdAt',
- $strategy,
- );
-
- $hydrator->addStrategy(
- 'uuid',
- new UuidStrategy()
- );
-
- return new ProjectService($repository, $hydrator);
- }
-}
diff --git a/src/App/Service/Token/AccessTokenService.php b/src/App/Service/Token/AccessTokenService.php
new file mode 100644
index 00000000..016a53aa
--- /dev/null
+++ b/src/App/Service/Token/AccessTokenService.php
@@ -0,0 +1,34 @@
+ $this->config->iss,
+ 'aud' => $this->config->aud,
+ 'iat' => $now,
+ 'exp' => $now + $this->config->duration,
+ 'uuid' => $uuid->getHex()->toString(),
+ ];
+
+ return JWT::encode($payload, $this->config->key, $this->config->algorithmus);
+ }
+}
diff --git a/src/App/Service/Token/AccessTokenServiceFactory.php b/src/App/Service/Token/AccessTokenServiceFactory.php
new file mode 100644
index 00000000..ba0b2d36
--- /dev/null
+++ b/src/App/Service/Token/AccessTokenServiceFactory.php
@@ -0,0 +1,17 @@
+get('config')['jwt_token']['access'];
+ $jwtTokenConfig = JwtTokenConfig::createFromArray($jwtTokenConfig);
+
+ return new AccessTokenService($jwtTokenConfig);
+ }
+}
diff --git a/src/App/Service/Token/ActivationTokenService.php b/src/App/Service/Token/ActivationTokenService.php
new file mode 100644
index 00000000..c7444652
--- /dev/null
+++ b/src/App/Service/Token/ActivationTokenService.php
@@ -0,0 +1,30 @@
+token->getHex()->toString());
+
+ $email = new Email()
+ ->from('no-reply@stormannsgal.de')
+ ->to($activation->email->toString())
+ ->subject('Account Activation Code')
+ ->text($text);
+
+ $this->mailer->send($email);
+ }
+}
diff --git a/src/App/Service/Token/JwtTokenTrait.php b/src/App/Service/Token/JwtTokenTrait.php
new file mode 100644
index 00000000..db9d14a9
--- /dev/null
+++ b/src/App/Service/Token/JwtTokenTrait.php
@@ -0,0 +1,42 @@
+config->key, $this->config->algorithmus));
+ } catch (
+ InvalidArgumentException
+ | DomainException
+ | UnexpectedValueException
+ | SignatureInvalidException
+ | BeforeValidException
+ | ExpiredException $e
+ ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public function decode(string $token): object
+ {
+ if (!$this->isValid($token)) {
+ return throw new InvalidArgumentException();
+ }
+
+ return JWT::decode($token, new Key($this->config->key, $this->config->algorithmus));
+ }
+}
diff --git a/src/App/Service/Token/PasswordTokenService.php b/src/App/Service/Token/PasswordTokenService.php
new file mode 100644
index 00000000..962fc064
--- /dev/null
+++ b/src/App/Service/Token/PasswordTokenService.php
@@ -0,0 +1,31 @@
+token->getHex()->toString());
+
+ $email = new Email()
+ ->from('no-reply@stormannsgal.de')
+ ->to($email->toString())
+ ->subject('Password Forgotten Code')
+ ->text($text);
+
+ $this->mailer->send($email);
+ }
+}
diff --git a/src/App/Service/Token/RefreshTokenService.php b/src/App/Service/Token/RefreshTokenService.php
new file mode 100644
index 00000000..3863e2bb
--- /dev/null
+++ b/src/App/Service/Token/RefreshTokenService.php
@@ -0,0 +1,34 @@
+ $this->config->iss,
+ 'aud' => $this->config->aud,
+ 'iat' => $now,
+ 'exp' => $now + $this->config->duration,
+ 'ident' => $clientIdentification->identificationHash,
+ ];
+
+ return JWT::encode($payload, $this->config->key, $this->config->algorithmus);
+ }
+}
diff --git a/src/App/Service/Token/RefreshTokenServiceFactory.php b/src/App/Service/Token/RefreshTokenServiceFactory.php
new file mode 100644
index 00000000..9f0877f8
--- /dev/null
+++ b/src/App/Service/Token/RefreshTokenServiceFactory.php
@@ -0,0 +1,17 @@
+get('config')['jwt_token']['refresh'];
+ $jwtTokenConfig = JwtTokenConfig::createFromArray($jwtTokenConfig);
+
+ return new RefreshTokenService($jwtTokenConfig);
+ }
+}
diff --git a/src/App/Service/Topic/TopicPoolService.php b/src/App/Service/Topic/TopicPoolService.php
deleted file mode 100644
index 37f907e0..00000000
--- a/src/App/Service/Topic/TopicPoolService.php
+++ /dev/null
@@ -1,112 +0,0 @@
-repository->insert($topic);
- } catch (PDOException $e) {
- /** TODO: Change to Logger */
- throw new HttpException(['PDO' => $e->getMessage()], HTTP::STATUS_INTERNAL_SERVER_ERROR);
- }
-
- return $this;
- }
-
- public function updateEventId(Topic $topic): self
- {
- $this->repository->assignAnEvent($topic->id, $topic->eventId);
-
- return $this;
- }
-
- public function findById(int $id): Topic
- {
- $event = $this->repository->findById($id);
-
- if ($event === []) {
- throw new InvalidArgumentException(
- sprintf('Could not find Event with id %d', $id),
- HTTP::STATUS_NOT_FOUND
- );
- }
-
- return $this->hydrator->hydrate($event, Topic::class);
- }
-
- public function findByEventId(int $id): ?Topic
- {
- $topic = $this->repository->findByEventId($id);
-
- return $this->hydrator->hydrate($topic, Topic::class);
- }
-
- /**
- * @return array|null
- */
- public function findAvailable(): ?array
- {
- $topics = $this->repository->findAvailable();
-
- return $this->hydrator->hydrateList($topics, Topic::class);
- }
-
- /**
- * @return array|null
- */
- public function findAll(): ?array
- {
- $topics = $this->repository->findAll();
-
- return $this->hydrator->hydrateList($topics, Topic::class);
- }
-
- public function isTopic(string $topic): bool
- {
- $topic = $this->findByTopic($topic);
-
- return $topic instanceof Topic;
- }
-
- public function findByTopic(string $topic): ?Topic
- {
- $topic = $this->repository->findByTopic($topic);
-
- return $this->hydrator->hydrate($topic, Topic::class);
- }
-
- #[ArrayShape([
- 'allTopic' => 'int',
- 'allAcceptedTopic' => 'int',
- 'allSelectionAvailableTopic' => 'int',
- ])]
- public function getEntriesStatistic(): array
- {
- return [
- 'allTopic' => $this->repository->getCountTopic(),
- 'allAcceptedTopic' => $this->repository->getCountTopicAccepted(),
- 'allSelectionAvailableTopic' => $this->repository->getCountTopicSelectionAvailable(),
- ];
- }
-}
diff --git a/src/App/Service/Topic/TopicPoolServiceFactory.php b/src/App/Service/Topic/TopicPoolServiceFactory.php
deleted file mode 100644
index f1d579a2..00000000
--- a/src/App/Service/Topic/TopicPoolServiceFactory.php
+++ /dev/null
@@ -1,27 +0,0 @@
-get(TopicPoolRepository::class);
-
- /** @var ReflectionHydrator $hydrator */
- $hydrator = clone $container->get(ReflectionHydrator::class);
-
- $hydrator->addStrategy(
- 'uuid',
- new UuidStrategy()
- );
-
- return new TopicPoolService($repository, $hydrator);
- }
-}
diff --git a/src/App/Service/User/UserService.php b/src/App/Service/User/UserService.php
deleted file mode 100644
index 9cff7f00..00000000
--- a/src/App/Service/User/UserService.php
+++ /dev/null
@@ -1,95 +0,0 @@
-repository->updateLastUserActionTime($user->id, new DateTime());
-
- return $user;
- }
-
- public function create(User $user, UserRole $role = UserRole::USER): int
- {
- if ($this->isEmailExist($user->email)) {
- return throw new DuplicateEntryException('User', $user->uuid->getHex()->toString());
- }
-
- $hashedPassword = password_hash($user->password, PASSWORD_BCRYPT);
-
- $user = $user->with(
- password: $hashedPassword,
- role: $role,
- uuid: $this->uuid,
- );
-
- return $this->repository->insert($user);
- }
-
- public function update(User $user): bool
- {
- return (bool)$this->repository->update($user);
- }
-
- // @phpstan-ignore-next-line
- private function isUserExist(string $userName): bool
- {
- $user = $this->findByName($userName);
-
- return $user instanceof User;
- }
-
- private function isEmailExist(string $email): bool
- {
- $user = $this->findByEMail($email);
-
- return ($user instanceof User);
- }
-
- public function findById(int $id): ?User
- {
- $user = $this->repository->findById($id);
-
- return $user !== [] ? $this->hydrator->hydrate($user, User::class) : null;
- }
-
- public function findByUuid(string $uuid): ?User
- {
- $user = $this->repository->findByUuid($uuid);
-
- return $user !== [] ? $this->hydrator->hydrate($user, User::class) : null;
- }
-
- public function findByName(string $name): ?User
- {
- $user = $this->repository->findByName($name);
-
- return $user !== [] ? $this->hydrator->hydrate($user, User::class) : null;
- }
-
- public function findByEMail(string $email): ?User
- {
- $user = $this->repository->findByEMail($email);
-
- return $user !== [] ? $this->hydrator->hydrate($user, User::class) : null;
- }
-}
diff --git a/src/App/Service/User/UserServiceFactory.php b/src/App/Service/User/UserServiceFactory.php
deleted file mode 100644
index 21b3e213..00000000
--- a/src/App/Service/User/UserServiceFactory.php
+++ /dev/null
@@ -1,52 +0,0 @@
-get(UserRepository::class);
-
- /** @var ReflectionHydrator $hydrator */
- $hydrator = clone $container->get(ReflectionHydrator::class);
-
- /** @var DateTimeImmutableFormatterStrategy $dateTimeFormatterStrategy */
- $dateTimeFormatterStrategy = $container->get(DateTimeImmutableFormatterStrategy::class);
-
- /** @var Uuid $uuid */
- $uuid = $container->get(Uuid::class);
-
- $hydrator->addStrategy(
- 'registrationAt',
- $dateTimeFormatterStrategy,
- );
-
- $hydrator->addStrategy(
- 'lastActionAt',
- $dateTimeFormatterStrategy,
- );
-
- $hydrator->addStrategy(
- 'role',
- new BackedEnumStrategy(UserRole::class)
- );
-
- $hydrator->addStrategy(
- 'uuid',
- new UuidStrategy()
- );
-
- return new UserService($repository, $hydrator, $uuid);
- }
-}
diff --git a/src/App/Table/AbstractTable.php b/src/App/Table/AbstractTable.php
new file mode 100644
index 00000000..859829c5
--- /dev/null
+++ b/src/App/Table/AbstractTable.php
@@ -0,0 +1,44 @@
+table = substr(new ReflectionClass($this)->getShortName(), 0, -5);
+ $this->query = $query;
+ }
+
+ public function getTableName(): string
+ {
+ return $this->table;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function deleteById(int $id): true
+ {
+ $result = $this->query->delete($this->table, $id)->execute();
+
+ if ($result === false) {
+ throw new InvalidArgumentException(
+ sprintf('Failed to delete %s table with id: `%s`', $this->getTableName(), $id)
+ );
+ }
+
+ return true;
+ }
+}
diff --git a/src/App/Table/AccountAccessAuthTable.php b/src/App/Table/AccountAccessAuthTable.php
new file mode 100644
index 00000000..f0aa363c
--- /dev/null
+++ b/src/App/Table/AccountAccessAuthTable.php
@@ -0,0 +1,143 @@
+hydrator->extract($data);
+
+ unset($value['id']);
+
+ try {
+ $lastInsertId = $this->query->insertInto($this->table, $value)->execute();
+ } catch (Exception | PDOException $e) {
+ return throw new DuplicateEntryException($this->getTableName(), $data->id);
+ }
+
+ return true;
+ }
+
+ public function update(AccountAccessAuthInterface $data): true
+ {
+ $value = $this->hydrator->extract($data);
+
+ $result = $this->query->update($this->table, $value, $data->id)->execute();
+
+ if ($result === false) {
+ throw new InvalidArgumentException(
+ sprintf('Unknown Error while updating %s with id: %s', $this->getTableName(), $data->id)
+ );
+ }
+
+ return true;
+ }
+
+ public function findById(int $id): ?AccountAccessAuthInterface
+ {
+ $result = $this->query->from($this->table)
+ ->where('id', $id)
+ ->fetch();
+
+ return is_array($result) ? $this->hydrator->hydrate($result) : null;
+ }
+
+ public function findByAccountId(int $accountId): AccountAccessAuthCollectionInterface
+ {
+ $result = $this->query->from($this->table)
+ ->where('userId', $accountId)
+ ->fetchAll();
+
+ return is_array($result)
+ ? $this->hydrator->hydrateCollection($result)
+ : $this->hydrator->hydrateCollection(
+ []
+ );
+ }
+
+ public function findByAccountIdAndClientIdHash(int $accountId, string $clientHash): ?AccountAccessAuthInterface
+ {
+ $result = $this->query->from($this->table)
+ ->where('accountId', $accountId)
+ ->where('clientIdentHash', $clientHash)
+ ->fetch();
+
+ return is_array($result) ? $this->hydrator->hydrate($result) : null;
+ }
+
+ public function findByLabel(string $label): AccountAccessAuthCollectionInterface
+ {
+ $result = $this->query->from($this->table)
+ ->where('label', $label)
+ ->fetchAll();
+
+ return is_array($result)
+ ? $this->hydrator->hydrateCollection($result)
+ : $this->hydrator->hydrateCollection(
+ []
+ );
+ }
+
+ public function findByRefreshToken(string $refreshToken): ?AccountAccessAuthInterface
+ {
+ $result = $this->query->from($this->table)
+ ->where('refreshToken', $refreshToken)
+ ->fetch();
+
+ return is_array($result) ? $this->hydrator->hydrate($result) : null;
+ }
+
+ public function findByUserAgent(string $userAgent): AccountAccessAuthCollectionInterface
+ {
+ $result = $this->query->from($this->table)
+ ->where('userAgent', $userAgent)
+ ->fetchAll();
+
+ return is_array($result)
+ ? $this->hydrator->hydrateCollection($result)
+ : $this->hydrator->hydrateCollection(
+ []
+ );
+ }
+
+ public function findByClientIdentHash(string $clientIdentHash): ?AccountAccessAuthInterface
+ {
+ $result = $this->query->from($this->table)
+ ->where('clientIdentHash', $clientIdentHash)
+ ->fetch();
+
+ return is_array($result) ? $this->hydrator->hydrate($result) : null;
+ }
+
+ public function findAll(): AccountAccessAuthCollectionInterface
+ {
+ $result = $this->query->from($this->table)->fetchAll();
+
+ return is_array($result)
+ ? $this->hydrator->hydrateCollection($result)
+ : $this->hydrator->hydrateCollection(
+ []
+ );
+ }
+}
diff --git a/src/App/Table/AccountActivationTable.php b/src/App/Table/AccountActivationTable.php
new file mode 100644
index 00000000..137b1823
--- /dev/null
+++ b/src/App/Table/AccountActivationTable.php
@@ -0,0 +1,105 @@
+hydrator->extract($data);
+
+ unset($value['id']);
+
+ try {
+ $this->query->insertInto($this->table, $value)->execute();
+ } catch (PDOException $e) {
+ throw new DuplicateEntryException($this->getTableName(), $data->id);
+ }
+
+ return true;
+ }
+
+ public function update(AccountActivationInterface $data): true
+ {
+ $value = $this->hydrator->extract($data);
+
+ $result = $this->query->update($this->table, $value, $data->id)->execute();
+
+ if ($result === false) {
+ throw new InvalidArgumentException(
+ sprintf('Unknown Error while updating %s with id: %s', $this->getTableName(), $data->id)
+ );
+ }
+
+ return true;
+ }
+
+ public function findById(int $id): ?AccountActivationInterface
+ {
+ $result = $this->query->from($this->table)
+ ->where('id', $id)
+ ->fetch();
+
+ return is_array($result) ? $this->hydrator->hydrate($result) : null;
+ }
+
+ public function findByEmail(Email $email): AccountActivationCollectionInterface
+ {
+ $result = $this->query->from($this->table)
+ ->where('email', $email->toString())
+ ->fetchAll();
+
+ return is_array($result) ? $this->hydrator->hydrateCollection($result) : $this->hydrator->hydrateCollection([]);
+ }
+
+ public function findByToken(string $token): ?AccountActivationInterface
+ {
+ $result = $this->query->from($this->table)
+ ->where('token', $token)
+ ->fetch();
+
+ return is_array($result) ? $this->hydrator->hydrate($result) : null;
+ }
+
+ public function findAll(): AccountActivationCollectionInterface
+ {
+ $result = $this->query->from($this->table)->fetchAll();
+
+ return is_array($result) ? $this->hydrator->hydrateCollection($result) : $this->hydrator->hydrateCollection([]);
+ }
+
+ public function deleteByEmail(Email $email): true
+ {
+ $result = $this->query->delete($this->table)
+ ->where('email', $email->toString())
+ ->execute();
+
+ if ($result === false) {
+ throw new InvalidArgumentException(
+ sprintf('Failed to delete %s table with email: `%s`', $this->getTableName(), $email->toString())
+ );
+ }
+
+ return true;
+ }
+}
diff --git a/src/App/Table/AccountTable.php b/src/App/Table/AccountTable.php
new file mode 100644
index 00000000..2bc5dca5
--- /dev/null
+++ b/src/App/Table/AccountTable.php
@@ -0,0 +1,105 @@
+hydrator->extract($data);
+
+ unset($value['id']);
+
+ try {
+ $this->query->insertInto($this->table, $value)->execute();
+ } catch (PDOException $e) {
+ throw new DuplicateEntryException($this->getTableName(), $data->id);
+ }
+
+ return true;
+ }
+
+ public function update(AccountInterface $data): true
+ {
+ $value = $this->hydrator->extract($data);
+
+ $result = $this->query->update($this->table, $value, $data->id)->execute();
+
+ if ($result === false) {
+ throw new InvalidArgumentException(
+ sprintf('Unknown Error while updating %s with id: %s', $this->getTableName(), $data->id)
+ );
+ }
+
+ return true;
+ }
+
+ public function findById(int $id): ?AccountInterface
+ {
+ $result = $this->query->from($this->table)
+ ->where('id', $id)
+ ->fetch();
+
+ return is_array($result) ? $this->hydrator->hydrate($result) : null;
+ }
+
+ public function findByUuid(UuidInterface $uuid): ?AccountInterface
+ {
+ $result = $this->query->from($this->table)
+ ->where('uuid', $uuid->getHex()->toString())
+ ->fetch();
+
+ return is_array($result) ? $this->hydrator->hydrate($result) : null;
+ }
+
+ public function findByName(string $name): ?AccountInterface
+ {
+ $result = $this->query->from($this->table)
+ ->where('name', $name)
+ ->fetch();
+
+ return is_array($result) ? $this->hydrator->hydrate($result) : null;
+ }
+
+ public function findByEmail(Email $email): ?AccountInterface
+ {
+ $result = $this->query->from($this->table)
+ ->where('email', $email->toString())
+ ->fetch();
+
+ return is_array($result) ? $this->hydrator->hydrate($result) : null;
+ }
+
+ public function findAll(): AccountCollectionInterface
+ {
+ $result = $this->query->from($this->table)->fetchAll();
+
+ return is_array($result) ? $this->hydrator->hydrateCollection($result) : $this->hydrator->hydrateCollection([]);
+ }
+}
diff --git a/src/App/Table/EventTable.php b/src/App/Table/EventTable.php
deleted file mode 100644
index d789fec6..00000000
--- a/src/App/Table/EventTable.php
+++ /dev/null
@@ -1,75 +0,0 @@
- $event->uuid->getHex()->toString(),
- 'userId' => $event->userId,
- 'title' => $event->title,
- 'description' => $event->description,
- 'eventText' => $event->eventText,
- 'startedAt' => $event->startedAt->format('Y-m-d H:i'),
- 'duration' => $event->duration,
- ];
-
- $insertStatus = $this->query->insertInto($this->table, $values)->execute();
-
- if (!$insertStatus) {
- throw new DuplicateEntryException('Event', $event->uuid->getHex()->toString());
- }
-
- return (int)$insertStatus;
- }
-
- public function findAll(string $order = 'startedAt', string $sort = 'DESC'): array
- {
- $result = $this->query->from($this->table)->orderBy($order . ' ' . $sort)->fetchAll();
-
- return $result ?: [];
- }
-
- public function findByTitle(string $title): array
- {
- $result = $this->query->from($this->table)
- ->where('title', $title)
- ->fetch();
-
- return $result ?: [];
- }
-
- public function findAllActive(): array
- {
- $result = $this->query->from($this->table)
- ->where('active', 1)
- ->orderBy('startedAt DESC')
- ->fetchAll();
-
- return $result ?: [];
- }
-
- public function findAllInactive(): array
- {
- $result = $this->query->from($this->table)
- ->where('active', 0)
- ->orderBy('startedAt DESC')
- ->fetchAll();
-
- return $result ?: [];
- }
-
- public function remove(Event $event): bool
- {
- return $this->query->deleteFrom($this->table)
- ->where('id', $event->id)
- ->execute();
- }
-}
diff --git a/src/App/Table/ParticipantTable.php b/src/App/Table/ParticipantTable.php
deleted file mode 100644
index 65a8532f..00000000
--- a/src/App/Table/ParticipantTable.php
+++ /dev/null
@@ -1,69 +0,0 @@
- $participant->userId,
- 'eventId' => $participant->eventId,
- ];
-
- $insertStatus = $this->query->insertInto($this->table, $values)
- ->onDuplicateKeyUpdate(['subscribed' => 1])
- ->execute();
-
- if (!$insertStatus) {
- throw new DuplicateEntryException('Participant', (string)$participant->id);
- }
-
- return (int)$insertStatus;
- }
-
- public function remove(Participant $participant): bool
- {
- return (bool)$this->query->update($this->table)
- ->set(['subscribed' => 0])
- ->where('userId', $participant->userId)
- ->where('eventId', $participant->eventId)
- ->execute();
- }
-
- public function findByUserId(int $userId): array
- {
- $result = $this->query->from($this->table)
- ->where('userId', $userId)
- ->fetch();
-
- return $result ?: [];
- }
-
- public function findUserForAnEvent(int $userId, int $eventId): array
- {
- $result = $this->query->from($this->table)
- ->where('userId', $userId)
- ->where('eventId', $eventId)
- ->where('subscribed', 1)
- ->fetch();
-
- return $result ?: [];
- }
-
- public function findActiveParticipantsByEvent(int $eventId): array
- {
- $result = $this->query->from($this->table)
- ->where('eventId', $eventId)
- ->where('subscribed', 1)
- ->where('disqualified', 0)
- ->fetchAll();
-
- return $result ?: [];
- }
-}
diff --git a/src/App/Table/ProjectTable.php b/src/App/Table/ProjectTable.php
deleted file mode 100644
index f6ecdc73..00000000
--- a/src/App/Table/ProjectTable.php
+++ /dev/null
@@ -1,16 +0,0 @@
-query->from($this->table)
- ->where('participantId', $id)
- ->fetch();
- }
-}
diff --git a/src/App/Table/TokenTable.php b/src/App/Table/TokenTable.php
new file mode 100644
index 00000000..63425c1e
--- /dev/null
+++ b/src/App/Table/TokenTable.php
@@ -0,0 +1,104 @@
+hydrator->extract($data);
+
+ unset($value['id']);
+
+ try {
+ $this->query->insertInto($this->table, $value)->execute();
+ } catch (PDOException $e) {
+ throw new DuplicateEntryException($this->getTableName(), $data->id);
+ }
+
+ return true;
+ }
+
+ public function update(TokenInterface $data): true
+ {
+ $value = $this->hydrator->extract($data);
+
+ $result = $this->query->update($this->table, $value, $data->id)->execute();
+
+ if ($result === false) {
+ throw new InvalidArgumentException(
+ sprintf('Unknown Error while updating %s with id: %s', $this->getTableName(), $data->id)
+ );
+ }
+
+ return true;
+ }
+
+ public function findById(int $id): ?TokenInterface
+ {
+ $result = $this->query->from($this->table)
+ ->where('id', $id)
+ ->fetch();
+
+ return is_array($result) ? $this->hydrator->hydrate($result) : null;
+ }
+
+ public function findByAccountId(int $accountId): TokenCollectionInterface
+ {
+ $result = $this->query->from($this->table)
+ ->where('accountId', $accountId)
+ ->fetchAll();
+
+ return is_array($result) ? $this->hydrator->hydrateCollection($result) : $this->hydrator->hydrateCollection([]);
+ }
+
+ public function findByToken(string $token): ?TokenInterface
+ {
+ $result = $this->query->from($this->table)
+ ->where('token', $token)
+ ->fetch();
+
+ return is_array($result) ? $this->hydrator->hydrate($result) : null;
+ }
+
+ public function findAll(): TokenCollectionInterface
+ {
+ $result = $this->query->from($this->table)->fetchAll();
+
+ return is_array($result) ? $this->hydrator->hydrateCollection($result) : $this->hydrator->hydrateCollection([]);
+ }
+
+ public function deleteByAccountId(int $accountId): true
+ {
+ $result = $this->query->delete($this->table)
+ ->where('accountId', $accountId)
+ ->execute();
+
+ if ($result === false) {
+ throw new InvalidArgumentException(
+ sprintf('Failed to delete %s table with accountId: `%s`', $this->getTableName(), $accountId)
+ );
+ }
+
+ return true;
+ }
+}
diff --git a/src/App/Table/TopicPoolTable.php b/src/App/Table/TopicPoolTable.php
deleted file mode 100644
index 4189adb1..00000000
--- a/src/App/Table/TopicPoolTable.php
+++ /dev/null
@@ -1,89 +0,0 @@
- $topic->uuid->getHex()->toString(),
- 'topic' => $topic->topic,
- 'description' => $topic->description,
- ];
-
- $this->query->insertInto($this->table, $values)->execute();
-
- return $this;
- }
-
- public function findByUuId(string $uuid): bool|array
- {
- return $this->query->from($this->table)
- ->where('uuid', $uuid)
- ->fetch();
- }
-
- public function assignAnEvent(int $topicId, int $eventId): self
- {
- $values = [
- 'eventId' => $eventId,
- ];
- $this->query->update($this->table, $values, $topicId)->execute();
-
- return $this;
- }
-
- public function findByEventId(int $eventId): bool|array
- {
- return $this->query->from($this->table)
- ->where('eventId', $eventId)
- ->fetch();
- }
-
- public function findAvailable(): bool|array
- {
- return $this->query->from($this->table)
- ->where('eventId', null)
- ->where('accepted', 1)
- ->fetchAll();
- }
-
- public function findByTopic(string $topic): bool|array
- {
- return $this->query->from($this->table)
- ->where('topic', $topic)
- ->fetch();
- }
-
- public function getCountTopic(): int
- {
- $data = $this->query->from($this->table)
- ->select('COUNT(id) AS countTopic')
- ->fetch();
- return $data['countTopic'];
- }
-
- public function getCountTopicAccepted(): int
- {
- $data = $this->query->from($this->table)
- ->select('COUNT(id) AS countTopic')
- ->where('accepted', 1)
- ->fetch();
- return $data['countTopic'];
- }
-
- public function getCountTopicSelectionAvailable(): int
- {
- $data = $this->query->from($this->table)
- ->select('COUNT(id) AS countTopic')
- ->where('accepted', 1)
- ->where('eventId', null)
- ->fetch();
- return $data['countTopic'];
- }
-}
diff --git a/src/App/Validator/AccountActivationValidator.php b/src/App/Validator/AccountActivationValidator.php
new file mode 100644
index 00000000..9a9ad148
--- /dev/null
+++ b/src/App/Validator/AccountActivationValidator.php
@@ -0,0 +1,18 @@
+add($this->accountNameInput);
+ $this->add($this->passwordInput);
+ }
+}
diff --git a/src/App/Validator/AuthenticationValidator.php b/src/App/Validator/AuthenticationValidator.php
new file mode 100644
index 00000000..f01eca9c
--- /dev/null
+++ b/src/App/Validator/AuthenticationValidator.php
@@ -0,0 +1,18 @@
+add($this->emailInput);
+ $this->add($this->passwordInput);
+ }
+}
diff --git a/src/Core/Validator/DateLessNow.php b/src/App/Validator/DateLessNow.php
similarity index 89%
rename from src/Core/Validator/DateLessNow.php
rename to src/App/Validator/DateLessNow.php
index b4f04106..f645d1d0 100644
--- a/src/Core/Validator/DateLessNow.php
+++ b/src/App/Validator/DateLessNow.php
@@ -1,6 +1,6 @@
add($this->eventTitleInput);
- $this->add($this->descriptionInput);
- $this->add($this->eventTextInput);
- $this->add($this->startTimeInput);
- $this->add($this->durationInput);
- }
-}
diff --git a/src/App/Validator/Input/Topic/TopicInput.php b/src/App/Validator/Input/AccountNameInput.php
similarity index 73%
rename from src/App/Validator/Input/Topic/TopicInput.php
rename to src/App/Validator/Input/AccountNameInput.php
index e2591493..efedd759 100644
--- a/src/App/Validator/Input/Topic/TopicInput.php
+++ b/src/App/Validator/Input/AccountNameInput.php
@@ -1,14 +1,14 @@
setRequired(true);
@@ -19,7 +19,7 @@ public function __construct()
[
'encoding' => 'UTF-8',
'min' => 3,
- 'max' => 50,
+ 'max' => 64,
]
);
}
diff --git a/src/Core/Validator/Input/EmailInput.php b/src/App/Validator/Input/EmailInput.php
similarity index 87%
rename from src/Core/Validator/Input/EmailInput.php
rename to src/App/Validator/Input/EmailInput.php
index 36175a4e..3103418a 100644
--- a/src/Core/Validator/Input/EmailInput.php
+++ b/src/App/Validator/Input/EmailInput.php
@@ -1,6 +1,6 @@
setRequired(true);
diff --git a/src/App/Validator/Input/Event/EventDescriptionInput.php b/src/App/Validator/Input/Event/EventDescriptionInput.php
deleted file mode 100644
index 1fa4114c..00000000
--- a/src/App/Validator/Input/Event/EventDescriptionInput.php
+++ /dev/null
@@ -1,27 +0,0 @@
-setRequired(false);
-
- $this->getFilterChain()->attachByName('StringTrim');
-
- $this->getValidatorChain()->attachByName(
- 'StringLength',
- [
- 'encoding' => 'UTF-8',
- 'min' => 10,
- 'max' => 255,
- 'inclusive' => true,
- ]
- );
- }
-}
diff --git a/src/App/Validator/Input/Event/EventDurationInput.php b/src/App/Validator/Input/Event/EventDurationInput.php
deleted file mode 100644
index 689f0fad..00000000
--- a/src/App/Validator/Input/Event/EventDurationInput.php
+++ /dev/null
@@ -1,26 +0,0 @@
-setRequired(true);
-
- $this->getValidatorChain()->attachByName(
- 'GreaterThan',
- [
- 'min' => 1,
- 'max' => 356,
- 'inclusive' => true,
- ],
- );
-
- $this->getFilterChain()->attachByName('ToInt');
- }
-}
diff --git a/src/App/Validator/Input/Event/EventStartTimeInput.php b/src/App/Validator/Input/Event/EventStartTimeInput.php
deleted file mode 100644
index 5d7f8b52..00000000
--- a/src/App/Validator/Input/Event/EventStartTimeInput.php
+++ /dev/null
@@ -1,27 +0,0 @@
-setRequired(true);
- $this->setBreakOnFailure(true);
-
- $this->getValidatorChain()->attach(
- new Date([
- 'format' => 'Y-m-d H:i:s',
- 'strict' => true,
- ]),
- );
-
- $this->getValidatorChain()->attach(new DateLessNow());
- }
-}
diff --git a/src/App/Validator/Input/Event/EventTextInput.php b/src/App/Validator/Input/Event/EventTextInput.php
deleted file mode 100644
index d8f70f34..00000000
--- a/src/App/Validator/Input/Event/EventTextInput.php
+++ /dev/null
@@ -1,27 +0,0 @@
-setRequired(false);
-
- $this->getFilterChain()->attachByName('StringTrim');
-
- $this->getValidatorChain()->attachByName(
- 'StringLength',
- [
- 'encoding' => 'UTF-8',
- 'min' => 50,
- 'max' => 8192,
- 'inclusive' => true,
- ]
- );
- }
-}
diff --git a/src/App/Validator/Input/Event/EventTitleInput.php b/src/App/Validator/Input/Event/EventTitleInput.php
deleted file mode 100644
index 5dbdeded..00000000
--- a/src/App/Validator/Input/Event/EventTitleInput.php
+++ /dev/null
@@ -1,27 +0,0 @@
-setRequired(true);
-
- $this->getFilterChain()->attachByName('StringTrim');
-
- $this->getValidatorChain()->attachByName(
- 'StringLength',
- [
- 'encoding' => 'UTF-8',
- 'min' => 3,
- 'max' => 50,
- 'inclusive' => true,
- ]
- );
- }
-}
diff --git a/src/Core/Validator/Input/PasswordInput.php b/src/App/Validator/Input/PasswordInput.php
similarity index 88%
rename from src/Core/Validator/Input/PasswordInput.php
rename to src/App/Validator/Input/PasswordInput.php
index 0327d695..02a447d2 100644
--- a/src/Core/Validator/Input/PasswordInput.php
+++ b/src/App/Validator/Input/PasswordInput.php
@@ -1,6 +1,6 @@
'UTF-8',
'min' => 6,
+ 'max' => 255,
]
);
}
diff --git a/src/App/Validator/Input/Topic/TopicDescriptionInput.php b/src/App/Validator/Input/Topic/TopicDescriptionInput.php
deleted file mode 100644
index d7a16a79..00000000
--- a/src/App/Validator/Input/Topic/TopicDescriptionInput.php
+++ /dev/null
@@ -1,26 +0,0 @@
-setRequired(true);
-
- $this->getFilterChain()->attachByName('StringTrim');
-
- $this->getValidatorChain()->attachByName(
- 'StringLength',
- [
- 'encoding' => 'UTF-8',
- 'min' => 20,
- 'max' => 8096,
- ]
- );
- }
-}
diff --git a/src/Core/Validator/UserPasswordChangeValidator.php b/src/App/Validator/PasswordValidator.php
similarity index 64%
rename from src/Core/Validator/UserPasswordChangeValidator.php
rename to src/App/Validator/PasswordValidator.php
index c7fa1380..bca0e1bc 100644
--- a/src/Core/Validator/UserPasswordChangeValidator.php
+++ b/src/App/Validator/PasswordValidator.php
@@ -1,11 +1,11 @@
add($this->topicInput);
- $this->add($this->topicDescriptionInput);
- }
-}
diff --git a/src/Core/ConfigProvider.php b/src/Core/ConfigProvider.php
index 264b8db6..17e6d5ca 100644
--- a/src/Core/ConfigProvider.php
+++ b/src/Core/ConfigProvider.php
@@ -2,29 +2,10 @@
namespace Core;
-use App\Service\User\UserService;
-use Core\Handler\LoginHandlerFactory;
-use Core\Handler\UserPasswordForgottonHandlerFactory;
-use Core\Hydrator\ClassMethodsHydratorFactory;
-use Core\Hydrator\DateTimeFormatterStrategyFactory;
-use Core\Hydrator\DateTimeImmutableFormatterStrategyFactory;
-use Core\Hydrator\NullableStrategyFactory;
-use Core\Hydrator\ReflectionHydrator;
-use Core\Listener\LoggingErrorListener;
-use Core\Listener\LoggingErrorListenerFactory;
-use Core\Middleware\JwtAuthenticationMiddlewareFactory;
-use Core\Repository\UserRepository;
-use Core\Service\ApiAccessService;
-use Core\Service\ApiAccessServiceFactory;
-use Core\Service\LoginAuthenticationService;
-use Core\Table\UserTable;
-use Core\Token\TokenService;
-use Envms\FluentPDO\Query;
-use Laminas\Hydrator\ClassMethodsHydrator;
-use Laminas\Hydrator\Strategy\DateTimeFormatterStrategy;
-use Laminas\Hydrator\Strategy\DateTimeImmutableFormatterStrategy;
-use Laminas\Hydrator\Strategy\NullableStrategy;
+use App\Validator\Input\EmailInput;
+use App\Validator\Input\PasswordInput;
use Laminas\ServiceManager\AbstractFactory\ConfigAbstractFactory;
+use Psr\Log\LoggerInterface;
class ConfigProvider
{
@@ -40,50 +21,16 @@ public function getDependencies(): array
{
return [
'invokables' => [
- ReflectionHydrator::class,
-
- Validator\Input\EmailInput::class,
- Validator\Input\PasswordInput::class,
- Validator\Input\UsernameInput::class,
+ EmailInput::class => EmailInput::class,
+ PasswordInput::class => PasswordInput::class,
],
'aliases' => [
- UserRepository::class => UserTable::class,
],
'factories' => [
- ClassMethodsHydrator::class => ClassMethodsHydratorFactory::class,
- DateTimeFormatterStrategy::class => DateTimeFormatterStrategyFactory::class,
- DateTimeImmutableFormatterStrategy::class => DateTimeImmutableFormatterStrategyFactory::class,
-
- Handler\LoginHandler::class => LoginHandlerFactory::class,
- Handler\UserHandler::class => ConfigAbstractFactory::class,
- Handler\UserPasswordForgottonHandler::class => UserPasswordForgottonHandlerFactory::class,
-
- LoggingErrorListener::class => LoggingErrorListenerFactory::class,
-
- Middleware\ApiAccessMiddleware::class => ConfigAbstractFactory::class,
- Middleware\JwtAuthenticationMiddleware::class => JwtAuthenticationMiddlewareFactory::class,
- Middleware\LoginAuthenticationMiddleware::class => ConfigAbstractFactory::class,
- Middleware\LoginValidationMiddleware::class => ConfigAbstractFactory::class,
- Middleware\UserPasswordChangeMiddleware::class => ConfigAbstractFactory::class,
- Middleware\UserPasswordChangeValidatorMiddleware::class => ConfigAbstractFactory::class,
- Middleware\UserPasswordForgottenMiddleware::class => ConfigAbstractFactory::class,
- Middleware\UserPasswordForgottenValidator::class => ConfigAbstractFactory::class,
- Middleware\UserPasswordVerifyTokenMiddleware::class => ConfigAbstractFactory::class,
- Middleware\UserRegisterMiddleware::class => ConfigAbstractFactory::class,
- Middleware\UserRegisterValidationMiddleware::class => ConfigAbstractFactory::class,
- Middleware\UpdateLastUserActionTimeMiddleware::class => ConfigAbstractFactory::class,
- Middleware\UserMiddleware::class => ConfigAbstractFactory::class,
-
- NullableStrategy::class => NullableStrategyFactory::class,
-
- Service\ApiAccessService::class => ApiAccessServiceFactory::class,
+ Factory\ErrorResponseFactory::class => ConfigAbstractFactory::class,
+ Middleware\ApiErrorHandlerMiddleware::class => ConfigAbstractFactory::class,
+ Middleware\RouteNotFoundMiddleware::class => ConfigAbstractFactory::class,
- Table\UserTable::class => ConfigAbstractFactory::class,
-
- Validator\LoginValidator::class => ConfigAbstractFactory::class,
- Validator\PasswordForgottenEmailValidator::class => ConfigAbstractFactory::class,
- Validator\RegisterValidator::class => ConfigAbstractFactory::class,
- Validator\UserPasswordChangeValidator::class => ConfigAbstractFactory::class,
],
];
}
@@ -91,65 +38,14 @@ public function getDependencies(): array
public function getAbstractFactoryConfig(): array
{
return [
- Handler\UserHandler::class => [
- ClassMethodsHydrator::class,
- ],
- Middleware\UserRegisterMiddleware::class => [
- UserService::class,
- ReflectionHydrator::class,
- ],
- Middleware\ApiAccessMiddleware::class => [
- ApiAccessService::class,
- ],
- Middleware\UserPasswordForgottenMiddleware::class => [
- UserService::class,
- TokenService::class,
- ],
- Middleware\UserPasswordChangeMiddleware::class => [
- UserService::class,
- ],
- Middleware\UserPasswordChangeValidatorMiddleware::class => [
- Validator\UserPasswordChangeValidator::class,
- ],
- Middleware\UserPasswordForgottenValidator::class => [
- Validator\PasswordForgottenEmailValidator::class,
- ],
- Middleware\UserPasswordVerifyTokenMiddleware::class => [
- UserService::class,
- ],
- Middleware\UserRegisterValidationMiddleware::class => [
- Validator\RegisterValidator::class,
- ],
- Middleware\LoginAuthenticationMiddleware::class => [
- UserService::class,
- LoginAuthenticationService::class,
- ],
- Middleware\LoginValidationMiddleware::class => [
- Validator\LoginValidator::class,
- ],
- Middleware\UpdateLastUserActionTimeMiddleware::class => [
- UserService::class,
- ],
- Middleware\UserMiddleware::class => [
- UserService::class,
- ],
-
- Table\UserTable::class => [
- Query::class,
- ],
-
- Validator\LoginValidator::class => [
- Validator\Input\UsernameInput::class,
- Validator\Input\PasswordInput::class,
- ],
- Validator\PasswordForgottenEmailValidator::class => [
- Validator\Input\EmailInput::class,
+ Factory\ErrorResponseFactory::class => [
+ LoggerInterface::class,
],
- Validator\RegisterValidator::class => [
- Validator\Input\EmailInput::class,
+ Middleware\ApiErrorHandlerMiddleware::class => [
+ Factory\ErrorResponseFactory::class,
],
- Validator\UserPasswordChangeValidator::class => [
- Validator\Input\PasswordInput::class,
+ Middleware\RouteNotFoundMiddleware::class => [
+ LoggerInterface::class,
],
];
}
diff --git a/src/Core/Dto/ApiMeDto.php b/src/Core/Dto/ApiMeDto.php
deleted file mode 100644
index 21e1747f..00000000
--- a/src/Core/Dto/ApiMeDto.php
+++ /dev/null
@@ -1,38 +0,0 @@
-uuid = $user->uuid->getHex()->toString();
- $this->name = $user->name;
- $this->role = $user->role->getRoleName();
- }
-}
diff --git a/src/Core/Dto/HttpStatusCodeMessage.php b/src/Core/Dto/HttpStatusCodeMessage.php
deleted file mode 100644
index 781c960f..00000000
--- a/src/Core/Dto/HttpStatusCodeMessage.php
+++ /dev/null
@@ -1,35 +0,0 @@
-status = $status;
- $this->message = $message;
- $this->data = $data;
- }
-}
diff --git a/src/Core/Dto/SimpleMessageDto.php b/src/Core/Dto/SimpleMessageDto.php
deleted file mode 100644
index 0ff6ba79..00000000
--- a/src/Core/Dto/SimpleMessageDto.php
+++ /dev/null
@@ -1,20 +0,0 @@
-message = $message;
- }
-}
diff --git a/src/Core/Dto/User/LoginTokenDto.php b/src/Core/Dto/User/LoginTokenDto.php
deleted file mode 100644
index 76034da5..00000000
--- a/src/Core/Dto/User/LoginTokenDto.php
+++ /dev/null
@@ -1,20 +0,0 @@
-token = $token;
- }
-}
diff --git a/src/Core/Dto/User/LoginValidationFailureMessageDto.php b/src/Core/Dto/User/LoginValidationFailureMessageDto.php
deleted file mode 100644
index 5e2868c6..00000000
--- a/src/Core/Dto/User/LoginValidationFailureMessageDto.php
+++ /dev/null
@@ -1,36 +0,0 @@
-message = $message;
- $this->username = $data['username'] ?? null;
- $this->password = $data['password'] ?? null;
- }
-}
diff --git a/src/Core/Dto/User/UserLogInDataDto.php b/src/Core/Dto/User/UserLogInDataDto.php
deleted file mode 100644
index e5c8b902..00000000
--- a/src/Core/Dto/User/UserLogInDataDto.php
+++ /dev/null
@@ -1,27 +0,0 @@
-username = $username;
- $this->password = $password;
- }
-}
diff --git a/src/Core/Entity/Account/AccountAccessAuthCollectionInterface.php b/src/Core/Entity/Account/AccountAccessAuthCollectionInterface.php
new file mode 100644
index 00000000..173da23d
--- /dev/null
+++ b/src/Core/Entity/Account/AccountAccessAuthCollectionInterface.php
@@ -0,0 +1,16 @@
+ 'Eigentümer',
+ AccountRoles::Administrator => 'Administrator',
+ AccountRoles::Moderator => 'Moderator',
+ AccountRoles::User => 'Benutzer',
+ AccountRoles::Guest => 'Gast'
+ };
+ }
+}
diff --git a/src/Core/Enum/AccountVisibleStatus.php b/src/Core/Enum/AccountVisibleStatus.php
new file mode 100644
index 00000000..f0d1095f
--- /dev/null
+++ b/src/Core/Enum/AccountVisibleStatus.php
@@ -0,0 +1,23 @@
+ 'online',
+ AccountVisibleStatus::NOT_PRESENT => 'Abwesend',
+ AccountVisibleStatus::DO_NOT_DISTURB => 'Bitte nicht stören',
+ AccountVisibleStatus::GHOST => 'unsichtbar',
+ AccountVisibleStatus::PERSONALIZED => 'personalisiert'
+ };
+ }
+}
diff --git a/src/Core/Enum/DataType.php b/src/Core/Enum/DataType.php
new file mode 100644
index 00000000..fca7e15b
--- /dev/null
+++ b/src/Core/Enum/DataType.php
@@ -0,0 +1,19 @@
+jsonMessage = $jsonMessage;
- parent::__construct('', $code, $previous);
+ parent::__construct($logMessage->value, $this->getHttpStatusCode(), $previous);
+ $this->context = $context;
+ $this->responseMessage = $responseMessage;
+ $this->logLevel = $loglevel;
}
- public function getJSonMessage(): array
+ abstract public function getHttpStatusCode(): int;
+
+ public function getContext(): array
+ {
+ return $this->context;
+ }
+
+ public function getResponseMessage(): StatusMessage
+ {
+ return $this->responseMessage;
+ }
+
+ public function getLogLevel(): Level
{
- return $this->jsonMessage;
+ return $this->logLevel;
}
}
diff --git a/src/Core/Exception/HttpHandledInvalidArgumentAsSuccessException.php b/src/Core/Exception/HttpHandledInvalidArgumentAsSuccessException.php
new file mode 100644
index 00000000..5ea924b6
--- /dev/null
+++ b/src/Core/Exception/HttpHandledInvalidArgumentAsSuccessException.php
@@ -0,0 +1,27 @@
+get('config');
- $settings = $settings['database'];
+ $settings = $container->get('config')['database'];
$dsn = $settings['driver'] === 'mysql'
? 'mysql:dbname=' . $settings['dbname'] . ';host=' . $settings['host'] . ';port=' . $settings['port']
@@ -20,7 +25,7 @@ public function __invoke(ContainerInterface $container): PDO
$password = $settings['password'];
$options = [
PDO::ATTR_ERRMODE => $settings['error'],
- PDO::ATTR_EMULATE_PREPARES => false,
+ PDO::ATTR_EMULATE_PREPARES => $settings['emulate_prepares'],
];
return new PDO($dsn, $user, $password, $options);
diff --git a/src/Core/Factory/ErrorResponseFactory.php b/src/Core/Factory/ErrorResponseFactory.php
new file mode 100644
index 00000000..d0c2222a
--- /dev/null
+++ b/src/Core/Factory/ErrorResponseFactory.php
@@ -0,0 +1,51 @@
+getHttpStatusCode();
+ $logLevel = $e->getLogLevel();
+ $logContext = $e->getContext();
+ $responseMessage = $e->getResponseMessage();
+
+ $this->logger->log(
+ $logLevel->value,
+ sprintf('[%d] %s', $statusCode, $e->getMessage()),
+ $logContext
+ );
+ } else {
+ $this->logger->log(
+ Level::Critical,
+ sprintf('[%d] Unhandled exception %s', $statusCode, $e->getMessage()),
+ ['exception' => $e]
+ );
+ }
+
+ $message = HttpResponseMessage::create($statusCode, $responseMessage);
+ return new JsonResponse($message, $message->statusCode);
+ }
+}
diff --git a/src/Core/Factory/LoggerFactory.php b/src/Core/Factory/LoggerFactory.php
deleted file mode 100644
index 35978e94..00000000
--- a/src/Core/Factory/LoggerFactory.php
+++ /dev/null
@@ -1,53 +0,0 @@
-get('config')['logger']['path'];
-
- $date = (new DateTime())->format('Y-m-d');
- $path = rtrim($path, '/') . '/' . $date . '/';
-
- if (!is_dir($path)) {
- mkdir($path, 0775);
- }
-
- $formatter = new Simple(Simple::DEFAULT_FORMAT, 'Y-m-d H:i:s');
-
- $defaultWriter = new Stream($path . 'default.log');
- $defaultWriter->setFormatter($formatter);
-
- $errorWriter = new Stream($path . 'error.log');
- $errorFilter = new Priority(Logger::ERR);
- $errorWriter->addFilter($errorFilter);
- $errorWriter->setFormatter($formatter);
-
- $logger = new Logger();
-
- $logger->addWriter($defaultWriter);
- $logger->addWriter($errorWriter);
-
- $logger->addProcessor(new BaseInformationProcessor());
- $logger->addProcessor(new PsrPlaceholder());
-
- return new PsrLoggerAdapter($logger);
- }
-}
diff --git a/src/Core/Factory/MailFactory.php b/src/Core/Factory/MailFactory.php
index ce2fde8a..140c2c3e 100644
--- a/src/Core/Factory/MailFactory.php
+++ b/src/Core/Factory/MailFactory.php
@@ -4,11 +4,12 @@
use Psr\Container\ContainerInterface;
use Symfony\Component\Mailer\Mailer;
+use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mailer\Transport;
-readonly class MailFactory
+class MailFactory
{
- public function __invoke(ContainerInterface $container): Mailer
+ public function __invoke(ContainerInterface $container): MailerInterface
{
$settings = $container->get('config');
diff --git a/src/Core/Factory/QueryFactory.php b/src/Core/Factory/QueryFactory.php
index 4b88cd3b..063a6deb 100644
--- a/src/Core/Factory/QueryFactory.php
+++ b/src/Core/Factory/QueryFactory.php
@@ -4,10 +4,16 @@
use Envms\FluentPDO\Query;
use PDO;
+use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
+use Psr\Container\NotFoundExceptionInterface;
-readonly class QueryFactory
+class QueryFactory
{
+ /**
+ * @throws ContainerExceptionInterface
+ * @throws NotFoundExceptionInterface
+ */
public function __invoke(ContainerInterface $container): Query
{
return new Query($container->get(PDO::class));
diff --git a/src/Core/Factory/UuidFactory.php b/src/Core/Factory/UuidFactory.php
index 6d926697..cf9e115e 100644
--- a/src/Core/Factory/UuidFactory.php
+++ b/src/Core/Factory/UuidFactory.php
@@ -2,14 +2,12 @@
namespace Core\Factory;
-use Psr\Container\ContainerInterface;
-use Ramsey\Uuid\Uuid;
-use Ramsey\Uuid\UuidInterface;
+use Core\Utils\UuidFactoryInterface;
-readonly class UuidFactory
+class UuidFactory
{
- public function __invoke(ContainerInterface $container): UuidInterface
+ public function __invoke(): UuidFactoryInterface
{
- return Uuid::uuid7();
+ return new \Core\Utils\UuidFactory();
}
}
diff --git a/src/Core/Handler/LoginHandler.php b/src/Core/Handler/LoginHandler.php
deleted file mode 100644
index 31f3f544..00000000
--- a/src/Core/Handler/LoginHandler.php
+++ /dev/null
@@ -1,64 +0,0 @@
-getAttribute(User::AUTHENTICATED_USER);
-
- $token = $this->generateToken(
- $user->uuid->getHex()->toString(),
- $this->tokenSecret,
- $this->tokenDuration,
- );
-
- return new JsonResponse(new LoginTokenDto($token), HTTP::STATUS_OK);
- }
-}
diff --git a/src/Core/Handler/LoginHandlerFactory.php b/src/Core/Handler/LoginHandlerFactory.php
deleted file mode 100644
index 05b90f7f..00000000
--- a/src/Core/Handler/LoginHandlerFactory.php
+++ /dev/null
@@ -1,15 +0,0 @@
-get('config')['token']['auth'];
-
- return new LoginHandler($token['secret'], (int)$token['duration']);
- }
-}
diff --git a/src/Core/Handler/LogoutHandler.php b/src/Core/Handler/LogoutHandler.php
deleted file mode 100644
index c2e37e24..00000000
--- a/src/Core/Handler/LogoutHandler.php
+++ /dev/null
@@ -1,32 +0,0 @@
-getAttribute(User::class);
-
- $data = $this->hydrator->extract($user);
- unset($data['id'], $data['password'], $data['email']);
-
- return new JsonResponse($data, HTTP::STATUS_OK);
- }
-}
diff --git a/src/Core/Handler/UserPasswordChangeHandler.php b/src/Core/Handler/UserPasswordChangeHandler.php
deleted file mode 100644
index 47a8cf03..00000000
--- a/src/Core/Handler/UserPasswordChangeHandler.php
+++ /dev/null
@@ -1,17 +0,0 @@
- 'Password was changed'], HTTP::STATUS_OK);
- }
-}
diff --git a/src/Core/Handler/UserPasswordForgottonHandler.php b/src/Core/Handler/UserPasswordForgottonHandler.php
deleted file mode 100644
index 0b2d2e5d..00000000
--- a/src/Core/Handler/UserPasswordForgottonHandler.php
+++ /dev/null
@@ -1,48 +0,0 @@
-getAttribute(User::class);
-
- $email = (new Email())
- ->from($this->mailSender)
- ->to($user->email)
- ->subject('Password forgotton')
- ->text(
- sprintf(
- 'Follow the link to change your password: %s/user/password/%s',
- $this->projectUri,
- $user->name, /** ToDo implements Token support */
- )
- );
-
- $this->mailer->send($email);
-
- return new JsonResponse(['message' => 'Email was created and sent'], HTTP::STATUS_OK);
- }
-}
diff --git a/src/Core/Handler/UserPasswordForgottonHandlerFactory.php b/src/Core/Handler/UserPasswordForgottonHandlerFactory.php
deleted file mode 100644
index b19bb54f..00000000
--- a/src/Core/Handler/UserPasswordForgottonHandlerFactory.php
+++ /dev/null
@@ -1,18 +0,0 @@
-get(Mailer::class);
- $mailSender = $container->get('config')['mailer']['from'];
- $projectUri = $container->get('config')['project']['uri'];
-
- return new UserPasswordForgottonHandler($mailer, $mailSender, $projectUri);
- }
-}
diff --git a/src/Core/Handler/UserPasswordVerifyTokenHandler.php b/src/Core/Handler/UserPasswordVerifyTokenHandler.php
deleted file mode 100644
index a9c0b05f..00000000
--- a/src/Core/Handler/UserPasswordVerifyTokenHandler.php
+++ /dev/null
@@ -1,17 +0,0 @@
- 'Token verification successful'], HTTP::STATUS_OK);
- }
-}
diff --git a/src/Core/Handler/UserRegisterSubmitHandler.php b/src/Core/Handler/UserRegisterSubmitHandler.php
deleted file mode 100644
index 148ad2ea..00000000
--- a/src/Core/Handler/UserRegisterSubmitHandler.php
+++ /dev/null
@@ -1,33 +0,0 @@
- 'Account was created'], HTTP::STATUS_OK);
- }
-}
diff --git a/src/Core/Hydrator/ClassMethodsHydratorFactory.php b/src/Core/Hydrator/ClassMethodsHydratorFactory.php
deleted file mode 100644
index b19b4cd7..00000000
--- a/src/Core/Hydrator/ClassMethodsHydratorFactory.php
+++ /dev/null
@@ -1,14 +0,0 @@
-get(DateTimeFormatterStrategy::class);
-
- return new NullableStrategy($dateTimeFormatterStrategy);
- }
-}
diff --git a/src/Core/Hydrator/ReflectionHydrator.php b/src/Core/Hydrator/ReflectionHydrator.php
deleted file mode 100644
index db839053..00000000
--- a/src/Core/Hydrator/ReflectionHydrator.php
+++ /dev/null
@@ -1,49 +0,0 @@
-hydrate($data, $className);
- }
- }
-
- return $hydratedList;
- }
-
- public function hydrate(bool|array $data, string|object $object): ?object
- {
- if (!$data) {
- return null;
- }
-
- if (!is_object($object)) {
- $object = new ReflectionClass($object);
- $object = $object->newInstanceWithoutConstructor();
- }
-
- return parent::hydrate($data, $object);
- }
-
- public function extractList(array $data): array
- {
- $extractedList = [];
-
- foreach ($data as $value) {
- if (is_object($value)) {
- $extractedList[] = $this->extract($value);
- }
- }
- return $extractedList;
- }
-}
diff --git a/src/Core/Hydrator/Strategy/UuidStrategy.php b/src/Core/Hydrator/Strategy/UuidStrategy.php
deleted file mode 100644
index 0bd5a9a9..00000000
--- a/src/Core/Hydrator/Strategy/UuidStrategy.php
+++ /dev/null
@@ -1,47 +0,0 @@
-getHex()->toString();
- }
-
- public function hydrate($value, ?array $data)
- {
- if ($value instanceof UuidInterface) {
- return $value;
- }
-
- if (!is_string($value)) {
- throw new InvalidArgumentException(
- sprintf(
- 'Value must be string; %s provided',
- get_debug_type($value)
- )
- );
- }
-
- return Uuid::fromString($value);
- }
-}
diff --git a/src/Core/Listener/LoggingErrorListener.php b/src/Core/Listener/LoggingErrorListener.php
deleted file mode 100644
index 2c4d3148..00000000
--- a/src/Core/Listener/LoggingErrorListener.php
+++ /dev/null
@@ -1,32 +0,0 @@
-getServerParams();
-
- $this->logger->error(
- '{Host} Code: {Code} - Message: {Message}',
- [
- 'user-agent' => $serverParams['HTTP_USER_AGENT'],
- 'Code' => $error->getCode(),
- 'Message' => $error->getMessage(),
- ],
- );
- }
-}
diff --git a/src/Core/Listener/LoggingErrorListenerDelegatorFactory.php b/src/Core/Listener/LoggingErrorListenerDelegatorFactory.php
deleted file mode 100644
index 3fc7da4b..00000000
--- a/src/Core/Listener/LoggingErrorListenerDelegatorFactory.php
+++ /dev/null
@@ -1,17 +0,0 @@
-get(LoggingErrorListener::class);
- $errorHandler = $callback();
- $errorHandler->attachListener($listener);
- return $errorHandler;
- }
-}
diff --git a/src/Core/Listener/LoggingErrorListenerFactory.php b/src/Core/Listener/LoggingErrorListenerFactory.php
deleted file mode 100644
index 2e56cf95..00000000
--- a/src/Core/Listener/LoggingErrorListenerFactory.php
+++ /dev/null
@@ -1,16 +0,0 @@
-get(LoggerInterface::class);
-
- return new LoggingErrorListener($logger);
- }
-}
diff --git a/src/Core/Logger/BaseInformationProcessor.php b/src/Core/Logger/BaseInformationProcessor.php
deleted file mode 100644
index 470baa38..00000000
--- a/src/Core/Logger/BaseInformationProcessor.php
+++ /dev/null
@@ -1,29 +0,0 @@
-get('config')['logger']['path'];
+
+ $date = (new DateTime())->format('Y-m-d');
+ $path = rtrim($path, '/') . '/' . $date . '/';
+
+ if (!is_dir($path)) {
+ mkdir($path, 0775);
+ }
+
+ $dateFormat = 'Y-m-d H:i:s';
+ $output = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n";
+ $formatter = new LineFormatter($output, $dateFormat);
+ $stackTraceFormater = clone $formatter;
+ $stackTraceFormater->includeStacktraces(true);
+
+ $logger = new Logger('log');
+
+ $logger->pushHandler(new StreamHandler($path . 'default.log')->setFormatter($formatter));
+
+ $errorHandler = new StreamHandler($path . 'error.log', Level::Error)->setFormatter($formatter);
+ $errorHandler = new FilterHandler($errorHandler, Level::Error, Level::Error);
+
+ $logger->pushHandler($errorHandler);
+
+ $errorHandler = new StreamHandler($path . 'warning.log', Level::Warning)->setFormatter($formatter);
+ $errorHandler = new FilterHandler($errorHandler, Level::Error, Level::Error);
+
+ $logger->pushHandler($errorHandler);
+
+ $logger->pushHandler(
+ new StreamHandler($path . 'critical.log', Level::Critical)->setFormatter($stackTraceFormater)
+ );
+ $logger->pushProcessor(new PsrLogMessageProcessor());
+ $logger->pushProcessor(
+ new MetaDataProcessor(
+ filter_input(INPUT_SERVER, 'REMOTE_ADDR'),
+ filter_input(INPUT_SERVER, 'REQUEST_URI'),
+ filter_input(INPUT_SERVER, 'REQUEST_METHOD'),
+ filter_input(INPUT_SERVER, 'REDIRECT_URL'),
+ filter_input_array(INPUT_GET)
+ )
+ );
+ return $logger;
+ }
+}
diff --git a/src/Core/Logger/MetaDataProcessor.php b/src/Core/Logger/MetaDataProcessor.php
new file mode 100644
index 00000000..ff02b90f
--- /dev/null
+++ b/src/Core/Logger/MetaDataProcessor.php
@@ -0,0 +1,29 @@
+extra['Remote'] = $this->remoteAddr;
+ $record->extra['URI'] = $this->uri;
+ $record->extra['Method'] = $this->method;
+ $record->extra['Redirect'] = $this->redirect;
+ $record->extra['Query'] = $this->query;
+
+ return $record;
+ }
+}
diff --git a/src/Core/Middleware/ApiAccessMiddleware.php b/src/Core/Middleware/ApiAccessMiddleware.php
deleted file mode 100644
index 7df0c0ab..00000000
--- a/src/Core/Middleware/ApiAccessMiddleware.php
+++ /dev/null
@@ -1,30 +0,0 @@
-getHeader('Host')[0])[0];
-
- if (!$this->apiAccessService->hasAccessRights($domain)) {
- return new JsonResponse(['message' => 'No access authorization'], HTTP::STATUS_UNAUTHORIZED);
- }
-
- return $handler->handle($request);
- }
-}
diff --git a/src/Core/Exception/HttpExceptionMiddleware.php b/src/Core/Middleware/ApiErrorHandlerMiddleware.php
similarity index 52%
rename from src/Core/Exception/HttpExceptionMiddleware.php
rename to src/Core/Middleware/ApiErrorHandlerMiddleware.php
index 33f814df..a9371244 100644
--- a/src/Core/Exception/HttpExceptionMiddleware.php
+++ b/src/Core/Middleware/ApiErrorHandlerMiddleware.php
@@ -1,21 +1,27 @@
handle($request);
- } catch (HttpException $e) {
- return new JsonResponse($e->getJSonMessage(), $e->getCode());
+ } catch (Throwable $e) {
+ return $this->errorResponseFactory->createFromThrowable($e);
}
}
}
diff --git a/src/Core/Middleware/IsLoggedInAuthenticationMiddleware.php b/src/Core/Middleware/IsLoggedInAuthenticationMiddleware.php
deleted file mode 100644
index 96feafb5..00000000
--- a/src/Core/Middleware/IsLoggedInAuthenticationMiddleware.php
+++ /dev/null
@@ -1,29 +0,0 @@
-getAttribute(User::AUTHENTICATED_USER);
-
- if (!$user) {
- return new JsonResponse(new SimpleMessageDto('Authentication is required'), HTTP::STATUS_UNAUTHORIZED);
- }
-
- return $handler->handle($request);
- }
-}
diff --git a/src/Core/Middleware/JwtAuthenticationMiddleware.php b/src/Core/Middleware/JwtAuthenticationMiddleware.php
deleted file mode 100644
index 2cae4b3d..00000000
--- a/src/Core/Middleware/JwtAuthenticationMiddleware.php
+++ /dev/null
@@ -1,60 +0,0 @@
-getHeaderLine('Authorization');
- $token = substr($token, 7);
-
- $user = null;
-
- if ($token) {
- try {
- $tokenData = JWT::decode($token, new Key($this->tokenSecret, $this->tokenAlgorithmus));
- } catch (ExpiredException $e) {
- $this->logger->notice(
- '{Host} has call {URI} with expired Token',
- [
- 'Host' => $request->getServerParams()['HTTP_HOST'],
- 'URI' => $request->getServerParams()['REQUEST_URI'],
- ]
- );
- return new JsonResponse(['message' => 'invalid Token'], HTTP::STATUS_UNAUTHORIZED);
- }
-
- $user = $this->userService->findByUuid($tokenData->uuid);
- }
-
- $this->logger->info('{Host} as {User} call -> {URI}', [
- 'User' => $user ? $user->name : 'Guest',
- ]);
-
- return $handler->handle($request->withAttribute(User::AUTHENTICATED_USER, $user));
- }
-}
diff --git a/src/Core/Middleware/JwtAuthenticationMiddlewareFactory.php b/src/Core/Middleware/JwtAuthenticationMiddlewareFactory.php
deleted file mode 100644
index 1d916e19..00000000
--- a/src/Core/Middleware/JwtAuthenticationMiddlewareFactory.php
+++ /dev/null
@@ -1,24 +0,0 @@
-get(UserService::class);
- $token = $container->get('config')['token']['auth'];
- $logger = $container->get(LoggerInterface::class);
-
- return new JwtAuthenticationMiddleware(
- $userService,
- $token['secret'],
- $token['algorithmus'],
- $logger,
- );
- }
-}
diff --git a/src/Core/Middleware/LoginAuthenticationMiddleware.php b/src/Core/Middleware/LoginAuthenticationMiddleware.php
deleted file mode 100644
index ab4efbda..00000000
--- a/src/Core/Middleware/LoginAuthenticationMiddleware.php
+++ /dev/null
@@ -1,41 +0,0 @@
-getParsedBody();
-
- $name = $data['username'];
- $password = $data['password'];
-
- $user = $this->userService->findByName($name);
-
- if (!($user instanceof User) || !$this->authService->isUserDataCorrect($user, $password)) {
- return new JsonResponse(new SimpleMessageDto('Login failed'), HTTP::STATUS_UNAUTHORIZED);
- }
-
- return $handler->handle(
- $request->withAttribute(User::AUTHENTICATED_USER, $user)
- );
- }
-}
diff --git a/src/Core/Middleware/LoginValidationMiddleware.php b/src/Core/Middleware/LoginValidationMiddleware.php
deleted file mode 100644
index 5acb8896..00000000
--- a/src/Core/Middleware/LoginValidationMiddleware.php
+++ /dev/null
@@ -1,37 +0,0 @@
-getParsedBody();
-
- $this->validator->setData($data);
-
- if (!$this->validator->isValid()) {
- // ToDo $this->validator->getMessage()
- return new JsonResponse(
- new LoginValidationFailureMessageDto('Login failed', $data),
- HTTP::STATUS_BAD_REQUEST
- );
- }
-
- return $handler->handle($request->withParsedBody($this->validator->getValues()));
- }
-}
diff --git a/src/App/Middleware/Topic/TopicListMiddleware.php b/src/Core/Middleware/RouteNotFoundMiddleware.php
similarity index 54%
rename from src/App/Middleware/Topic/TopicListMiddleware.php
rename to src/Core/Middleware/RouteNotFoundMiddleware.php
index 3d647d38..aa37efe6 100644
--- a/src/App/Middleware/Topic/TopicListMiddleware.php
+++ b/src/Core/Middleware/RouteNotFoundMiddleware.php
@@ -1,24 +1,24 @@
topicPoolService->findAll();
+ $this->logger->notice('Route not found');
- return $handler->handle($request->withAttribute('topics', $topics));
+ return $handler->handle($request);
}
}
diff --git a/src/Core/Middleware/UpdateLastUserActionTimeMiddleware.php b/src/Core/Middleware/UpdateLastUserActionTimeMiddleware.php
deleted file mode 100644
index 368b5e9b..00000000
--- a/src/Core/Middleware/UpdateLastUserActionTimeMiddleware.php
+++ /dev/null
@@ -1,29 +0,0 @@
-getAttribute(User::AUTHENTICATED_USER);
-
- if ($user instanceof User) {
- $user = $this->userService->updateLastUserActionTime($user);
- }
-
- return $handler->handle($request->withAttribute(User::AUTHENTICATED_USER, $user));
- }
-}
diff --git a/src/Core/Middleware/UserMiddleware.php b/src/Core/Middleware/UserMiddleware.php
deleted file mode 100644
index ef4aa663..00000000
--- a/src/Core/Middleware/UserMiddleware.php
+++ /dev/null
@@ -1,33 +0,0 @@
-getAttribute('userUuid');
-
- $user = $this->userService->findByUuid($userUuid);
-
- if (!$user) {
- return new JsonResponse(['message' => 'User could not be found'], HTTP::STATUS_NOT_FOUND);
- }
-
- return $handler->handle($request->withAttribute(User::class, $user));
- }
-}
diff --git a/src/Core/Middleware/UserPasswordChangeMiddleware.php b/src/Core/Middleware/UserPasswordChangeMiddleware.php
deleted file mode 100644
index 41e7e0b6..00000000
--- a/src/Core/Middleware/UserPasswordChangeMiddleware.php
+++ /dev/null
@@ -1,43 +0,0 @@
-getAttribute(User::class);
-
- $data = $request->getParsedBody();
-
- /** ToDo implements Token support */
- $user = $user->with(['password' => password_hash($data['password'], PASSWORD_BCRYPT)]);
-
- if (!$this->userService->update($user)) {
- return new JsonResponse(['Password could not be changed'], Http::STATUS_BAD_REQUEST);
- }
-
- return $handler->handle($request);
- }
-}
diff --git a/src/Core/Middleware/UserPasswordChangeValidatorMiddleware.php b/src/Core/Middleware/UserPasswordChangeValidatorMiddleware.php
deleted file mode 100644
index f0e7e4df..00000000
--- a/src/Core/Middleware/UserPasswordChangeValidatorMiddleware.php
+++ /dev/null
@@ -1,35 +0,0 @@
-getParsedBody();
-
- $this->validator->setData($data);
-
- if (!$this->validator->isValid()) {
- return new JsonResponse([
- 'message' => 'Validation fault',
- 'data' => $this->validator->getMessages(),
- ], HTTP::STATUS_NOT_FOUND);
- }
-
- return $handler->handle($request->withParsedBody($this->validator->getValues()));
- }
-}
diff --git a/src/Core/Middleware/UserPasswordForgottenMiddleware.php b/src/Core/Middleware/UserPasswordForgottenMiddleware.php
deleted file mode 100644
index 93e7e94f..00000000
--- a/src/Core/Middleware/UserPasswordForgottenMiddleware.php
+++ /dev/null
@@ -1,40 +0,0 @@
-getParsedBody();
-
- $user = $this->userService->findByEMail($data['email']);
-
- if (!$user) {
- return new JsonResponse(['message' => 'invalid E-Mai'], HTTP::STATUS_BAD_REQUEST);
- }
-
- /** ToDo implements Token support */
- $this->tokenService->generateToken();
-
- $this->userService->update($user);
-
- return $handler->handle($request->withAttribute(User::class, $user));
- }
-}
diff --git a/src/Core/Middleware/UserPasswordForgottenValidator.php b/src/Core/Middleware/UserPasswordForgottenValidator.php
deleted file mode 100644
index 73a07a27..00000000
--- a/src/Core/Middleware/UserPasswordForgottenValidator.php
+++ /dev/null
@@ -1,35 +0,0 @@
-getParsedBody();
-
- $this->validator->setData($data);
-
- if (!$this->validator->isValid()) {
- return new JsonResponse([
- 'message' => 'Validation fault',
- 'data' => $this->validator->getMessages(),
- ], HTTP::STATUS_NOT_FOUND);
- }
-
- return $handler->handle($request->withParsedBody($this->validator->getValues()));
- }
-}
diff --git a/src/Core/Middleware/UserPasswordVerifyTokenMiddleware.php b/src/Core/Middleware/UserPasswordVerifyTokenMiddleware.php
deleted file mode 100644
index e28ece53..00000000
--- a/src/Core/Middleware/UserPasswordVerifyTokenMiddleware.php
+++ /dev/null
@@ -1,37 +0,0 @@
-getAttribute('token');
-
- /** ToDo implements Token */
- $user = $this->userService->findById($token);
-
- if (!$user instanceof User) {
- return new JsonResponse(
- ['message' => 'Password cannot be changed due to invalid token'],
- HTTP::STATUS_BAD_REQUEST
- );
- }
-
- return $handler->handle($request->withAttribute(User::class, $user));
- }
-}
diff --git a/src/Core/Middleware/UserRegisterMiddleware.php b/src/Core/Middleware/UserRegisterMiddleware.php
deleted file mode 100644
index a70aa2ba..00000000
--- a/src/Core/Middleware/UserRegisterMiddleware.php
+++ /dev/null
@@ -1,64 +0,0 @@
-getParsedBody();
- $newUser = [
- 'id' => 1,
- 'uuid' => $this->uuid,
- 'role' => UserRole::GUEST,
- 'name' => '',
- 'password' => '',
- 'email' => $data['e-mail'],
- 'registrationAt' => new DateTime(),
- 'lastActionAt' => new DateTime(),
- ];
-
- $user = $this->hydrator->hydrate($newUser, User::class);
-
- try {
- !$this->userService->create($user);
- } catch (DuplicateEntryException $exception) {
- $validationMessages = [
- 'email' => [
- 'message' => 'Invalid registration data',
- ],
- ];
-
- return new JsonResponse(
- new HttpStatusCodeMessage(
- $exception->getCode(),
- 'Registration failed',
- $validationMessages
- ),
- $exception->getCode()
- );
- }
- return $handler->handle($request);
- }
-}
diff --git a/src/Core/Middleware/UserRegisterValidationMiddleware.php b/src/Core/Middleware/UserRegisterValidationMiddleware.php
deleted file mode 100644
index ba4e1510..00000000
--- a/src/Core/Middleware/UserRegisterValidationMiddleware.php
+++ /dev/null
@@ -1,39 +0,0 @@
-getParsedBody();
-
- $this->validator->setData($data);
-
- if (!$this->validator->isValid()) {
- return new JsonResponse([
- new HttpStatusCodeMessage(
- HTTP::STATUS_BAD_REQUEST,
- 'Registration failed',
- $this->validator->getMessages()
- ),
- ], HTTP::STATUS_BAD_REQUEST);
- }
-
- return $handler->handle($request->withParsedBody($this->validator->getValues()));
- }
-}
diff --git a/src/Core/Repository/AccountAccessAuthRepositoryInterface.php b/src/Core/Repository/AccountAccessAuthRepositoryInterface.php
new file mode 100644
index 00000000..6258aa2e
--- /dev/null
+++ b/src/Core/Repository/AccountAccessAuthRepositoryInterface.php
@@ -0,0 +1,29 @@
+apiAccessConfig['domain']['whitelist'], true);
- }
-}
diff --git a/src/Core/Service/ApiAccessServiceFactory.php b/src/Core/Service/ApiAccessServiceFactory.php
deleted file mode 100644
index 32f7ecb9..00000000
--- a/src/Core/Service/ApiAccessServiceFactory.php
+++ /dev/null
@@ -1,15 +0,0 @@
-get('config')['api']['access'];
-
- return new ApiAccessService($apiAccessConfig);
- }
-}
diff --git a/src/Core/Service/LoginAuthenticationService.php b/src/Core/Service/LoginAuthenticationService.php
deleted file mode 100644
index 6c006da3..00000000
--- a/src/Core/Service/LoginAuthenticationService.php
+++ /dev/null
@@ -1,19 +0,0 @@
-password);
- }
-}
diff --git a/src/Core/Store/AccountAccessAuthStoreInterface.php b/src/Core/Store/AccountAccessAuthStoreInterface.php
new file mode 100644
index 00000000..73487b96
--- /dev/null
+++ b/src/Core/Store/AccountAccessAuthStoreInterface.php
@@ -0,0 +1,29 @@
+table = substr((new ReflectionClass($this))->getShortName(), 0, -5);
- }
-
- public function getTableName(): string
- {
- return $this->table;
- }
-
- public function findById(int $id): array
- {
- $result = $this->query->from($this->table)
- ->where('id', $id)
- ->fetch();
-
- return $result ?: [];
- }
-
- public function findAll(): array
- {
- $result = $this->query->from($this->table)->fetchAll();
-
- return $result ?: [];
- }
-}
diff --git a/src/Core/Table/UserTable.php b/src/Core/Table/UserTable.php
deleted file mode 100644
index fca4e705..00000000
--- a/src/Core/Table/UserTable.php
+++ /dev/null
@@ -1,93 +0,0 @@
- $user->uuid->getHex()->toString(),
- 'roleId' => $user->role->value,
- 'name' => $user->name,
- 'password' => $user->password,
- 'email' => $user->email,
- ];
-
- $lastInsertId = $this->query->insertInto($this->table, $values)->execute();
-
- if (!$lastInsertId) {
- return throw new DuplicateEntryException('User', $user->uuid->getHex()->toString());
- }
-
- return (int)$lastInsertId;
- }
-
- public function update(User $user): int
- {
- $values = [
- 'uuid' => $user->uuid,
- 'roleId' => $user->role->value,
- 'name' => $user->name,
- 'password' => $user->password,
- 'email' => $user->email,
- 'registrationAt' => $user->registrationAt->format('Y-m-d H:i:s'),
- 'lastActionAt' => $user->lastActionAt->format('Y-m-d H:i:s'),
- ];
-
- $affectedRowCount = $this->query->update($this->table, $values, $user->id)->execute();
-
- if (!$affectedRowCount) {
- throw new InvalidArgumentException('User data could not be modified');
- }
-
- return (int)$affectedRowCount;
- }
-
- public function updateLastUserActionTime(int $id, DateTime $actionTime): self
- {
- $result = $this->query->update($this->table)
- ->set(['lastActionAt' => $actionTime->format('Y-m-d H:i:s')])
- ->where('id', $id)
- ->execute();
-
- if (!$result) {
- throw new InvalidArgumentException('User data could not be modified');
- }
-
- return $this;
- }
-
- public function findByUuid(string $uuid): array
- {
- $result = $this->query->from($this->table)
- ->where('uuid', $uuid)
- ->fetch();
-
- return $result ?: [];
- }
-
- public function findByName(string $name): array
- {
- $result = $this->query->from($this->table)
- ->where('name', $name)
- ->fetch();
-
- return $result ?: [];
- }
-
- public function findByEMail(string $email): array
- {
- $result = $this->query->from($this->table)
- ->where('email', $email)
- ->fetch();
-
- return $result ?: [];
- }
-}
diff --git a/src/Core/Token/JwtTokenGeneratorTrait.php b/src/Core/Token/JwtTokenGeneratorTrait.php
deleted file mode 100644
index fca83751..00000000
--- a/src/Core/Token/JwtTokenGeneratorTrait.php
+++ /dev/null
@@ -1,26 +0,0 @@
- $now,
- 'exp' => $now + $timeout,
-
- 'uuid' => $uuid,
- ],
- $tokenSecret,
- $alg
- );
- }
-}
diff --git a/src/Core/Token/TokenService.php b/src/Core/Token/TokenService.php
deleted file mode 100644
index 0d55c8cf..00000000
--- a/src/Core/Token/TokenService.php
+++ /dev/null
@@ -1,14 +0,0 @@
-value = $value instanceof self ? (string)$value : $this->prepareValue($value);
+ }
+
+ public function toString(): string
+ {
+ return $this->value;
+ }
+
+ public function __toString(): string
+ {
+ return $this->toString();
+ }
+
+ public function serialize(): string
+ {
+ return $this->toString();
+ }
+
+ public function __serialize(): array
+ {
+ return ['string' => $this->toString()];
+ }
+
+ public function unserialize(string $data): void
+ {
+ $this->__construct($data);
+ }
+
+ public function __unserialize(array $data): void
+ {
+ // @codeCoverageIgnoreStart
+ if (!isset($data['string'])) {
+ throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__));
+ }
+ // @codeCoverageIgnoreEnd
+
+ $this->unserialize($data['string']);
+ }
+
+ public function jsonSerialize(): string
+ {
+ return $this->toString();
+ }
+
+ private function prepareValue(string $value): string
+ {
+ if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
+ throw new HttpInvalidArgumentException(
+ LogMessage::EMAIL_FORMAT_REQUIRED,
+ StatusMessage::INVALID_DATA,
+ [
+ 'email' => $value,
+ ]
+ );
+ }
+
+ return $value;
+ }
+}
diff --git a/src/Core/Type/TypeInterface.php b/src/Core/Type/TypeInterface.php
new file mode 100644
index 00000000..7f7c9ae9
--- /dev/null
+++ b/src/Core/Type/TypeInterface.php
@@ -0,0 +1,13 @@
+ $collection
+ */
+ protected array $collection = [];
+ private int $position = 0;
+
+ public function offsetExists(mixed $offset): bool
+ {
+ return isset($this->collection[$offset]);
+ }
+
+ /**
+ * @throws UndefinedOffsetException
+ */
+ public function offsetGet(mixed $offset): mixed
+ {
+ if (!$this->offsetExists($offset)) {
+ throw new UndefinedOffsetException(
+ sprintf('Undefined offset: %s in Collection %s on Line %s', $offset, __FILE__, __LINE__)
+ );
+ }
+
+ return $this->collection[$offset];
+ }
+
+ public function offsetSet(mixed $offset, mixed $value): void
+ {
+ is_null($offset)
+ ? $this->collection[] = $value
+ : $this->collection[$offset] = $value;
+ }
+
+ public function offsetUnset(mixed $offset): void
+ {
+ unset($this->collection[$offset]);
+ }
+
+ public function current(): mixed
+ {
+ return $this->collection[$this->position];
+ }
+
+ public function next(): void
+ {
+ $this->position++;
+ }
+
+ public function key(): int
+ {
+ return $this->position;
+ }
+
+ public function valid(): bool
+ {
+ return $this->offsetExists($this->position);
+ }
+
+ public function rewind(): void
+ {
+ $this->position = 0;
+ }
+
+ public function count(): int
+ {
+ return count($this->collection);
+ }
+
+ public function first(): mixed
+ {
+ $collection = $this->collection;
+ return array_shift($collection);
+ }
+
+ public function last(): mixed
+ {
+ $collection = $this->collection;
+ return array_pop($collection);
+ }
+
+ /**
+ * @return array
+ */
+ public function filter(Closure $function): array
+ {
+ return array_filter($this->collection, $function);
+ }
+
+ public function getElements(): array
+ {
+ return $this->collection;
+ }
+
+ public function jsonSerialize(): array
+ {
+ return $this->getElements();
+ }
+}
diff --git a/src/Core/Utils/CollectionInterface.php b/src/Core/Utils/CollectionInterface.php
new file mode 100644
index 00000000..9e838aa7
--- /dev/null
+++ b/src/Core/Utils/CollectionInterface.php
@@ -0,0 +1,12 @@
+setRequired(true);
-
- $this->getFilterChain()->attachByName('StringTrim');
-
- $this->getValidatorChain()->attachByName(
- 'StringLength',
- [
- 'encoding' => 'UTF-8',
- 'min' => 3,
- 'max' => 50,
- ]
- );
- }
-}
diff --git a/src/Core/Validator/LoginValidator.php b/src/Core/Validator/LoginValidator.php
deleted file mode 100644
index f8584b4a..00000000
--- a/src/Core/Validator/LoginValidator.php
+++ /dev/null
@@ -1,18 +0,0 @@
-add($this->usernameInput);
- $this->add($this->passwordInput);
- }
-}
diff --git a/src/Core/Validator/PasswordForgottenEmailValidator.php b/src/Core/Validator/PasswordForgottenEmailValidator.php
deleted file mode 100644
index d032a063..00000000
--- a/src/Core/Validator/PasswordForgottenEmailValidator.php
+++ /dev/null
@@ -1,15 +0,0 @@
-add($this->emailInput);
- }
-}
diff --git a/tests/Data/Entity/EventTestEntity.php b/tests/Data/Entity/EventTestEntity.php
deleted file mode 100644
index d2f9c83a..00000000
--- a/tests/Data/Entity/EventTestEntity.php
+++ /dev/null
@@ -1,28 +0,0 @@
- TestConstants::EVENT_ID,
- 'uuid' => UuidV7::fromString(TestConstants::EVENT_UUID),
- 'userId' => TestConstants::USER_ID,
- 'title' => TestConstants::EVENT_TITLE,
- 'description' => TestConstants::EVENT_DESCRIPTION,
- 'eventText' => TestConstants::EVENT_TEXT,
- 'createdAt' => new DateTimeImmutable(TestConstants::TIME),
- 'startedAt' => new DateTimeImmutable(TestConstants::TIME),
- 'duration' => TestConstants::EVENT_DURATION,
- 'status' => EventStatus::SOON,
- 'ratingCompleted' => false,
- ];
- }
-}
diff --git a/tests/Data/Entity/ParticipantTestEntity.php b/tests/Data/Entity/ParticipantTestEntity.php
deleted file mode 100644
index f0bf7e23..00000000
--- a/tests/Data/Entity/ParticipantTestEntity.php
+++ /dev/null
@@ -1,21 +0,0 @@
- TestConstants::PARTICIPANT_ID,
- 'userId' => TestConstants::USER_ID,
- 'eventId' => TestConstants::EVENT_ID,
- 'requestedAt' => new DateTimeImmutable(TestConstants::TIME),
- 'subscribed' => true,
- 'disqualified' => false,
- ];
- }
-}
diff --git a/tests/Data/Entity/ProjectTestEntity.php b/tests/Data/Entity/ProjectTestEntity.php
deleted file mode 100644
index 3490b844..00000000
--- a/tests/Data/Entity/ProjectTestEntity.php
+++ /dev/null
@@ -1,24 +0,0 @@
- TestConstants::PROJECT_ID,
- 'uuid' => UuidV7::fromString(TestConstants::PROJECT_UUID),
- 'participantId' => TestConstants::PARTICIPANT_ID,
- 'title' => TestConstants::PROJECT_TITLE,
- 'description' => TestConstants::PROJECT_DESCRIPTION,
- 'createdAt' => new DateTimeImmutable(TestConstants::TIME),
- 'gitRepoUri' => TestConstants::PROJECT_GIT_URL,
- 'demoPageUri' => TestConstants::PROJECT_DEMO_URI,
- ];
- }
-}
diff --git a/tests/Data/Entity/RoleTestEntity.php b/tests/Data/Entity/RoleTestEntity.php
deleted file mode 100644
index 21f57716..00000000
--- a/tests/Data/Entity/RoleTestEntity.php
+++ /dev/null
@@ -1,19 +0,0 @@
- TestConstants::ROLE_ID,
- 'uuid' => UuidV7::fromString(TestConstants::ROLE_UUID),
- 'name' => TestConstants::ROLE_NAME,
- 'description' => TestConstants::ROLE_DESCRIPTION,
- ];
- }
-}
diff --git a/tests/Data/Entity/TopicTestEntity.php b/tests/Data/Entity/TopicTestEntity.php
deleted file mode 100644
index 9ea733a0..00000000
--- a/tests/Data/Entity/TopicTestEntity.php
+++ /dev/null
@@ -1,21 +0,0 @@
- TestConstants::TOPIC_ID,
- 'uuid' => UuidV7::fromString(TestConstants::TOPIC_UUID),
- 'eventId' => TestConstants::EVENT_ID,
- 'topic' => TestConstants::TOPIC_TITLE,
- 'description' => TestConstants::TOPIC_DESCRIPTION,
- 'accepted' => true,
- ];
- }
-}
diff --git a/tests/Data/Entity/UserTestEntity.php b/tests/Data/Entity/UserTestEntity.php
deleted file mode 100644
index d5e79eda..00000000
--- a/tests/Data/Entity/UserTestEntity.php
+++ /dev/null
@@ -1,25 +0,0 @@
- TestConstants::USER_ID,
- 'uuid' => UuidV7::fromString(TestConstants::USER_UUID),
- 'role' => UserRole::USER,
- 'name' => TestConstants::USER_NAME,
- 'password' => TestConstants::USER_PASSWORD,
- 'email' => TestConstants::USER_EMAIL,
- 'registrationAt' => new DateTimeImmutable(TestConstants::TIME),
- 'lastActionAt' => new DateTimeImmutable(TestConstants::TIME),
- ];
- }
-}
diff --git a/tests/Data/TestConstants.php b/tests/Data/TestConstants.php
deleted file mode 100644
index d2513be7..00000000
--- a/tests/Data/TestConstants.php
+++ /dev/null
@@ -1,110 +0,0 @@
-app = new MezzioTestEnvironment($basePath);
- }
-}
diff --git a/tests/Functional/Root/PingTest.php b/tests/Functional/Root/PingTest.php
deleted file mode 100644
index 70477cf4..00000000
--- a/tests/Functional/Root/PingTest.php
+++ /dev/null
@@ -1,26 +0,0 @@
-app->dispatchRequest($request);
-
- self::assertSame(StatusCodeInterface::STATUS_OK, $response->getStatusCode());
- self::assertJsonValueMatches(
- self::getContentAsJson($response),
- '$.ack',
- self::greaterThanOrEqual(time())
- );
- }
-}
diff --git a/tests/Functional/UserControl/UserMeTest.php b/tests/Functional/UserControl/UserMeTest.php
deleted file mode 100644
index ea361784..00000000
--- a/tests/Functional/UserControl/UserMeTest.php
+++ /dev/null
@@ -1,54 +0,0 @@
-app->dispatchRequest($request);
-
- self::assertSame(StatusCodeInterface::STATUS_OK, $response->getStatusCode());
- self::assertEmpty(self::getContentAsJson($response));
- }
-
- /**
- * ToDo - The Auth Token for verification is still missing here
- */
- public function testMeReturnValidUserByAuthenticatedUser(): void
- {
- $token = $this->app->container()->get('config')['token']['auth'];
-
- $user = new User(
- 1,
- Uuid::uuid7(),
- UserRole::USER,
- 'TestingUser',
- 'myworld',
- 'testing@example.com',
- new DateTimeImmutable(),
- new DateTimeImmutable()
- );
-
- /** @var UserService $userService */
- $userService = $this->app->container()->get(UserService::class);
- $userService->create($user);
-
- $request = new ServerRequest(uri: '/api/user/me', method: 'GET');
-
- $response = $this->app->dispatchRequest($request);
-
- self::assertSame(StatusCodeInterface::STATUS_OK, $response->getStatusCode());
- }
-}
diff --git a/tests/FunctionalTest/AbstractFunctional.php b/tests/FunctionalTest/AbstractFunctional.php
new file mode 100644
index 00000000..bdbd8b9b
--- /dev/null
+++ b/tests/FunctionalTest/AbstractFunctional.php
@@ -0,0 +1,83 @@
+initContainer();
+ $this->initApp();
+ $this->initPipeline();
+ $this->initRoutes();
+ }
+
+ public static function tearDownAfterClass(): void
+ {
+ system('php ' . dirname(__FILE__) . '/bootstrap.php');
+ }
+
+ protected function initContainer(): void
+ {
+ $this->container = require __DIR__ . '/../../config/container.php';
+ }
+
+ protected function initApp(): void
+ {
+ $this->app = $this->container->get(Application::class);
+ }
+
+ protected function initPipeline(): void
+ {
+ $factory = $this->container->get(MiddlewareFactory::class);
+ (require __DIR__ . '/../../config/pipeline.php')($this->app, $factory, $this->container);
+ }
+
+ protected function initRoutes(): void
+ {
+ $factory = $this->container->get(MiddlewareFactory::class);
+ (require __DIR__ . '/../../config/routes.php')($this->app, $factory, $this->container);
+ }
+
+ /**
+ * Override parent method's hard-coded regex
+ */
+ public static function bodyMatchesJson(array $constraints): Constraint
+ {
+ return Assert::logicalAnd(
+ self::hasHeader(
+ 'content-type',
+ Assert::matchesRegularExpression(
+ ',^application/(.+\+)?json(;.+)?$,'
+ )
+ ),
+ self::bodyMatches(
+ Assert::logicalAnd(
+ Assert::isJson(),
+ new JsonValueMatchesMany($constraints)
+ )
+ )
+ );
+ }
+}
diff --git a/tests/Functional/Mock/NullLogger.php b/tests/FunctionalTest/Mock/NullLogger.php
similarity index 59%
rename from tests/Functional/Mock/NullLogger.php
rename to tests/FunctionalTest/Mock/NullLogger.php
index 59f0d6f1..ac8c5631 100644
--- a/tests/Functional/Mock/NullLogger.php
+++ b/tests/FunctionalTest/Mock/NullLogger.php
@@ -1,17 +1,17 @@
accountRepository = $this->container->get(AccountRepositoryInterface::class);
+ $this->accountAccessAuthRepository = $this->container->get(AccountAccessAuthRepository::class);
+ $this->clientIdentificationService = $this->container->get(ClientIdentificationService::class);
+ $this->clientIdentificationData = ClientIdentificationData::create(
+ self::CLIENT_IDENTIFICATION,
+ self::USER_AGENT
+ );
+ $clientIdentifcationHash = $this->clientIdentificationService->getClientIdentificationHash(
+ $this->clientIdentificationData
+ );
+ $this->clientIdentification = ClientIdentification::create(
+ $this->clientIdentificationData,
+ $clientIdentifcationHash
+ );
+ $this->refreshTokenService = $this->container->get(RefreshTokenService::class);
+ $this->accessTokenService = $this->container->get(AccessTokenService::class);
+ $this->refreshToken = $this->refreshTokenService->generate($this->clientIdentification);
+ /** @var Query $query */
+ $query = $this->container->get(Query::class);
+ $this->PDO = $query->getPdo();
+ }
+
+ public function testReturnANewAccessToken(): void
+ {
+ $userAccount = $this->accountRepository->findByName('User');
+ $accountAccessAuth = new AccountAccessAuth(
+ null,
+ $userAccount->id,
+ 'Testing',
+ $this->refreshToken,
+ self::USER_AGENT,
+ $this->clientIdentificationService->getClientIdentificationHash($this->clientIdentificationData),
+ new DateTimeImmutable()
+ );
+ $this->accountAccessAuthRepository->insert($accountAccessAuth);
+ $accountAccessAuthId = (int)$this->PDO->lastInsertId();
+
+ $request = new ServerRequest(
+ uri: '/api/token/refresh',
+ method: 'GET',
+ headers: [
+ 'x-ident' => self::CLIENT_IDENTIFICATION,
+ 'Authentication' => $this->refreshToken,
+ 'User-Agent' => self::USER_AGENT,
+ ]
+ );
+
+ $response = $this->app->handle($request);
+ $content = $this->getContentAsJson($response);
+
+ $this->assertSame(HTTP::STATUS_OK, $response->getStatusCode());
+ $this->assertThat($response, $this->bodyMatchesJson([
+ 'accessToken' => Assert::isType('string'),
+ ]));
+
+ $isAccessToken = $this->accessTokenService->isValid($content['accessToken']);
+
+ $this->assertTrue($isAccessToken);
+
+ $this->accountAccessAuthRepository->deleteById($accountAccessAuthId);
+ }
+
+ public function testGivenRefreshTokenIsInvalid(): void
+ {
+ $userAccount = $this->accountRepository->findByName('User');
+ $accountAccessAuth = new AccountAccessAuth(
+ null,
+ $userAccount->id,
+ 'Testing',
+ $this->refreshToken,
+ self::USER_AGENT,
+ $this->clientIdentificationService->getClientIdentificationHash($this->clientIdentificationData),
+ new DateTimeImmutable()
+ );
+ $this->accountAccessAuthRepository->insert($accountAccessAuth);
+ $accountAccessAuthId = (int)$this->PDO->lastInsertId();
+
+ $request = new ServerRequest(
+ uri: '/api/token/refresh',
+ method: 'GET',
+ headers: [
+ 'x-ident' => self::CLIENT_IDENTIFICATION,
+ 'Authentication' => self::INVALID_REFRESH_TOKEN,
+ 'User-Agent' => self::USER_AGENT,
+ ]
+ );
+
+ $response = $this->app->handle($request);
+ $content = $this->getContentAsJson($response);
+
+ $this->assertSame(HTTP::STATUS_UNAUTHORIZED, $response->getStatusCode());
+ $this->assertSame(StatusMessage::TOKEN_INVALID->value, $content['message']);
+
+ $this->accountAccessAuthRepository->deleteById($accountAccessAuthId);
+ }
+
+ public function testGivenRefreshTokenIsExpired(): void
+ {
+ $userAccount = $this->accountRepository->findByName('User');
+ $accountAccessAuth = new AccountAccessAuth(
+ 1,
+ $userAccount->id,
+ 'Testing',
+ $this->refreshToken,
+ self::USER_AGENT,
+ $this->clientIdentificationService->getClientIdentificationHash($this->clientIdentificationData),
+ new DateTimeImmutable()
+ );
+ $this->accountAccessAuthRepository->insert($accountAccessAuth);
+ $accountAccessAuthId = (int)$this->PDO->lastInsertId();
+
+ $request = new ServerRequest(
+ uri: '/api/token/refresh',
+ method: 'GET',
+ headers: [
+ 'x-ident' => self::CLIENT_IDENTIFICATION,
+ 'Authentication' => self::EXPIRED_REFRESH_TOKEN,
+ 'User-Agent' => self::USER_AGENT,
+ ]
+ );
+
+ $response = $this->app->handle($request);
+ $content = $this->getContentAsJson($response);
+
+ $this->assertSame(HTTP::STATUS_UNAUTHORIZED, $response->getStatusCode());
+ $this->assertSame(StatusMessage::TOKEN_INVALID->value, $content['message']);
+
+ $this->accountAccessAuthRepository->deleteById($accountAccessAuthId);
+ }
+
+ public function testGivenRefreshTokenIsNotPersistenInDatabase(): void
+ {
+ $request = new ServerRequest(
+ uri: '/api/token/refresh',
+ method: 'GET',
+ headers: [
+ 'x-ident' => self::CLIENT_IDENTIFICATION,
+ 'Authentication' => $this->refreshToken,
+ 'User-Agent' => self::USER_AGENT,
+ ]
+ );
+
+ $response = $this->app->handle($request);
+ $content = $this->getContentAsJson($response);
+
+ $this->assertSame(HTTP::STATUS_UNAUTHORIZED, $response->getStatusCode());
+ $this->assertSame(StatusMessage::TOKEN_NOT_PERSISTENT->value, $content['message']);
+ }
+
+ public function testUnexpectedClientIdentification(): void
+ {
+ $userAccount = $this->accountRepository->findByName('User');
+ $accountAccessAuth = new AccountAccessAuth(
+ 1,
+ $userAccount->id,
+ 'Testing',
+ $this->refreshToken,
+ self::USER_AGENT,
+ $this->clientIdentificationService->getClientIdentificationHash($this->clientIdentificationData),
+ new DateTimeImmutable()
+ );
+ $this->accountAccessAuthRepository->insert($accountAccessAuth);
+ $accountAccessAuthId = (int)$this->PDO->lastInsertId();
+
+ $request = new ServerRequest(
+ uri: '/api/token/refresh',
+ method: 'GET',
+ headers: [
+ 'x-ident' => self::UNEXPECTED_CLIENT_IDENTIFICATION,
+ 'Authentication' => $this->refreshToken,
+ 'User-Agent' => self::USER_AGENT,
+ ]
+ );
+
+ $response = $this->app->handle($request);
+ $content = $this->getContentAsJson($response);
+
+ $this->assertSame(HTTP::STATUS_UNAUTHORIZED, $response->getStatusCode());
+ $this->assertSame(StatusMessage::CLIENT_UNEXPECTED->value, $content['message']);
+
+ $this->accountAccessAuthRepository->deleteById($accountAccessAuthId);
+ }
+
+ public function testUnexpectedUserAgent(): void
+ {
+ $userAccount = $this->accountRepository->findByName('User');
+ $accountAccessAuth = new AccountAccessAuth(
+ 1,
+ $userAccount->id,
+ 'Testing',
+ $this->refreshToken,
+ self::USER_AGENT,
+ $this->clientIdentificationService->getClientIdentificationHash($this->clientIdentificationData),
+ new DateTimeImmutable()
+ );
+ $this->accountAccessAuthRepository->insert($accountAccessAuth);
+ $accountAccessAuthId = (int)$this->PDO->lastInsertId();
+
+ $request = new ServerRequest(
+ uri: '/api/token/refresh',
+ method: 'GET',
+ headers: [
+ 'x-ident' => self::CLIENT_IDENTIFICATION,
+ 'Authentication' => $this->refreshToken,
+ 'User-Agent' => self::UNEXPECTED_USER_AGENT,
+ ]
+ );
+
+ $response = $this->app->handle($request);
+ $content = $this->getContentAsJson($response);
+
+ $this->assertSame(HTTP::STATUS_UNAUTHORIZED, $response->getStatusCode());
+ $this->assertSame(StatusMessage::CLIENT_UNEXPECTED->value, $content['message']);
+
+ $this->accountAccessAuthRepository->deleteById($accountAccessAuthId);
+ }
+}
diff --git a/tests/FunctionalTest/Root/Account/AccountActivationHandlerTest.php b/tests/FunctionalTest/Root/Account/AccountActivationHandlerTest.php
new file mode 100644
index 00000000..1a0e1e82
--- /dev/null
+++ b/tests/FunctionalTest/Root/Account/AccountActivationHandlerTest.php
@@ -0,0 +1,119 @@
+container->get(UuidFactoryInterface::class);
+
+ /** @var AccountActivationRepositoryInterface $activationRepository */
+ $activationRepository = $this->container->get(AccountActivationRepositoryInterface::class);
+
+ $testAccountActivate = new AccountActivation(
+ id: null,
+ email: new Email('test@example.com'),
+ token: $uuid->uuid7(),
+ createdAt: new DateTimeImmutable()
+ );
+
+ $activationRepository->insert($testAccountActivate);
+
+ $request = new ServerRequest(
+ uri: '/api/account/activation/' . $testAccountActivate->token->getHex()->toString(),
+ method: 'POST'
+ );
+ $request = $request->withParsedBody([
+ 'accountName' => 'Test',
+ 'password' => 'TestBlaBlubb',
+ ]);
+ $response = $this->app->handle($request);
+
+ $emptyAccountActivate = $activationRepository->findByToken(
+ $testAccountActivate->token->getHex()->toString()
+ );
+
+ $this->assertSame(HTTP::STATUS_OK, $response->getStatusCode());
+ $this->assertNull($emptyAccountActivate);
+ }
+
+ public function testTokenNotGiven(): void
+ {
+ $request = new ServerRequest(
+ uri: '/api/account/activation/',
+ method: 'POST'
+ );
+ $request = $request->withParsedBody([
+ 'accountName' => 'Test',
+ 'password' => 'TestBlaBlubb',
+ ]);
+ $response = $this->app->handle($request);
+ $content = $this->getContentAsJson($response);
+
+ $this->assertSame(HTTP::STATUS_BAD_REQUEST, $response->getStatusCode());
+ $this->assertThat($response, $this->bodyMatchesJson([
+ 'statusCode' => Assert::isType(DataType::INTEGER->value),
+ 'message' => Assert::isType(DataType::STRING->value),
+ ]));
+ $this->assertSame(HTTP::STATUS_BAD_REQUEST, $response->getStatusCode());
+ $this->assertSame(StatusMessage::TOKEN_INVALID->value, $content['message']);
+ }
+
+ public function testBodyIsInvalid(): void
+ {
+ $request = new ServerRequest(
+ uri: '/api/account/activation/',
+ method: 'POST'
+ );
+
+ $response = $this->app->handle($request);
+ $content = $this->getContentAsJson($response);
+
+ $this->assertSame(HTTP::STATUS_BAD_REQUEST, $response->getStatusCode());
+ $this->assertThat($response, $this->bodyMatchesJson([
+ 'statusCode' => Assert::isType(DataType::INTEGER->value),
+ 'message' => Assert::isType(DataType::STRING->value),
+ ]));
+ $this->assertSame(HTTP::STATUS_BAD_REQUEST, $response->getStatusCode());
+ $this->assertSame(StatusMessage::INVALID_DATA->value, $content['message']);
+ }
+
+ public function testTokenIsInvalidOrNotPersistent(): void
+ {
+ $request = new ServerRequest(
+ uri: '/api/account/activation/1ddwrer2',
+ method: 'POST'
+ );
+ $request = $request->withParsedBody([
+ 'accountName' => 'Test',
+ 'password' => 'TestBlaBlubb',
+ ]);
+ $response = $this->app->handle($request);
+ $content = $this->getContentAsJson($response);
+
+ $this->assertSame(HTTP::STATUS_BAD_REQUEST, $response->getStatusCode());
+ $this->assertThat($response, $this->bodyMatchesJson([
+ 'statusCode' => Assert::isType(DataType::INTEGER->value),
+ 'message' => Assert::isType(DataType::STRING->value),
+ ]));
+ $this->assertSame(HTTP::STATUS_BAD_REQUEST, $response->getStatusCode());
+ $this->assertSame(StatusMessage::TOKEN_INVALID->value, $content['message']);
+ }
+}
diff --git a/tests/FunctionalTest/Root/Account/AccountPasswordForgottenHandlerTest.php b/tests/FunctionalTest/Root/Account/AccountPasswordForgottenHandlerTest.php
new file mode 100644
index 00000000..edf80a39
--- /dev/null
+++ b/tests/FunctionalTest/Root/Account/AccountPasswordForgottenHandlerTest.php
@@ -0,0 +1,61 @@
+withParsedBody(['email' => self::EMAIL_VALID]);
+ $response = $this->app->handle($request);
+
+ /** @var AccountRepositoryInterface $accountRepository */
+ $accountRepository = $this->container->get(AccountRepositoryInterface::class);
+ $account = $accountRepository->findByEmail(new Email(self::EMAIL_VALID));
+
+ /** @var TokenRepositoryInterface $tokenRepository */
+ $tokenRepository = $this->container->get(TokenRepositoryInterface::class);
+
+ $token = $tokenRepository->findByAccountId($account->id);
+
+ $this->assertSame(HTTP::STATUS_OK, $response->getStatusCode());
+ $this->assertArrayHasKey(0, $token);
+ $this->assertInstanceOf(UuidInterface::class, $token[0]->token);
+ }
+
+ public function testDontCreateTokenForPasswordChange(): void
+ {
+ $request = new ServerRequest(
+ uri: '/api/account/password/forgotten',
+ method: 'POST'
+ );
+ $request = $request->withParsedBody(['email' => self::EMAIL_INVALID]);
+ $response = $this->app->handle($request);
+
+ /** @var AccountRepositoryInterface $accountRepository */
+ $accountRepository = $this->container->get(AccountRepositoryInterface::class);
+ $account = $accountRepository->findByEmail(new Email(self::EMAIL_INVALID));
+
+ $this->assertSame(HTTP::STATUS_OK, $response->getStatusCode());
+ $this->assertNull($account);
+ }
+}
diff --git a/tests/FunctionalTest/Root/Account/AccountPasswordHandlerTest.php b/tests/FunctionalTest/Root/Account/AccountPasswordHandlerTest.php
new file mode 100644
index 00000000..4a14ea84
--- /dev/null
+++ b/tests/FunctionalTest/Root/Account/AccountPasswordHandlerTest.php
@@ -0,0 +1,134 @@
+accountRepository = $this->container->get(AccountRepositoryInterface::class);
+ $this->tokenRepository = $this->container->get(TokenRepositoryInterface::class);
+ $this->uuid = $this->container->get(UuidFactoryInterface::class);
+
+ $this->account = $this->accountRepository->findByEmail(new Email('user@example.com'));
+ $this->token = new Token(
+ null,
+ $this->account->id,
+ TokenType::EMail,
+ $this->uuid->uuid7(),
+ new DateTimeImmutable()
+ );
+ }
+
+ public function testChangePasswortHasStatusOk(): void
+ {
+ $this->tokenRepository->insert($this->token);
+
+ $request = new ServerRequest(
+ uri: '/api/account/password/' . $this->token->token->getHex()->toString(),
+ method: 'PATCH'
+ );
+ $request = $request->withParsedBody(['password' => self::PASSWORD_NEW]);
+ $response = $this->app->handle($request);
+
+ $this->assertSame(HTTP::STATUS_OK, $response->getStatusCode());
+ }
+
+ public function testChangedPasswordIsValid(): void
+ {
+ $this->tokenRepository->insert($this->token);
+
+ $request = new ServerRequest(
+ uri: '/api/account/password/' . $this->token->token->getHex()->toString(),
+ method: 'PATCH'
+ );
+ $request = $request->withParsedBody(['password' => self::PASSWORD_NEW]);
+ $this->app->handle($request);
+
+ $changedAccount = $this->accountRepository->findById($this->account->id);
+
+ $this->assertNotSame($this->account->password, $changedAccount->password);
+ $this->assertTrue(password_verify(self::PASSWORD_NEW, $changedAccount->password));
+ }
+
+ public function testChangedPasswordIsInvalid(): void
+ {
+ $this->tokenRepository->insert($this->token);
+
+ $request = new ServerRequest(
+ uri: '/api/account/password/' . $this->token->token->getHex()->toString(),
+ method: 'PATCH'
+ );
+ $request = $request->withParsedBody(['password' => self::PASSWORD_NEW_INVALID]);
+ $response = $this->app->handle($request);
+
+ $this->assertSame(HTTP::STATUS_BAD_REQUEST, $response->getStatusCode());
+ }
+
+ public function testTokenIsInvalid(): void
+ {
+ $request = new ServerRequest(
+ uri: '/api/account/password/InvalidToken',
+ method: 'PATCH'
+ );
+ $request = $request->withParsedBody(['password' => self::PASSWORD_NEW]);
+ $response = $this->app->handle($request);
+
+ $this->assertSame(HTTP::STATUS_BAD_REQUEST, $response->getStatusCode());
+ }
+
+ public function testTokenIsMissed(): void
+ {
+ $request = new ServerRequest(
+ uri: '/api/account/password/',
+ method: 'PATCH'
+ );
+ $request = $request->withParsedBody(['password' => self::PASSWORD_NEW]);
+ $response = $this->app->handle($request);
+
+ $this->assertSame(HTTP::STATUS_BAD_REQUEST, $response->getStatusCode());
+ }
+
+ public function testTokenWasDestroyed(): void
+ {
+ $this->tokenRepository->insert($this->token);
+
+ $request = new ServerRequest(
+ uri: '/api/account/password/' . $this->token->token->getHex()->toString(),
+ method: 'PATCH'
+ );
+ $request = $request->withParsedBody(['password' => self::PASSWORD_NEW]);
+ $this->app->handle($request);
+
+ $destroyedToken = $this->tokenRepository->findByToken($this->token->token->getHex()->toString());
+
+ $this->assertNull($destroyedToken);
+ }
+}
diff --git a/tests/FunctionalTest/Root/Account/AccountRegisterHandlerTest.php b/tests/FunctionalTest/Root/Account/AccountRegisterHandlerTest.php
new file mode 100644
index 00000000..949af802
--- /dev/null
+++ b/tests/FunctionalTest/Root/Account/AccountRegisterHandlerTest.php
@@ -0,0 +1,104 @@
+app->handle($request);
+ $content = $this->getContentAsJson($response);
+
+ $this->assertSame(HTTP::STATUS_BAD_REQUEST, $response->getStatusCode());
+ $this->assertThat($response, $this->bodyMatchesJson([
+ 'statusCode' => Assert::isType(DataType::INTEGER->value),
+ 'message' => Assert::isType(DataType::STRING->value),
+ ]));
+ $this->assertSame(HTTP::STATUS_BAD_REQUEST, $response->getStatusCode());
+ $this->assertSame(StatusMessage::INVALID_DATA->value, $content['message']);
+ }
+
+ public function testBodyHasInvalidParameter(): void
+ {
+ $request = new ServerRequest(
+ uri: '/api/account',
+ method: 'POST'
+ );
+
+ $response = $this->app->handle($request);
+ $request = $request->withParsedBody(['password' => 'password']);
+ $content = $this->getContentAsJson($response);
+
+ $this->assertSame(HTTP::STATUS_BAD_REQUEST, $response->getStatusCode());
+ $this->assertThat($response, $this->bodyMatchesJson([
+ 'statusCode' => Assert::isType(DataType::INTEGER->value),
+ 'message' => Assert::isType(DataType::STRING->value),
+ ]));
+ $this->assertSame(HTTP::STATUS_BAD_REQUEST, $response->getStatusCode());
+ $this->assertSame(StatusMessage::INVALID_DATA->value, $content['message']);
+ }
+
+ public function testActivationDataSetWasCreated(): void
+ {
+ $request = new ServerRequest(
+ uri: '/api/account',
+ method: 'POST'
+ );
+ $request = $request->withParsedBody(['email' => 'Tester@example.com']);
+ $response = $this->app->handle($request);
+
+ /** @var AccountActivationRepositoryInterface $repository */
+ $repository = $this->container->get(AccountActivationRepositoryInterface::class);
+ $activationDataSet = $repository->findEmail(new Email('Tester@example.com'));
+
+ $this->assertSame(HTTP::STATUS_OK, $response->getStatusCode());
+ $this->assertArrayHasKey(0, $activationDataSet);
+ $this->assertInstanceOf(AccountActivationInterface::class, $activationDataSet[0]);
+ }
+
+ public function testPasswordDataSetWasCreated(): void
+ {
+ /** @var AccountRepositoryInterface $accountRepository */
+ $accountRepository = $this->container->get(AccountRepositoryInterface::class);
+ $account = $accountRepository->findByEmail(new Email('user@example.com'));
+
+ /** @var TokenRepositoryInterface $tokenRepository */
+ $tokenRepository = $this->container->get(TokenRepositoryInterface::class);
+ $tokenRepository->deleteByAccountId($account->id);
+
+ $request = new ServerRequest(
+ uri: '/api/account',
+ method: 'POST'
+ );
+ $request = $request->withParsedBody(['email' => 'user@example.com']);
+ $response = $this->app->handle($request);
+
+ $activationDataSet = $tokenRepository->findByAccountId($account->id);
+
+ $this->assertSame(HTTP::STATUS_OK, $response->getStatusCode());
+ $this->assertArrayHasKey(0, $activationDataSet);
+ $this->assertInstanceOf(TokenInterface::class, $activationDataSet[0]);
+ }
+}
diff --git a/tests/FunctionalTest/Root/Account/AuthenticationHandlerTest.php b/tests/FunctionalTest/Root/Account/AuthenticationHandlerTest.php
new file mode 100644
index 00000000..973dee06
--- /dev/null
+++ b/tests/FunctionalTest/Root/Account/AuthenticationHandlerTest.php
@@ -0,0 +1,180 @@
+withParsedBody(['email' => $email, 'password' => $password])
+ ->withAddedHeader('x-ident', (string)rand());
+ $response = $this->app->handle($request);
+
+ $this->assertSame(HTTP::STATUS_OK, $response->getStatusCode());
+ }
+
+ #[DataProvider('invalidAuthenticateDataProvider')]
+ public function testAuthenticateFailed(string $email, string $password): void
+ {
+ $request = new ServerRequest(
+ uri: '/api/account/authentication',
+ method: 'POST'
+ );
+ $request = $request->withParsedBody(['email' => $email, 'password' => $password])
+ ->withAddedHeader('x-ident', (string)rand());
+ $response = $this->app->handle($request);
+
+ $this->assertSame(HTTP::STATUS_UNAUTHORIZED, $response->getStatusCode());
+ }
+
+ public function testNoDoubleSameLogins(): void
+ {
+ $request = new ServerRequest(
+ uri: '/api/account/authentication',
+ method: 'POST'
+ );
+ $request = $request->withParsedBody(['email' => 'owner@example.com', 'password' => 'owner123456'])
+ ->withAddedHeader('x-ident', (string)rand());
+
+ $response = $this->app->handle($request);
+ $this->assertSame(HTTP::STATUS_OK, $response->getStatusCode());
+
+ $response = $this->app->handle($request);
+ $this->assertSame(HTTP::STATUS_BAD_REQUEST, $response->getStatusCode());
+ }
+
+ public function testAccountIsAlreadyAuthenticated(): void
+ {
+ $request = new ServerRequest(
+ uri: '/api/account/authentication',
+ method: 'POST'
+ );
+ $request = $request->withParsedBody(['email' => 'owner@example.com', 'password' => 'owner123456'])
+ ->withAddedHeader('x-ident', (string)rand())
+ ->withAddedHeader('Authentication', 'Authentication');
+
+ $response = $this->app->handle($request);
+ $this->assertSame(HTTP::STATUS_UNAUTHORIZED, $response->getStatusCode());
+ }
+
+ public function testAccountIsAlreadyAuthorized(): void
+ {
+ $request = new ServerRequest(
+ uri: '/api/account/authentication',
+ method: 'POST'
+ );
+ $request = $request->withParsedBody(['email' => 'admin@example.com', 'password' => 'admin123456'])
+ ->withAddedHeader('x-ident', (string)rand())
+ ->withAddedHeader('Authorization', 'Authorization');
+
+ $response = $this->app->handle($request);
+ $this->assertSame(HTTP::STATUS_UNAUTHORIZED, $response->getStatusCode());
+ }
+
+ public function testResponseHasValidAccessAndRefreshToken(): void
+ {
+ /** @var AccountRepositoryInterface $accountRepository */
+ $accountRepository = $this->container->get(AccountRepositoryInterface::class);
+
+ /** @var AccessTokenService $accessTokenService */
+ $accessTokenService = $this->container->get(AccessTokenService::class);
+
+ /** @var RefreshTokenService $refreshTokenService */
+ $refreshTokenService = $this->container->get(RefreshTokenService::class);
+
+ /** @var UuidFactoryInterface $uuid */
+ $uuid = $this->container->get(UuidFactoryInterface::class);
+
+ $account = new \App\Entity\Account\Account(
+ null,
+ $uuid->uuid7(),
+ 'I see your Token',
+ password_hash('I see your Token', PASSWORD_DEFAULT),
+ new Email('iseeyourtoken@example.com'),
+ new DateTimeImmutable(),
+ new DateTimeImmutable()
+ );
+ $accountRepository->insert($account);
+
+ $request = new ServerRequest(
+ uri: '/api/account/authentication',
+ method: 'POST'
+ );
+ $request = $request->withParsedBody(
+ ['email' => $account->email->toString(), 'password' => 'I see your Token']
+ );
+
+ $response = $this->app->handle($request);
+ $content = $this->getContentAsJson($response);
+
+ $this->assertSame(HTTP::STATUS_OK, $response->getStatusCode());
+ $this->assertThat($response, $this->bodyMatchesJson([
+ 'accessToken' => Assert::isType('string'),
+ 'refreshToken' => Assert::isType('string'),
+ ]));
+
+ $isAccessToken = $accessTokenService->isValid($content['accessToken']);
+ $isRefreshToken = $refreshTokenService->isValid($content['refreshToken']);
+
+ $this->assertTrue($isAccessToken);
+ $this->assertTrue($isRefreshToken);
+ }
+
+ public static function validAccountDataProvider(): array
+ {
+ return [
+ 'Owner' => ['owner@example.com', 'owner123456'],
+ 'Administrator' => ['admin@example.com', 'admin123456'],
+ 'Moderator' => ['moderator@example.com', 'moderator'],
+ 'User' => ['user@example.com', 'user123456'],
+ 'Valid fixed Account Constant' => [Account::EMAIL, Account::PASSWORD_STRING,],
+ ];
+ }
+
+ public static function invalidAuthenticateDataProvider(): array
+ {
+ return [
+ 'Empty Fields' => ['', ''],
+ 'Empty E-Mail' => ['', '123456'],
+ 'Empty Password' => ['account@example.com', ''],
+ 'No E-Mail' => ['no E-Mail', '123456'],
+ 'Invalid email prefixe' => ['abc..def@mail.com', '123456'],
+ 'Password too Short' => ['account@example.com', '123'],
+ 'Password too Long' => [
+ 'account@example.com',
+ '11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'
+ . '11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'
+ . '111111111111111111111111111111111111111111111111111111',
+ ],
+ 'Account with bad Password' => ['owner@example.com', '123456'],
+ 'SQL Injection Comment one' => ["owner@example.com'--", '123456'],
+ 'SQL Injection Comment two' => ["owner@example.com';", '123456'],
+ ];
+ }
+}
diff --git a/tests/FunctionalTest/Root/Account/InvalidEMailAddressProviderTrait.php b/tests/FunctionalTest/Root/Account/InvalidEMailAddressProviderTrait.php
new file mode 100644
index 00000000..36bb2927
--- /dev/null
+++ b/tests/FunctionalTest/Root/Account/InvalidEMailAddressProviderTrait.php
@@ -0,0 +1,54 @@
+withParsedBody(['email' => $email]);
+ $response = $this->app->handle($request);
+ $content = $this->getContentAsJson($response);
+
+ $this->assertSame(HTTP::STATUS_BAD_REQUEST, $response->getStatusCode());
+ $this->assertThat($response, $this->bodyMatchesJson([
+ 'statusCode' => Assert::isType(DataType::INTEGER->value),
+ 'message' => Assert::isType(DataType::STRING->value),
+ ]));
+ $this->assertSame(HTTP::STATUS_BAD_REQUEST, $response->getStatusCode());
+ $this->assertSame(StatusMessage::INVALID_DATA->value, $content['message']);
+ }
+
+ public static function invalidEMailAddressProvider(): array
+ {
+ return [
+ 'Missing @ symbol' => ['invalidemail.com'],
+ 'Missing domain' => ['user@'],
+ 'Missing local part' => ['@domain.com'],
+ 'Consecutive dots' => ['user..name@domain.com'],
+ 'Invalid character in local part' => ['user:name@domain.com'],
+ 'Invalid character in domain' => ['user@domain!.com'],
+ 'Missing top-level domain' => ['user@domain'],
+ 'Space in local part' => ['user name@domain.com'],
+ 'Space in domain' => ['user@domain .com'],
+ 'Double dot in domain' => ['user@domain..com'],
+ 'Invalid character' => ['user@-domain.com'],
+ 'Invalid domain (example.invalid)' => ['test@example.invalid'],
+ 'Invalid top level domain (example.web)' => ['test@example.web'],
+ 'Trailing space' => ['test@example '],
+ 'Leading space' => [' test@example.com'],
+ ];
+ }
+}
diff --git a/tests/FunctionalTest/Root/PingHandlerTest.php b/tests/FunctionalTest/Root/PingHandlerTest.php
new file mode 100644
index 00000000..7c861301
--- /dev/null
+++ b/tests/FunctionalTest/Root/PingHandlerTest.php
@@ -0,0 +1,29 @@
+app->handle($request);
+
+ $this->assertSame($response->getStatusCode(), HTTP::STATUS_OK);
+ $this->assertThat($response, $this->bodyMatchesJson([
+ 'ack' => Assert::greaterThanOrEqual($timestamp),
+ ]));
+ }
+}
diff --git a/tests/FunctionalTest/bootstrap.php b/tests/FunctionalTest/bootstrap.php
new file mode 100644
index 00000000..aba6b5ec
--- /dev/null
+++ b/tests/FunctionalTest/bootstrap.php
@@ -0,0 +1,10 @@
+addSql($sql);
+ }
+
+ public function down(Schema $schema): void
+ {
+ $sql = <<addSql($sql);
+ }
+}
diff --git a/tests/Unit/App/Handler/Topic/TopicCreateHandlerTest.php b/tests/Unit/App/Handler/Topic/TopicCreateHandlerTest.php
deleted file mode 100644
index 7b7e1305..00000000
--- a/tests/Unit/App/Handler/Topic/TopicCreateHandlerTest.php
+++ /dev/null
@@ -1,32 +0,0 @@
-handle(
- $this->request->withAttribute(Topic::class, new Topic(...TopicTestEntity::getDefaultTopicValue()))
- );
-
- $responseData = $response->getBody()->getContents();
-
- $responseDataAsArray = json_decode($responseData, true);
-
- self::assertInstanceOf(JsonResponse::class, $response);
- self::assertIsString($responseData);
- self::assertJson($responseData);
- self::assertIsArray($responseDataAsArray);
- self::assertArrayHasKey('topic', $responseDataAsArray);
- }
-}
diff --git a/tests/Unit/App/Handler/Topic/TopicListAvailableHandlerTest.php b/tests/Unit/App/Handler/Topic/TopicListAvailableHandlerTest.php
deleted file mode 100644
index f6c950de..00000000
--- a/tests/Unit/App/Handler/Topic/TopicListAvailableHandlerTest.php
+++ /dev/null
@@ -1,34 +0,0 @@
-handle($this->request->withAttribute('availableTopics', $topicList));
-
- self::assertInstanceOf(JsonResponse::class, $response);
- }
-
- public function testReturnJsonResponseWithoutItems(): void
- {
- $handler = new TopicListAvailableHandler();
-
- $topicList = [];
-
- $response = $handler->handle($this->request->withAttribute('availableTopics', $topicList));
-
- self::assertInstanceOf(JsonResponse::class, $response);
- }
-}
diff --git a/tests/Unit/App/Middleware/Event/EventCreateMiddlewareFactoryTest.php b/tests/Unit/App/Middleware/Event/EventCreateMiddlewareFactoryTest.php
deleted file mode 100644
index 14cb11dd..00000000
--- a/tests/Unit/App/Middleware/Event/EventCreateMiddlewareFactoryTest.php
+++ /dev/null
@@ -1,35 +0,0 @@
- new MockEventService(),
- ReflectionHydrator::class => new ReflectionHydrator(),
- DateTimeFormatterStrategy::class => new DateTimeFormatterStrategy(),
- ]
- );
-
- $middleware = (new EventCreateMiddlewareFactory())($container);
-
- self::assertInstanceOf(EventCreateMiddleware::class, $middleware);
- }
-}
diff --git a/tests/Unit/App/Middleware/Event/EventCreateMiddlewareTest.php b/tests/Unit/App/Middleware/Event/EventCreateMiddlewareTest.php
deleted file mode 100644
index 0c8a7652..00000000
--- a/tests/Unit/App/Middleware/Event/EventCreateMiddlewareTest.php
+++ /dev/null
@@ -1,53 +0,0 @@
-hydrator);
- $user = new User(...UserTestEntity::getDefaultUserValue());
- $user = $user->with(id: TestConstants::USER_ID);
-
- $response = $middleware->process(
- $this->request->withAttribute(User::AUTHENTICATED_USER, $user)
- ->withParsedBody(['id' => 2]),
- $this->handler
- );
-
- self::assertInstanceOf(ResponseInterface::class, $response);
- self::assertNotInstanceOf(JsonResponse::class, $response);
- }
-
- public function testEventIsPresentAndCanNotCreated(): void
- {
- $middleware = new EventCreateMiddleware(new MockEventService(), $this->hydrator);
- $user = new User(...UserTestEntity::getDefaultUserValue());
- $user = $user->with(id: TestConstants::USER_ID);
-
- $response = $middleware->process(
- $this->request->withAttribute(User::AUTHENTICATED_USER, $user)
- ->withParsedBody(['id' => TestConstants::USER_ID]),
- $this->handler
- );
-
- self::assertInstanceOf(JsonResponse::class, $response);
- self::assertSame(HTTP::STATUS_NOT_FOUND, $response->getStatusCode());
- }
-}
diff --git a/tests/Unit/App/Middleware/Event/EventCreateValidationMiddlewareTest.php b/tests/Unit/App/Middleware/Event/EventCreateValidationMiddlewareTest.php
deleted file mode 100644
index 11698a75..00000000
--- a/tests/Unit/App/Middleware/Event/EventCreateValidationMiddlewareTest.php
+++ /dev/null
@@ -1,42 +0,0 @@
-process(
- $this->request->withParsedBody([true]),
- $this->handler
- );
-
- self::assertInstanceOf(ResponseInterface::class, $response);
- self::assertNotInstanceOf(JsonResponse::class, $response);
- }
-
- public function testValidationIsNotValide(): void
- {
- $middleware = new EventCreateValidationMiddleware(new MockEventCreateValidator());
-
- $response = $middleware->process(
- $this->request->withParsedBody([false]),
- $this->handler
- );
-
- self::assertInstanceOf(JsonResponse::class, $response);
- }
-}
diff --git a/tests/Unit/App/Middleware/Event/EventListMiddlewareTest.php b/tests/Unit/App/Middleware/Event/EventListMiddlewareTest.php
deleted file mode 100644
index 1350136e..00000000
--- a/tests/Unit/App/Middleware/Event/EventListMiddlewareTest.php
+++ /dev/null
@@ -1,60 +0,0 @@
-process($this->request, $this->handler);
-
- self::assertInstanceOf(ResponseInterface::class, $response);
- }
-
- public function testCanFindAllEventSortedASC(): void
- {
- $middleware = new EventListMiddleware(new MockEventService(), new MockUserService());
-
- $response = $middleware->process(
- $this->request->withQueryParams(
- [
- 'order' => 'startedAt',
- 'sort' => 'ASC',
- ]
- ),
- $this->handler
- );
-
- self::assertInstanceOf(ResponseInterface::class, $response);
- }
-
- public function testCanFindAllEventSortedDESC(): void
- {
- $middleware = new EventListMiddleware(new MockEventService(), new MockUserService());
-
- $response = $middleware->process(
- $this->request->withQueryParams(
- [
- 'order' => 'startedAt',
- 'sort' => 'DESC',
- ]
- ),
- $this->handler
- );
-
- self::assertInstanceOf(ResponseInterface::class, $response);
- }
-}
diff --git a/tests/Unit/App/Middleware/Event/EventMiddlewareTest.php b/tests/Unit/App/Middleware/Event/EventMiddlewareTest.php
deleted file mode 100644
index 16cc4e92..00000000
--- a/tests/Unit/App/Middleware/Event/EventMiddlewareTest.php
+++ /dev/null
@@ -1,41 +0,0 @@
-process($this->request->withAttribute('eventId', 1), $this->handler);
-
- self::assertInstanceOf(ResponseInterface::class, $response);
- }
-
- public function testThrowInvalidArgumentException(): void
- {
- $middleware = new EventMiddleware(new MockEventService());
-
- self::expectException(InvalidArgumentException::class);
- self::expectExceptionCode(HTTP::STATUS_BAD_REQUEST);
-
- $middleware->process(
- $this->request->withAttribute('eventId', TestConstants::EVENT_ID_THROW_EXCEPTION),
- $this->handler
- );
- }
-}
diff --git a/tests/Unit/App/Middleware/Event/EventNameMiddlewareTest.php b/tests/Unit/App/Middleware/Event/EventNameMiddlewareTest.php
deleted file mode 100644
index 48046c92..00000000
--- a/tests/Unit/App/Middleware/Event/EventNameMiddlewareTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-process(
- $this->request->withAttribute('eventName', TestConstants::EVENT_TITLE),
- $this->handler
- );
-
- self::assertInstanceOf(ResponseInterface::class, $response);
- }
-
- public function testThrowInvalidArgumentException(): void
- {
- $middleware = new EventNameMiddleware(new MockEventService());
-
- self::expectException(InvalidArgumentException::class);
- self::expectExceptionCode(HTTP::STATUS_BAD_REQUEST);
-
- $middleware->process(
- $this->request->withAttribute('eventName', TestConstants::EVENT_TITLE_THROW_EXCEPTION),
- $this->handler
- );
- }
-}
diff --git a/tests/Unit/App/Middleware/Topic/TopicCreateSubmitMiddlewareTest.php b/tests/Unit/App/Middleware/Topic/TopicCreateSubmitMiddlewareTest.php
deleted file mode 100644
index d62fe159..00000000
--- a/tests/Unit/App/Middleware/Topic/TopicCreateSubmitMiddlewareTest.php
+++ /dev/null
@@ -1,45 +0,0 @@
-middleware = new TopicCreateSubmitMiddleware(
- new MockTopicPoolService(),
- $this->hydrator,
- Uuid::uuid7()
- );
- }
-
- public function testHasCreateNewTopicAndReturnResponse(): void
- {
- $response = $this->middleware->process(
- $this->request->withParsedBody(['topic' => TestConstants::TOPIC_TITLE_CREATE] + TopicTestEntity::getDefaultTopicValue()),
- $this->handler
- );
-
- self::assertInstanceOf(ResponseInterface::class, $response);
- }
-
- public function testTopicIsDuplicatedAndThrowException(): void
- {
- $data = ['topic' => TestConstants::TOPIC_TITLE] + TopicTestEntity::getDefaultTopicValue();
- self::expectException(DuplicateNameHttpException::class);
-
- $this->middleware->process($this->request->withParsedBody($data), $this->handler);
- }
-}
diff --git a/tests/Unit/App/Middleware/Topic/TopicCreateValidationMiddlewareTest.php b/tests/Unit/App/Middleware/Topic/TopicCreateValidationMiddlewareTest.php
deleted file mode 100644
index e45e2ffc..00000000
--- a/tests/Unit/App/Middleware/Topic/TopicCreateValidationMiddlewareTest.php
+++ /dev/null
@@ -1,43 +0,0 @@
- 'topic',
- 'description' => 'This is the one and only Description',
- ];
-
- private TopicCreateValidationMiddleware $middleware;
-
- public function setUp(): void
- {
- $this->middleware = new TopicCreateValidationMiddleware(new MockTopicCreateValidator());
- parent::setUp();
- }
-
- public function testValidateTopicData(): void
- {
- $response = $this->middleware->process(
- $this->request->withParsedBody($this->topicData),
- $this->handler
- );
-
- self::assertInstanceOf(ResponseInterface::class, $response);
- }
-
- public function testValidateTopicDataThrowException(): void
- {
- self::expectException(InvalidArgumentHttpException::class);
-
- $this->middleware->process($this->request->withParsedBody([]), $this->handler);
- }
-}
diff --git a/tests/Unit/App/Middleware/Topic/TopicListMiddlewareTest.php b/tests/Unit/App/Middleware/Topic/TopicListMiddlewareTest.php
deleted file mode 100644
index ec67e4f8..00000000
--- a/tests/Unit/App/Middleware/Topic/TopicListMiddlewareTest.php
+++ /dev/null
@@ -1,20 +0,0 @@
-process($this->request, $this->handler);
-
- self::assertInstanceOf(ResponseInterface::class, $response);
- }
-}
diff --git a/tests/Unit/App/Service/EventServiceFactoryTest.php b/tests/Unit/App/Service/EventServiceFactoryTest.php
deleted file mode 100644
index a3e91a2f..00000000
--- a/tests/Unit/App/Service/EventServiceFactoryTest.php
+++ /dev/null
@@ -1,30 +0,0 @@
- new MockEventTable(),
- ReflectionHydrator::class => $this->hydrator,
- DateTimeFormatterStrategy::class => $this->dateTimeFormatterStrategy,
- ]);
-
- $factory = new EventServiceFactory();
-
- $service = $factory($container);
-
- self::assertInstanceOf(EventService::class, $service);
- }
-}
diff --git a/tests/Unit/App/Service/EventServiceTest.php b/tests/Unit/App/Service/EventServiceTest.php
deleted file mode 100644
index e2978828..00000000
--- a/tests/Unit/App/Service/EventServiceTest.php
+++ /dev/null
@@ -1,98 +0,0 @@
-service = new EventService(new MockEventTable(), $this->hydrator);
- }
-
- public function testCanNotCreate(): void
- {
- $event = new Event(...EventTestEntity::getDefaultEventValue());
- $event = $event->with(title: TestConstants::EVENT_TITLE);
-
- $event = $this->service->create($event);
-
- self::assertSame(false, $event);
- }
-
- public function testCanCreate(): void
- {
- $event = new Event(...EventTestEntity::getDefaultEventValue());
- $event = $event->with(title: TestConstants::EVENT_CREATE_TITLE);
-
- $event = $this->service->create($event);
-
- self::assertSame(true, $event);
- }
-
- public function testFindByIdThrowException(): void
- {
- self::expectException(InvalidArgumentException::class);
-
- $this->service->findById(TestConstants::EVENT_ID_THROW_EXCEPTION);
- }
-
- public function testFindById(): void
- {
- $event = $this->service->findById(TestConstants::EVENT_ID);
-
- self::assertInstanceOf(Event::class, $event);
- }
-
- public function testCanFindAll(): void
- {
- $event = $this->service->findAll();
-
- self::assertIsArray($event);
- self::assertArrayHasKey(0, $event);
- self::assertInstanceOf(Event::class, $event[0]);
- }
-
- public function testCanFindAllActive(): void
- {
- $event = $this->service->findAllActive();
-
- self::assertIsArray($event);
- self::assertArrayHasKey(0, $event);
- self::assertInstanceOf(Event::class, $event[0]);
- }
-
- public function testCanFindAllNotActive(): void
- {
- $event = $this->service->findAllNotActive();
-
- self::assertIsArray($event);
- self::assertArrayHasKey(0, $event);
- self::assertInstanceOf(Event::class, $event[0]);
- }
-
- public function testCheckIsRatingCompleted(): void
- {
- $event = $this->service->isRatingCompleted(TestConstants::EVENT_ID);
-
- self::assertSame(true, $event);
- }
-
- public function testCheckIsRatingNotCompleted(): void
- {
- $event = $this->service->isRatingCompleted(TestConstants::EVENT_ID_RATING_NOT_COMPLETED);
-
- self::assertSame(false, $event);
- }
-}
diff --git a/tests/Unit/App/Service/ParticipantServiceFactoryTest.php b/tests/Unit/App/Service/ParticipantServiceFactoryTest.php
deleted file mode 100644
index 6a0cb91d..00000000
--- a/tests/Unit/App/Service/ParticipantServiceFactoryTest.php
+++ /dev/null
@@ -1,30 +0,0 @@
- new MockParticipantTable(),
- ReflectionHydrator::class => $this->hydrator,
- DateTimeFormatterStrategy::class => $this->dateTimeFormatterStrategy,
- ]);
-
- $factory = new ParticipantServiceFactory();
-
- $service = $factory($container);
-
- self::assertInstanceOf(ParticipantService::class, $service);
- }
-}
diff --git a/tests/Unit/App/Service/ParticipantServiceTest.php b/tests/Unit/App/Service/ParticipantServiceTest.php
deleted file mode 100644
index d949b914..00000000
--- a/tests/Unit/App/Service/ParticipantServiceTest.php
+++ /dev/null
@@ -1,109 +0,0 @@
-service = new ParticipantService($table, $this->hydrator);
- }
-
- public function testCanNotCreateParticipant(): void
- {
- $participant = new Participant(...ParticipantTestEntity::getDefaultParticipantValue());
- $participant = $participant->with(
- id: TestConstants::PARTICIPANT_ID,
- userId: TestConstants::USER_ID,
- eventId: TestConstants::EVENT_ID,
- );
-
- $participant = $this->service->create($participant);
-
- self::assertSame(false, $participant);
- }
-
- public function testCanCreateParticipant(): void
- {
- $participant = new Participant(...ParticipantTestEntity::getDefaultParticipantValue());
- $participant = $participant->with(
- id: TestConstants::PARTICIPANT_ID_UNUSED,
- userId: TestConstants::USER_ID_UNUSED,
- eventId: TestConstants::EVENT_ID_UNUSED,
- );
-
- $participant = $this->service->create($participant);
-
- self::assertSame(true, $participant);
- }
-
- public function testCanRemoveParticipant(): void
- {
- $participant = new Participant(...ParticipantTestEntity::getDefaultParticipantValue());
- $participant = $participant->with(id: TestConstants::PARTICIPANT_ID);
-
- $response = $this->service->remove($participant);
-
- self::assertSame(true, $response);
- }
-
- public function testCanNotRemoveParticipant(): void
- {
- $participant = new Participant(...ParticipantTestEntity::getDefaultParticipantValue());
- $participant = $participant->with(id: TestConstants::PARTICIPANT_ID_UNUSED);
-
- $response = $this->service->remove($participant);
-
- self::assertSame(false, $response);
- }
-
- public function testFindByIdThrowException(): void
- {
- self::expectException(InvalidArgumentException::class);
-
- $this->service->findById(TestConstants::PARTICIPANT_ID_THROW_EXCEPTION);
- }
-
- public function testCanFindById(): void
- {
- $participant = $this->service->findById(TestConstants::PARTICIPANT_ID);
-
- self::assertInstanceOf(Participant::class, $participant);
- }
-
- public function testCanFindByUserId(): void
- {
- $participant = $this->service->findByUserId(TestConstants::USER_ID);
-
- self::assertInstanceOf(Participant::class, $participant);
- }
-
- public function testCanNotFindByUserId(): void
- {
- $participant = $this->service->findByUserId(TestConstants::USER_ID_UNUSED);
-
- self::assertNull($participant);
- }
-
- public function testCanFindActiveParticipantByEvent(): void
- {
- $participant = $this->service->findActiveParticipantByEvent(TestConstants::EVENT_ID);
-
- self::assertIsArray($participant);
- self::assertArrayHasKey(0, $participant);
- self::assertInstanceOf(Participant::class, $participant[0]);
- }
-}
diff --git a/tests/Unit/App/Service/ProjectServiceFactoryTest.php b/tests/Unit/App/Service/ProjectServiceFactoryTest.php
deleted file mode 100644
index 177101b4..00000000
--- a/tests/Unit/App/Service/ProjectServiceFactoryTest.php
+++ /dev/null
@@ -1,30 +0,0 @@
- new MockProjectTable(),
- ReflectionHydrator::class => $this->hydrator,
- DateTimeFormatterStrategy::class => $this->dateTimeFormatterStrategy,
- ]);
-
- $factory = new ProjectServiceFactory();
-
- $service = $factory($container);
-
- self::assertInstanceOf(ProjectService::class, $service);
- }
-}
diff --git a/tests/Unit/App/Service/ProjectServiceTest.php b/tests/Unit/App/Service/ProjectServiceTest.php
deleted file mode 100644
index 62608ee9..00000000
--- a/tests/Unit/App/Service/ProjectServiceTest.php
+++ /dev/null
@@ -1,51 +0,0 @@
-service = new ProjectService($table, $this->hydrator);
- }
-
- public function testCanFindById(): void
- {
- $project = $this->service->findById(1);
-
- self::assertInstanceOf(Project::class, $project);
- }
-
- public function testCanNotFindById(): void
- {
- self::expectException(InvalidArgumentException::class);
-
- $this->service->findById(TestConstants::PROJECT_ID_UNUSED);
- }
-
- public function testCanFindByParticipantId(): void
- {
- $project = $this->service->findByParticipantId(1);
-
- self::assertInstanceOf(Project::class, $project);
- }
-
- public function testCanNotFindByParticipantId(): void
- {
- $project = $this->service->findByParticipantId(2);
-
- self::assertNull($project);
- }
-}
diff --git a/tests/Unit/App/Service/TopicPoolServiceTest.php b/tests/Unit/App/Service/TopicPoolServiceTest.php
deleted file mode 100644
index eacd6470..00000000
--- a/tests/Unit/App/Service/TopicPoolServiceTest.php
+++ /dev/null
@@ -1,113 +0,0 @@
-table = new MockTopicPoolTable();
- $this->service = new TopicPoolService($this->table, $this->hydrator);
- }
-
- public function testCanInsertTopic(): void
- {
- $insertTopic = $this->service->insert(new Topic(...TopicTestEntity::getDefaultTopicValue()));
-
- self::assertInstanceOf(TopicPoolService::class, $insertTopic);
- }
-
- public function testCanUpdateEventId(): void
- {
- $updateTopic = $this->service->updateEventId(new Topic(...TopicTestEntity::getDefaultTopicValue()));
-
- self::assertInstanceOf(TopicPoolService::class, $updateTopic);
- }
-
- public function testFindByIdThrowException(): void
- {
- self::expectException(InvalidArgumentException::class);
-
- $this->service->findById(TestConstants::TOPIC_ID_THROW_EXCEPTION);
- }
-
- public function testCanFindById(): void
- {
- $topic = $this->service->findById(TestConstants::TOPIC_ID);
-
- self::assertInstanceOf(Topic::class, $topic);
- }
-
- public function testCanNotFindByEventId(): void
- {
- $topic = $this->service->findByEventId(TestConstants::EVENT_ID_UNUSED);
-
- $this->assertNull($topic);
- }
-
- public function testCanFindByEventId(): void
- {
- $topic = $this->service->findByEventId(TestConstants::EVENT_ID);
-
- self::assertInstanceOf(Topic::class, $topic);
- }
-
- public function testCanFindAvailable(): void
- {
- $topic = $this->service->findAvailable();
-
- self::assertIsArray($topic);
- self::assertArrayHasKey(0, $topic);
- self::assertInstanceOf(Topic::class, $topic[0]);
- }
-
- public function testCanFindAll(): void
- {
- $topic = $this->service->findAll();
-
- self::assertIsArray($topic);
- self::assertArrayHasKey(0, $topic);
- self::assertInstanceOf(Topic::class, $topic[0]);
- }
-
- public function testIsNotTopic(): void
- {
- $topic = $this->service->isTopic('fakeIsNotTopic');
-
- self::assertSame(false, $topic);
- }
-
- public function testIsTopic(): void
- {
- $topic = $this->service->isTopic(TestConstants::TOPIC_TITLE);
-
- self::assertSame(true, $topic);
- }
-
- public function testCanGetEntriesStatistic(): void
- {
- $values = [
- 'allTopic' => $this->table->getCountTopic(),
- 'allAcceptedTopic' => $this->table->getCountTopicAccepted(),
- 'allSelectionAvailableTopic' => $this->table->getCountTopicSelectionAvailable(),
- ];
-
- $statistic = $this->service->getEntriesStatistic();
-
- self::assertSame($values, $statistic);
- }
-}
diff --git a/tests/Unit/App/Table/EventTableTest.php b/tests/Unit/App/Table/EventTableTest.php
deleted file mode 100644
index e121aee6..00000000
--- a/tests/Unit/App/Table/EventTableTest.php
+++ /dev/null
@@ -1,137 +0,0 @@
-table->getTableName());
- }
-
- public function testCanInsertEvent(): void
- {
- $event = new Event(...EventTestEntity::getDefaultEventValue());
- $event = $event->with(title: TestConstants::EVENT_CREATE_TITLE);
-
- $insertLastId = $this->table->insert($event);
-
- self::assertSame(1, $insertLastId);
- }
-
- public function testInsertEventThrowsException(): void
- {
- $event = new Event(...EventTestEntity::getDefaultEventValue());
-
- self::expectException(DuplicateEntryException::class);
-
- $this->table->insert($event);
- }
-
- public function testCanFindById(): void
- {
- $event = $this->table->findById(TestConstants::EVENT_ID);
-
- self::assertEquals(EventTestEntity::getDefaultEventValue(), $event);
- }
-
- public function testFindByIdHasEmptyResult(): void
- {
- $event = $this->table->findById(TestConstants::EVENT_ID_UNUSED);
-
- self::assertSame([], $event);
- }
-
- public function testCanFindAll(): void
- {
- $event = $this->table->findAll();
-
- self::assertEquals([0 => EventTestEntity::getDefaultEventValue()], $event);
- }
-
- public function testFindAllHasEmptyResult(): void
- {
- $table = new EventTable(new MockQueryForCanNot());
-
- $event = $table->findAll();
-
- self::assertSame([], $event);
- }
-
- public function testCanFindByName(): void
- {
- $event = $this->table->findByTitle(TestConstants::EVENT_TITLE);
-
- self::assertEquals(EventTestEntity::getDefaultEventValue(), $event);
- }
-
- public function testFindByNameHasEmptyResult(): void
- {
- $event = $this->table->findByTitle(TestConstants::EVENT_TITLE_UNUSED);
-
- self::assertSame([], $event);
- }
-
- public function testCanFindAllActive(): void
- {
- $event = $this->table->findAllActive();
-
- self::assertEquals([0 => EventTestEntity::getDefaultEventValue()], $event);
- }
-
- public function testFindAllActiveHasEmptyResult(): void
- {
- $table = new EventTable(new MockQueryForCanNot());
-
- $event = $table->findAllActive();
-
- self::assertSame([], $event);
- }
-
- public function testCanFindAllNotActive(): void
- {
- $event = $this->table->findAllInactive();
-
- self::assertEquals([0 => EventTestEntity::getDefaultEventValue()], $event);
- }
-
- public function testFindAllNotActiveHasEmptyResult(): void
- {
- $table = new EventTable(new MockQueryForCanNot());
-
- $event = $table->findAllInactive();
-
- self::assertSame([], $event);
- }
-
- public function testCanRemoveEvent(): void
- {
- $event = new Event(...EventTestEntity::getDefaultEventValue());
- $event = $event->with(id: TestConstants::EVENT_ID);
-
- $removeStatus = $this->table->remove($event);
-
- self::assertSame(true, $removeStatus);
- }
-
- public function testCanNotRemoveEvent(): void
- {
- $event = new Event(...EventTestEntity::getDefaultEventValue());
- $event = $event->with(id: TestConstants::EVENT_ID_NOT_REMOVED);
-
- $removeStatus = $this->table->remove($event);
-
- self::assertSame(false, $removeStatus);
- }
-}
diff --git a/tests/Unit/App/Table/ParticipantTableTest.php b/tests/Unit/App/Table/ParticipantTableTest.php
deleted file mode 100644
index 2f708567..00000000
--- a/tests/Unit/App/Table/ParticipantTableTest.php
+++ /dev/null
@@ -1,125 +0,0 @@
-table->getTableName());
- }
-
- public function testCanInsertParticipant(): void
- {
- $participant = new Participant(...ParticipantTestEntity::getDefaultParticipantValue());
- $participant = $participant->with(userId: TestConstants::USER_CREATE_ID);
-
- $insertParticipant = $this->table->insert($participant);
-
- self::assertSame(1, $insertParticipant);
- }
-
- public function testInsertParticipantThrowsException(): void
- {
- $participant = new Participant(...ParticipantTestEntity::getDefaultParticipantValue());
- $participant = $participant->with(userId: TestConstants::USER_ID);
-
- self::expectException(DuplicateEntryException::class);
-
- $this->table->insert($participant);
- }
-
- public function testCanRemoveParticipant(): void
- {
- $participant = new Participant(...ParticipantTestEntity::getDefaultParticipantValue());
-
- $removeParticipant = $this->table->remove($participant);
-
- self::assertSame(true, $removeParticipant);
- }
-
- public function testCanFindById(): void
- {
- $project = $this->table->findById(TestConstants::PARTICIPANT_ID);
-
- self::assertEquals(ParticipantTestEntity::getDefaultParticipantValue(), $project);
- }
-
- public function testFindByIdHaveEmptyResult(): void
- {
- $project = $this->table->findById(TestConstants::PARTICIPANT_ID_UNUSED);
-
- self::assertSame([], $project);
- }
-
- public function testCanFindAll(): void
- {
- $project = $this->table->findAll();
-
- self::assertEquals([0 => ParticipantTestEntity::getDefaultParticipantValue()], $project);
- }
-
- public function testFindAllHasEmptyResult(): void
- {
- $table = new ParticipantTable(new MockQueryForCanNot());
-
- $project = $table->findAll();
-
- self::assertSame([], $project);
- }
-
- public function testCanFindByUserId(): void
- {
- $participant = $this->table->findByUserId(TestConstants::USER_ID);
-
- self::assertEquals(ParticipantTestEntity::getDefaultParticipantValue(), $participant);
- }
-
- public function testFindByUserIdHasEmptyResult(): void
- {
- $participant = $this->table->findByUserId(TestConstants::USER_ID_UNUSED);
-
- self::assertSame([], $participant);
- }
-
- public function testCanFindByUserIdAndEventId(): void
- {
- $participant = $this->table->findUserForAnEvent(TestConstants::USER_ID, TestConstants::EVENT_ID);
-
- self::assertEquals(ParticipantTestEntity::getDefaultParticipantValue(), $participant);
- }
-
- public function testFindByUserIdAndEventIdHasEmptyResult(): void
- {
- $participant = $this->table->findUserForAnEvent(TestConstants::USER_ID_UNUSED, TestConstants::EVENT_ID_UNUSED);
-
- self::assertSame([], $participant);
- }
-
- public function testCanFindActiveParticipantByEvent(): void
- {
- $participant = $this->table->findActiveParticipantsByEvent(TestConstants::EVENT_ID);
-
- self::assertEquals([0 => ParticipantTestEntity::getDefaultParticipantValue()], $participant);
- }
-
- public function testFindActiveParticipantByEventHasEmptyResult(): void
- {
- $table = new ParticipantTable(new MockQueryForCanNot());
-
- $participant = $table->findActiveParticipantsByEvent(TestConstants::EVENT_ID_UNUSED);
-
- self::assertSame([], $participant);
- }
-}
diff --git a/tests/Unit/App/Table/ProjectTableTest.php b/tests/Unit/App/Table/ProjectTableTest.php
deleted file mode 100644
index 25cd3981..00000000
--- a/tests/Unit/App/Table/ProjectTableTest.php
+++ /dev/null
@@ -1,47 +0,0 @@
-table->getTableName());
- }
-
- public function testCanFindById(): void
- {
- $project = $this->table->findById(TestConstants::PROJECT_ID);
-
- self::assertEquals(ProjectTestEntity::getDefaultProjectValue(), $project);
- }
-
- public function testFindByIdHaveEmptyResult(): void
- {
- $project = $this->table->findById(TestConstants::PROJECT_ID_UNUSED);
-
- self::assertSame([], $project);
- }
-
- public function testCanFindAll(): void
- {
- $project = $this->table->findAll();
-
- self::assertEquals([0 => ProjectTestEntity::getDefaultProjectValue()], $project);
- }
-
- public function testCanFindByParticipantId(): void
- {
- $project = $this->table->findByParticipantId(TestConstants::PARTICIPANT_ID);
-
- self::assertEquals(ProjectTestEntity::getDefaultProjectValue(), $project);
- }
-}
diff --git a/tests/Unit/App/Table/TopicPoolTableTest.php b/tests/Unit/App/Table/TopicPoolTableTest.php
deleted file mode 100644
index 800af161..00000000
--- a/tests/Unit/App/Table/TopicPoolTableTest.php
+++ /dev/null
@@ -1,108 +0,0 @@
-table->getTableName());
- }
-
- public function testCanInsertTopic(): void
- {
- $topic = new Topic(...TopicTestEntity::getDefaultTopicValue());
-
- $insertTopic = $this->table->insert($topic);
-
- self::assertInstanceOf(TopicPoolTable::class, $insertTopic);
- }
-
- public function testCanUpdateEventId(): void
- {
- $topic = new Topic(...TopicTestEntity::getDefaultTopicValue());
-
- $updateTopic = $this->table->assignAnEvent($topic->id, $topic->eventId);
-
- self::assertInstanceOf(TopicPoolTable::class, $updateTopic);
- }
-
- public function testCanFindById(): void
- {
- $topic = $this->table->findById(TestConstants::TOPIC_POOL_ID);
-
- self::assertEquals(TopicTestEntity::getDefaultTopicValue(), $topic);
- }
-
- public function testFindByIdHaveEmptyResult(): void
- {
- $topic = $this->table->findById(TestConstants::TOPIC_POOL_ID_UNUSED);
-
- self::assertSame([], $topic);
- }
-
- public function testCanFindByUuId(): void
- {
- $topic = $this->table->findByUuId(TestConstants::TOPIC_UUID);
-
- self::assertEquals(TopicTestEntity::getDefaultTopicValue(), $topic);
- }
-
- public function testCanFindAll(): void
- {
- $users = $this->table->findAll();
-
- self::assertEquals([0 => TopicTestEntity::getDefaultTopicValue()], $users);
- }
-
- public function testCanFindByEventId(): void
- {
- $topic = $this->table->findByEventId(TestConstants::EVENT_ID);
-
- self::assertEquals(TopicTestEntity::getDefaultTopicValue(), $topic);
- }
-
- public function testCanFindAvailable(): void
- {
- $topic = $this->table->findAvailable();
-
- self::assertEquals([0 => TopicTestEntity::getDefaultTopicValue()], $topic);
- }
-
- public function testCanFindByTopic(): void
- {
- $topic = $this->table->findByTopic(TestConstants::TOPIC_TITLE);
-
- self::assertEquals(TopicTestEntity::getDefaultTopicValue(), $topic);
- }
-
- public function testCanGetCountTopic(): void
- {
- $topicCount = $this->table->getCountTopic();
-
- self::assertSame(1, $topicCount);
- }
-
- public function testCanGetCountTopicAccepted(): void
- {
- $topicCount = $this->table->getCountTopicAccepted();
-
- self::assertSame(1, $topicCount);
- }
-
- public function testCanGetCountTopicSelectionAvailable(): void
- {
- $topicCount = $this->table->getCountTopicSelectionAvailable();
-
- self::assertSame(1, $topicCount);
- }
-}
diff --git a/tests/Unit/Core/Factory/MailFactoryTest.php b/tests/Unit/Core/Factory/MailFactoryTest.php
deleted file mode 100644
index d90bb92e..00000000
--- a/tests/Unit/Core/Factory/MailFactoryTest.php
+++ /dev/null
@@ -1,28 +0,0 @@
- [
- 'dsn' => 'smtp://example.com:1025',
- 'from' => 'example@example.com',
- ],
- ];
-
- $container = new MockContainer();
- $container->add('config', $config);
-
- $mailer = (new MailFactory())($container);
-
- self::assertInstanceOf(Mailer::class, $mailer);
- }
-}
diff --git a/tests/Unit/Core/Factory/UuidFactoryTest.php b/tests/Unit/Core/Factory/UuidFactoryTest.php
deleted file mode 100644
index 6075280f..00000000
--- a/tests/Unit/Core/Factory/UuidFactoryTest.php
+++ /dev/null
@@ -1,20 +0,0 @@
-handle(
- $this->request->withAttribute(User::AUTHENTICATED_USER, new User(...UserTestEntity::getDefaultUserValue()))
- );
-
- $responseData = $response->getBody()->getContents();
-
- $responseDataAsArray = json_decode($responseData, true);
-
- self::assertInstanceOf(JsonResponse::class, $response);
- self::assertIsString($responseData);
- self::assertJson($responseData);
- self::assertIsArray($responseDataAsArray);
- self::assertArrayHasKey('token', $responseDataAsArray);
- }
-}
diff --git a/tests/Unit/Core/Hydrator/ClassMethodsHydratorFactoryTest.php b/tests/Unit/Core/Hydrator/ClassMethodsHydratorFactoryTest.php
deleted file mode 100644
index e3e2a999..00000000
--- a/tests/Unit/Core/Hydrator/ClassMethodsHydratorFactoryTest.php
+++ /dev/null
@@ -1,18 +0,0 @@
-add(DateTimeFormatterStrategy::class, (new DateTimeFormatterStrategyFactory())($container));
-
- $nullableStragegy = (new NullableStrategyFactory())($container);
-
- self::assertInstanceOf(NullableStrategy::class, $nullableStragegy);
- }
-}
diff --git a/tests/Unit/Core/Hydrator/ReflectionHydratorTest.php b/tests/Unit/Core/Hydrator/ReflectionHydratorTest.php
deleted file mode 100644
index a6ea4b66..00000000
--- a/tests/Unit/Core/Hydrator/ReflectionHydratorTest.php
+++ /dev/null
@@ -1,49 +0,0 @@
-hydrator = new ReflectionHydrator();
- }
-
- public function testCanNotHydrate(): void
- {
- $hydrate = $this->hydrator->hydrate(false, User::class);
-
- self::assertNull($hydrate);
- }
-
- public function testCanHydrate(): void
- {
- $hydrate = $this->hydrator->hydrate(UserTestEntity::getDefaultUserValue(), User::class);
-
- self::assertInstanceOf(User::class, $hydrate);
- }
-
- public function testCanHydrateListWithoutData(): void
- {
- $hydrate = $this->hydrator->hydrateList([], User::class);
-
- self::assertIsArray($hydrate);
- self::assertSame(0, count($hydrate));
- }
-
- public function testCanHydrateListWithData(): void
- {
- $hydrate = $this->hydrator->hydrateList([0 => UserTestEntity::getDefaultUserValue()], User::class);
-
- self::assertIsArray($hydrate);
- self::assertArrayHasKey(0, $hydrate);
- self::assertInstanceOf(User::class, $hydrate[0]);
- }
-}
diff --git a/tests/Unit/Core/Middleware/ApiAccessMiddlewareTest.php b/tests/Unit/Core/Middleware/ApiAccessMiddlewareTest.php
deleted file mode 100644
index 2a01e12f..00000000
--- a/tests/Unit/Core/Middleware/ApiAccessMiddlewareTest.php
+++ /dev/null
@@ -1,57 +0,0 @@
-apiAccessService = new MockApiAccessService();
- }
-
- public function testReturnResponseInterfaceWithoutPort(): void
- {
- $middleware = new ApiAccessMiddleware($this->apiAccessService);
-
- $response = $middleware->process(
- $this->request->withHeader('Host', 'localhost'),
- $this->handler
- );
-
- self::assertInstanceOf(ResponseInterface::class, $response);
- }
-
- public function testReturnResponseInterfaceWithPort(): void
- {
- $middleware = new ApiAccessMiddleware($this->apiAccessService);
-
- $response = $middleware->process(
- $this->request->withHeader('Host', 'localhost:80'),
- $this->handler
- );
-
- self::assertInstanceOf(ResponseInterface::class, $response);
- }
-
- public function testReturnJSonResponse(): void
- {
- $middleware = new ApiAccessMiddleware($this->apiAccessService);
-
- $response = $middleware->process(
- $this->request->withHeader('Host', 'example.com'),
- $this->handler
- );
-
- self::assertInstanceOf(JsonResponse::class, $response);
- self::assertSame(HTTP::STATUS_UNAUTHORIZED, $response->getStatusCode());
- }
-}
diff --git a/tests/Unit/Core/Middleware/UpdateLastUserActionTimeMiddlewareTest.php b/tests/Unit/Core/Middleware/UpdateLastUserActionTimeMiddlewareTest.php
deleted file mode 100644
index 62b5d97f..00000000
--- a/tests/Unit/Core/Middleware/UpdateLastUserActionTimeMiddlewareTest.php
+++ /dev/null
@@ -1,36 +0,0 @@
-userService = new MockUserService();
- }
-
- public function testReturnResponseInterface(): void
- {
- $middleware = new UpdateLastUserActionTimeMiddleware($this->userService);
-
- $user = new User(...UserTestEntity::getDefaultUserValue());
-
- $response = $middleware->process(
- $this->request->withAttribute(User::AUTHENTICATED_USER, $user),
- $this->handler
- );
-
- self::assertInstanceOf(ResponseInterface::class, $response);
- }
-}
diff --git a/tests/Unit/Core/Middleware/UserMiddlewareTest.php b/tests/Unit/Core/Middleware/UserMiddlewareTest.php
deleted file mode 100644
index 04379e44..00000000
--- a/tests/Unit/Core/Middleware/UserMiddlewareTest.php
+++ /dev/null
@@ -1,48 +0,0 @@
-userService = new MockUserService();
- }
-
- public function testReturnResponseInterface(): void
- {
- $middleware = new UserMiddleware($this->userService);
-
- $response = $middleware->process(
- $this->request->withAttribute('userUuid', TestConstants::USER_UUID),
- $this->handler
- );
-
- self::assertInstanceOf(ResponseInterface::class, $response);
- }
-
- public function testReturnStatusNotFound(): void
- {
- $middleware = new UserMiddleware($this->userService);
-
- $response = $middleware->process(
- $this->request->withAttribute('userUuid', '-'),
- $this->handler
- );
-
- self::assertInstanceOf(JsonResponse::class, $response);
- self::assertSame($response->getStatusCode(), HTTP::STATUS_NOT_FOUND);
- }
-}
diff --git a/tests/Unit/Core/Service/AbstractService.php b/tests/Unit/Core/Service/AbstractService.php
deleted file mode 100644
index 0f725b8d..00000000
--- a/tests/Unit/Core/Service/AbstractService.php
+++ /dev/null
@@ -1,33 +0,0 @@
-hydrator = new ReflectionHydrator();
- $this->dateTimeFormatterStrategy = new DateTimeFormatterStrategy();
- $this->dateTimeImmutableFormatterStrategy = new DateTimeImmutableFormatterStrategy(new DateTimeFormatterStrategy('Y-m-d H:i:s'));
- $this->nullableStrategy = new NullableStrategy($this->dateTimeFormatterStrategy);
- $this->uuidStrategy = new UuidStrategy();
- $this->uuid = Uuid::uuid4();
- parent::setUp();
- }
-}
diff --git a/tests/Unit/Core/Service/ApiAccessServiceFactoryTest.php b/tests/Unit/Core/Service/ApiAccessServiceFactoryTest.php
deleted file mode 100644
index 578c66be..00000000
--- a/tests/Unit/Core/Service/ApiAccessServiceFactoryTest.php
+++ /dev/null
@@ -1,37 +0,0 @@
- [
- 'access' => [
- 'domain' => [
- 'whitelist' => [
- 'localhost',
- ],
- ],
- ],
- ],
- ];
-
- $container = new MockContainer(['config' => $config]);
-
- $apiAccessService = (new ApiAccessServiceFactory())($container);
-
- self::assertInstanceOf(ApiAccessService::class, $apiAccessService);
- }
-}
diff --git a/tests/Unit/Core/Service/ApiAccessServiceTest.php b/tests/Unit/Core/Service/ApiAccessServiceTest.php
deleted file mode 100644
index a92ed312..00000000
--- a/tests/Unit/Core/Service/ApiAccessServiceTest.php
+++ /dev/null
@@ -1,38 +0,0 @@
-config = [
- 'domain' => [
- 'whitelist' => [
- 'localhost',
- ],
- ],
- ];
-
- $this->apiAccessService = new ApiAccessService($this->config);
- }
-
- public function testHasAccessRights(): void
- {
- $hasRights = $this->apiAccessService->hasAccessRights('localhost');
- self::assertSame(true, $hasRights);
- }
-
- public function testHasAccessNotRights(): void
- {
- $hasRights = $this->apiAccessService->hasAccessRights('example.com');
- self::assertSame(false, $hasRights);
- }
-}
diff --git a/tests/Unit/Core/Service/TokenServiceTest.php b/tests/Unit/Core/Service/TokenServiceTest.php
deleted file mode 100644
index b2603e1a..00000000
--- a/tests/Unit/Core/Service/TokenServiceTest.php
+++ /dev/null
@@ -1,18 +0,0 @@
-generateToken();
-
- self::assertIsString($token);
- self::assertSame(32, strlen($token));
- }
-}
diff --git a/tests/Unit/Core/Service/UserServiceFactoryTest.php b/tests/Unit/Core/Service/UserServiceFactoryTest.php
deleted file mode 100644
index 70381c4f..00000000
--- a/tests/Unit/Core/Service/UserServiceFactoryTest.php
+++ /dev/null
@@ -1,33 +0,0 @@
- new MockUserTable(),
- ReflectionHydrator::class => $this->hydrator,
- NullableStrategy::class => $this->nullableStrategy,
- DateTimeImmutableFormatterStrategy::class => $this->dateTimeImmutableFormatterStrategy,
- Uuid::class => Uuid::uuid4(),
- ]);
-
- $factory = new UserServiceFactory();
-
- $service = $factory($container);
-
- self::assertInstanceOf(UserService::class, $service);
- }
-}
diff --git a/tests/Unit/Core/Service/UserServiceTest.php b/tests/Unit/Core/Service/UserServiceTest.php
deleted file mode 100644
index f564953c..00000000
--- a/tests/Unit/Core/Service/UserServiceTest.php
+++ /dev/null
@@ -1,134 +0,0 @@
-hydrator->addStrategy(UuidStrategy::class, $this->uuidStrategy);
- $this->userService = new UserService($table, $this->hydrator, $this->uuid);
- }
-
- public function testCanNotCreateUserWithExistUser(): void
- {
- $user = new User(...UserTestEntity::getDefaultUserValue());
- $user = $user->with(name: TestConstants::USER_NAME);
-
- self::expectException(DuplicateEntryException::class);
-
- $this->userService->create($user);
- }
-
- public function testCanNotCreateUserWithExistEmail(): void
- {
- $user = new User(...UserTestEntity::getDefaultUserValue());
- $user = $user->with(email: TestConstants::USER_EMAIL);
-
- self::expectException(DuplicateEntryException::class);
-
- $this->userService->create($user);
- }
-
- public function testCanCreateUser(): void
- {
- $user = new User(...UserTestEntity::getDefaultUserValue());
- $user = $user->with(
- name: TestConstants::USER_CREATE_NAME,
- email: TestConstants::USER_CREATE_EMAIL,
- );
-
- $insert = $this->userService->create($user);
-
- self::assertSame(1, $insert);
- }
-
- public function testCanNotCreateUser(): void
- {
- $user = new User(...UserTestEntity::getDefaultUserValue());
- $user = $user->with(
- name: TestConstants::USER_NAME,
- email: TestConstants::USER_EMAIL,
- );
-
- self::expectException(DuplicateEntryException::class);
-
- $this->userService->create($user);
- }
-
- public function testCanUpdateLastUserActionTime(): void
- {
- $user = new User(...UserTestEntity::getDefaultUserValue());
- $user = $user->with(
- id: TestConstants::USER_ID,
- lastActionAt: new DateTimeImmutable(),
- );
-
- $update = $this->userService->updateLastUserActionTime($user);
-
- self::assertInstanceOf(User::class, $update);
- }
-
- public function testCanNotUpdateUser(): void
- {
- $user = new User(...UserTestEntity::getDefaultUserValue());
- $user = $user->with(id: TestConstants::USER_ID_UNUSED);
-
- self::expectException(InvalidArgumentException::class);
-
- $this->userService->update($user);
- }
-
- public function testCanUpdateUser(): void
- {
- $user = new User(...UserTestEntity::getDefaultUserValue());
- $user = $user->with(id: TestConstants::USER_ID);
-
- $update = $this->userService->update($user);
-
- self::assertSame(true, $update);
- }
-
- public function testFindByIdResultIsNull(): void
- {
- $result = $this->userService->findById(TestConstants::USER_ID_UNUSED);
-
- self::assertNull($result);
- }
-
- public function testCanFindById(): void
- {
- $user = $this->userService->findById(TestConstants::USER_ID);
-
- self::assertInstanceOf(User::class, $user);
- }
-
- public function testCanFindByUuid(): void
- {
- $user = $this->userService->findByUuid(TestConstants::USER_UUID);
-
- self::assertInstanceOf(User::class, $user);
- }
-
- public function testCanNotFindByUuid(): void
- {
- $user = $this->userService->findByUuid(TestConstants::USER_UUID_UNUSED);
-
- self::assertNull($user);
- }
-}
diff --git a/tests/Unit/Core/Table/AbstractTable.php b/tests/Unit/Core/Table/AbstractTable.php
deleted file mode 100644
index 1cf05318..00000000
--- a/tests/Unit/Core/Table/AbstractTable.php
+++ /dev/null
@@ -1,39 +0,0 @@
- 1];
- protected array $fetchAllResult
- = [
- 0 => ['id' => 1],
- ];
-
- protected function setUp(): void
- {
- $this->query = new MockQuery();
-
- preg_match('@(Core.*|App.*)@i', get_class($this), $table);
-
- $this->table = new (
- substr($table[0], self::TABLE_NAME_OFFSET, self::TABLE_SUB_LENGTH)
- )(
- $this->query
- );
- }
-}
diff --git a/tests/Unit/Core/Table/UserTableTest.php b/tests/Unit/Core/Table/UserTableTest.php
deleted file mode 100644
index 6a6d5fd7..00000000
--- a/tests/Unit/Core/Table/UserTableTest.php
+++ /dev/null
@@ -1,158 +0,0 @@
-table->getTableName());
- }
-
- public function testCanInsertUser(): void
- {
- $user = new User(...UserTestEntity::getDefaultUserValue());
- $user = $user->with(name: TestConstants::USER_CREATE_NAME);
-
- $affectedRowCount = $this->table->insert($user);
-
- self::assertSame(1, $affectedRowCount);
- }
-
- public function testCanNotInsertUser(): void
- {
- $user = new User(...UserTestEntity::getDefaultUserValue());
- $user = $user->with(name: TestConstants::USER_NAME);
-
- self::expectException(DuplicateEntryException::class);
-
- $this->table->insert($user);
- }
-
- public function testCanUpdateUser(): void
- {
- $user = new User(...UserTestEntity::getDefaultUserValue());
- $user = $user->with(
- id: TestConstants::USER_ID,
- registrationAt: new DateTimeImmutable(),
- lastActionAt: new DateTimeImmutable(),
- );
-
- $updateUser = $this->table->update($user);
-
- self::assertSame(1, $updateUser);
- }
-
- public function testUpdateUserThrowException(): void
- {
- $user = new User(...UserTestEntity::getDefaultUserValue());
- $user = $user->with(
- id: TestConstants::USER_ID_THROW_EXCEPTION,
- lastActionAt: new DateTimeImmutable(),
- );
-
- $table = new UserTable(new MockQueryForCanNot());
-
- self::expectException(InvalidArgumentException::class);
-
- $table->update($user);
- }
-
- public function testCanUpdateLastUserActionTime(): void
- {
- $updateUser = $this->table->updateLastUserActionTime(TestConstants::USER_ID, new DateTime());
-
- self::assertInstanceOf(UserTable::class, $updateUser);
- }
-
- public function testUpdateLastUserActionTimeThrowException(): void
- {
- self::expectException(InvalidArgumentException::class);
-
- $this->table->updateLastUserActionTime(TestConstants::USER_ID_THROW_EXCEPTION, new DateTime());
- }
-
- public function testCanFindById(): void
- {
- $user = $this->table->findById(TestConstants::USER_ID);
-
- self::assertEquals(UserTestEntity::getDefaultUserValue(), $user);
- }
-
- public function testFindByIdHasEmptyResult(): void
- {
- $user = $this->table->findById(TestConstants::USER_ID_UNUSED);
-
- self::assertSame([], $user);
- }
-
- public function testCanFindByUuid(): void
- {
- $user = $this->table->findByUuid(TestConstants::USER_UUID);
-
- self::assertEquals(UserTestEntity::getDefaultUserValue(), $user);
- }
-
- public function testFindByUuidHasEmptyResult(): void
- {
- $user = $this->table->findByUuid(TestConstants::USER_UUID_UNUSED);
-
- self::assertSame([], $user);
- }
-
- public function testCanFindAll(): void
- {
- $users = $this->table->findAll();
-
- self::assertEquals([0 => UserTestEntity::getDefaultUserValue()], $users);
- }
-
- public function testFindAllReturnedEmpty(): void
- {
- $table = new UserTable(new MockQueryForCanNot());
- $users = $table->findAll();
-
- self::assertSame([], $users);
- }
-
- public function testCanFindByName(): void
- {
- $user = $this->table->findByName(TestConstants::USER_NAME);
-
- self::assertEquals(UserTestEntity::getDefaultUserValue(), $user);
- }
-
- public function testFindByNameHasEmptyResult(): void
- {
- $user = $this->table->findByName(TestConstants::USER_NAME_UNUSED);
-
- self::assertSame([], $user);
- }
-
- public function testCanFindByEmail(): void
- {
- $user = $this->table->findByEMail(TestConstants::USER_EMAIL);
-
- self::assertEquals(UserTestEntity::getDefaultUserValue(), $user);
- }
-
- public function testFindByEmailHasEmptyResult(): void
- {
- $user = $this->table->findByEMail(TestConstants::USER_EMAIL_UNUSED);
-
- self::assertSame([], $user);
- }
-}
diff --git a/tests/Unit/Mock/Database/MockInsert.php b/tests/Unit/Mock/Database/MockInsert.php
deleted file mode 100644
index c7409a2b..00000000
--- a/tests/Unit/Mock/Database/MockInsert.php
+++ /dev/null
@@ -1,58 +0,0 @@
-handle($this->statements['INSERT INTO'], $this->statements['VALUES']);
- }
-
- private function handle(string $table, array $values): int|bool
- {
- return match($table) {
- 'Event', 'MockEvent' => $this->handleEvent($values),
- 'User', 'MockUser' => $this->handleUser($values),
- 'Participant', 'MockParticipant' => $this->handleParticipant($values),
- default => false,
- };
- }
-
- private function handleEvent(array $values): int|bool
- {
- if ($values[0]['title'] === TestConstants::EVENT_CREATE_TITLE) {
- return 1;
- }
-
- return false;
- }
-
- private function handleParticipant(array $values): int|bool
- {
- if ($values[0]['userId'] === TestConstants::USER_CREATE_ID) {
- return 1;
- }
-
- return false;
- }
-
- private function handleUser(array $values): int|bool
- {
-
- if ($values[0]['name'] === TestConstants::USER_CREATE_NAME) {
- return 1;
- }
-
- return false;
- }
-}
diff --git a/tests/Unit/Mock/Database/MockSelect.php b/tests/Unit/Mock/Database/MockSelect.php
deleted file mode 100644
index bf779e70..00000000
--- a/tests/Unit/Mock/Database/MockSelect.php
+++ /dev/null
@@ -1,144 +0,0 @@
-statements['SELECT'])
- && $this->statements['SELECT'][1] === 'COUNT(id) AS countTopic'
- ) {
- return [
- 'countTopic' => 1,
- ];
- }
-
- if (array_key_exists('WHERE', $this->statements)) {
- return $this->handle($this->statements['FROM'], $this->statements['WHERE'], $this->parameters['WHERE']);
- }
-
- return false;
- }
-
- public function fetchAll($index = '', $selectOnly = ''): array
- {
- return match ($this->getFromTable()) {
- 'MockEvent', 'Event' => [0 => EventTestEntity::getDefaultEventValue()],
- 'MockParticipant', 'Participant' => [0 => ParticipantTestEntity::getDefaultParticipantValue()],
- 'MockProject', 'Project' => [0 => ProjectTestEntity::getDefaultProjectValue()],
- 'MockRole', 'Role' => [0 => RoleTestEntity::getDefaultRoleValue()],
- 'MockTopicPool', 'TopicPool' => [0 => TopicTestEntity::getDefaultTopicValue()],
- 'MockUser', 'User' => [0 => UserTestEntity::getDefaultUserValue()],
- default => [],
- };
- }
-
- private function handle(string $from, array $where, array $params): bool|array
- {
- return match ($from) {
- 'Event' => $this->handleEvent($where, $params),
- 'Participant' => $this->handleParticipant($where, $params),
- 'Project' => $this->handleProject($where, $params),
- 'TopicPool' => $this->handleTopic($where, $params),
- 'User' => $this->handleUser($where, $params),
- default => false
- };
- }
-
- private function handleEvent(array $where, array $params): array
- {
- return match ($where[0][1]) {
- 'id = ?' => $params[0] === TestConstants::EVENT_ID
- ? ['id' => TestConstants::EVENT_ID] + EventTestEntity::getDefaultEventValue()
- : [],
- 'title = ?' => $params[0] === TestConstants::EVENT_TITLE
- ? ['id' => TestConstants::EVENT_ID] + EventTestEntity::getDefaultEventValue()
- : [],
- default => []
- };
- }
-
- private function handleParticipant(array $where, array $params): array
- {
- return match ($where[0][1]) {
- 'id = ?' => $params[0] === TestConstants::PARTICIPANT_ID
- ? ['id' => TestConstants::PARTICIPANT_ID] + ParticipantTestEntity::getDefaultParticipantValue()
- : [],
- 'userId = ?' => $params[0] === TestConstants::USER_ID
- ? ['id' => TestConstants::PARTICIPANT_ID] + ParticipantTestEntity::getDefaultParticipantValue()
- : [],
- default => []
- };
- }
-
- private function handleProject(array $where, array $params): array
- {
- return match ($where[0][1]) {
- 'id = ?' => $params[0] === TestConstants::PROJECT_ID
- ? ['id' => TestConstants::PROJECT_ID] + ProjectTestEntity::getDefaultProjectValue()
- : [],
- 'participantId = ?' =>
- $params[0] === TestConstants::PARTICIPANT_ID
- ? ['id' => TestConstants::PROJECT_ID] + ProjectTestEntity::getDefaultProjectValue()
- : [],
- default => []
- };
- }
-
- private function handleTopic(array $where, array $params): array
- {
- return match ($where[0][1]) {
- 'id = ?' => $params[0] === TestConstants::TOPIC_ID
- ? ['id' => TestConstants::TOPIC_ID] + TopicTestEntity::getDefaultTopicValue()
- : [],
- 'uuid = ?' => $params[0] === TestConstants::TOPIC_UUID
- ? ['id' => TestConstants::TOPIC_ID] + TopicTestEntity::getDefaultTopicValue()
- : [],
- 'eventId = ?' => $params[0] === TestConstants::EVENT_ID
- ? ['id' => TestConstants::TOPIC_ID] + TopicTestEntity::getDefaultTopicValue()
- : [],
- 'topic = ?' => $params[0] === TestConstants::TOPIC_TITLE
- ? ['id' => TestConstants::TOPIC_ID] + TopicTestEntity::getDefaultTopicValue()
- : [],
- default => []
- };
- }
-
- private function handleUser(array $where, array $params): array
- {
- return match ($where[0][1]) {
- 'id = ?' => $params[0] === TestConstants::USER_ID
- ? ['id' => TestConstants::USER_ID] + UserTestEntity::getDefaultUserValue()
- : [],
- 'uuid = ?' => $params[0] === TestConstants::USER_UUID
- ? ['id' => TestConstants::USER_ID] + UserTestEntity::getDefaultUserValue()
- : [],
- 'name = ?' => $params[0] === TestConstants::USER_NAME
- ? ['id' => TestConstants::USER_ID] + UserTestEntity::getDefaultUserValue()
- : [],
- 'email = ?' => $params[0] === TestConstants::USER_EMAIL
- ? ['id' => TestConstants::USER_ID] + UserTestEntity::getDefaultUserValue()
- : [],
- default => [],
- };
- }
-}
diff --git a/tests/Unit/Mock/Database/MockSelectForFetchAll.php b/tests/Unit/Mock/Database/MockSelectForFetchAll.php
deleted file mode 100644
index 7936b6c9..00000000
--- a/tests/Unit/Mock/Database/MockSelectForFetchAll.php
+++ /dev/null
@@ -1,109 +0,0 @@
-statements['SELECT'])
- && $this->statements['SELECT'][1] === 'COUNT(id) AS countTopic'
- ) {
- return [
- 'countTopic' => 1,
- ];
- }
-
- if (array_key_exists('WHERE', $this->statements)) {
- return $this->handle($this->statements['FROM'], $this->statements['WHERE'], $this->parameters['WHERE']);
- }
-
- return false;
- }
-
- public function fetchAll($index = '', $selectOnly = ''): array
- {
- return [];
- }
-
- private function handle(string $from, array $where, array $params): bool|array
- {
- return match ($from) {
- 'Event' => $this->handleEvent($where, $params),
- 'Participant' => $this->handleParticipant($where, $params),
- 'Project' => $this->handleProject($where, $params),
- 'TopicPool' => $this->handleTopic($where, $params),
- 'User' => $this->handleUser($where, $params),
- default => false
- };
- }
-
- private function handleEvent(array $where, array $params): array
- {
- return match ($where[0][1]) {
- 'title = ?' => $params[0] === TestConstants::EVENT_TITLE ? EventTestEntity::getDefaultEventValue() : [],
- 'id = ?' => $params[0] === TestConstants::EVENT_ID ? EventTestEntity::getDefaultEventValue() : [],
- default => []
- };
- }
-
- private function handleParticipant(array $where, array $params): array
- {
- return match ($where[0][1]) {
- 'id = ?' => $params[0] === TestConstants::PARTICIPANT_ID
- ? ParticipantTestEntity::getDefaultParticipantValue() : [],
- 'userId = ?' => $params[0] === TestConstants::USER_ID ? ParticipantTestEntity::getDefaultParticipantValue()
- : [],
- default => []
- };
- }
-
- private function handleProject(array $where, array $params): array
- {
- return match ($where[0][1]) {
- 'id = ?' => $params[0] === TestConstants::PROJECT_ID ? ProjectTestEntity::getDefaultProjectValue() : [],
- 'participantId = ?' => $params[0] === TestConstants::PARTICIPANT_ID
- ? ProjectTestEntity::getDefaultProjectValue() : [],
- default => []
- };
- }
-
- private function handleTopic(array $where, array $params): array
- {
- return match ($where[0][1]) {
- 'id = ?' => $params[0] === TestConstants::TOPIC_ID ? TopicTestEntity::getDefaultTopicValue() : [],
- 'uuid = ?' => $params[0] === TestConstants::TOPIC_UUID ? TopicTestEntity::getDefaultTopicValue() : [],
- 'eventId = ?' => $params[0] === TestConstants::EVENT_ID ? TopicTestEntity::getDefaultTopicValue() : [],
- 'topic = ?' => $params[0] === TestConstants::TOPIC_TITLE ? TopicTestEntity::getDefaultTopicValue() : [],
- default => []
- };
- }
-
- private function handleUser(array $where, array $params): array
- {
- return match ($where[0][1]) {
- 'id = ?' => $params[0] === TestConstants::USER_ID ? UserTestEntity::getDefaultUserValue() : [],
- 'uuid = ?' => $params[0] === TestConstants::USER_UUID ? UserTestEntity::getDefaultUserValue() : [],
- 'name = ?' => $params[0] === TestConstants::USER_NAME ? UserTestEntity::getDefaultUserValue() : [],
- 'email = ?' => $params[0] === TestConstants::USER_EMAIL ? UserTestEntity::getDefaultUserValue() : [],
- default => []
- };
- }
-}
diff --git a/tests/Unit/Mock/Database/MockUpdate.php b/tests/Unit/Mock/Database/MockUpdate.php
deleted file mode 100644
index 5824db9f..00000000
--- a/tests/Unit/Mock/Database/MockUpdate.php
+++ /dev/null
@@ -1,46 +0,0 @@
-statements['UPDATE']) {
- 'User', 'MockUser' => $this->handleUser(),
- default => true
- };
- }
-
- private function handleUser(): bool|int
- {
- if (array_key_exists('SET', $this->statements)) {
- if ($this->statements['SET'] === []) {
- return 1;
- }
-
- if ($this->statements['SET']['lastActionAt']) {
- return match ($this->statements['WHERE'][0][1]) {
- 'id = ?' => $this->parameters['WHERE'][0] === TestConstants::USER_ID ? 1 : false,
- default => 1
- };
- }
- }
-
- return false;
- }
-}
diff --git a/tests/Unit/Mock/Database/MockUpdateForNotUpdate.php b/tests/Unit/Mock/Database/MockUpdateForNotUpdate.php
deleted file mode 100644
index 0826c8ec..00000000
--- a/tests/Unit/Mock/Database/MockUpdateForNotUpdate.php
+++ /dev/null
@@ -1,46 +0,0 @@
-statements['UPDATE']) {
- 'User', 'MockUser' => $this->handleUser(),
- default => true
- };
- }
-
- private function handleUser(): bool|int
- {
- if (array_key_exists('SET', $this->statements)) {
- if ($this->statements['SET'] === []) {
- return false;
- }
-
- if ($this->statements['SET']['lastAction']) {
- return match ($this->statements['WHERE'][0][1]) {
- 'id = ?' => $this->parameters['WHERE'][0] === TestConstants::USER_ID ? 1 : false,
- default => 1
- };
- }
- }
-
- return false;
- }
-}
diff --git a/tests/Unit/Mock/MockResponse.php b/tests/Unit/Mock/MockResponse.php
deleted file mode 100644
index e8ecab1f..00000000
--- a/tests/Unit/Mock/MockResponse.php
+++ /dev/null
@@ -1,79 +0,0 @@
-headers;
- }
-
- public function hasHeader($name)
- {
- // TODO: Implement hasHeader() method.
- }
-
- public function getHeader($name)
- {
- return array_key_exists($name, $this->headers) ? $this->headers[$name] : null;
- }
-
- public function getHeaderLine($name)
- {
- // TODO: Implement getHeaderLine() method.
- }
-
- public function withHeader($name, $value)
- {
- $this->headers[$name] = $value;
-
- return clone $this;
- }
-
- public function withAddedHeader($name, $value)
- {
- // TODO: Implement withAddedHeader() method.
- }
-
- public function withoutHeader($name)
- {
- // TODO: Implement withoutHeader() method.
- }
-
- public function getBody()
- {
- return $this->body;
- }
-
- public function withBody(StreamInterface $body)
- {
- // TODO: Implement withBody() method.
- }
-
- public function getRequestTarget()
- {
- // TODO: Implement getRequestTarget() method.
- }
-
- public function withRequestTarget($requestTarget)
- {
- // TODO: Implement withRequestTarget() method.
- }
-
- public function getMethod()
- {
- // TODO: Implement getMethod() method.
- }
-
- public function withMethod($method)
- {
- // TODO: Implement withMethod() method.
- }
-
- public function getUri()
- {
- // TODO: Implement getUri() method.
- }
-
- public function withUri(UriInterface $uri, $preserveHost = false)
- {
- // TODO: Implement withUri() method.
- }
-
- public function getServerParams()
- {
- // TODO: Implement getServerParams() method.
- }
-
- public function getCookieParams()
- {
- // TODO: Implement getCookieParams() method.
- }
-
- public function withCookieParams(array $cookies)
- {
- // TODO: Implement withCookieParams() method.
- }
-
- public function getQueryParams()
- {
- return $this->queryParams;
- }
-
- public function withQueryParams(array $query): self
- {
- $this->queryParams = $query;
-
- return clone $this;
- }
-
- public function getUploadedFiles()
- {
- // TODO: Implement getUploadedFiles() method.
- }
-
- public function withUploadedFiles(array $uploadedFiles)
- {
- // TODO: Implement withUploadedFiles() method.
- }
-
- public function getParsedBody()
- {
- return $this->body;
- }
-
- public function withParsedBody($data)
- {
- $this->body = $data;
-
- return clone $this;
- }
-
- public function getAttributes()
- {
- // TODO: Implement getAttributes() method.
- }
-
- public function getAttribute($name, $default = null)
- {
- if (array_key_exists($name, $this->attributes)) {
- return $this->attributes[$name];
- }
-
- return $default;
- }
-
- public function withAttribute($name, $value): MockServerRequest
- {
- $this->attributes[$name] = $value;
-
- return clone $this;
- }
-
- public function withoutAttribute($name)
- {
- // TODO: Implement withoutAttribute() method.
- }
-}
diff --git a/tests/Unit/Mock/Service/MockApiAccessService.php b/tests/Unit/Mock/Service/MockApiAccessService.php
deleted file mode 100644
index f599f871..00000000
--- a/tests/Unit/Mock/Service/MockApiAccessService.php
+++ /dev/null
@@ -1,18 +0,0 @@
-id === TestConstants::EVENT_ID_NOT_REMOVED;
- }
-
- public function findById(int $id): Event
- {
- if ($id === TestConstants::EVENT_ID) {
- return new Event(...EventTestEntity::getDefaultEventValue());
- }
-
- throw new InvalidArgumentException('Could not find Event', HTTP::STATUS_BAD_REQUEST);
- }
-
- public function findByTitle(string $topic): ?Event
- {
- if ($topic === TestConstants::EVENT_TITLE_THROW_EXCEPTION) {
- throw new InvalidArgumentException(code: HTTP::STATUS_BAD_REQUEST);
- }
- if ($topic === TestConstants::EVENT_TITLE) {
- return new Event(...EventTestEntity::getDefaultEventValue());
- }
-
- return null;
- }
-}
diff --git a/tests/Unit/Mock/Service/MockTopicCreateEMailService.php b/tests/Unit/Mock/Service/MockTopicCreateEMailService.php
deleted file mode 100644
index c1026981..00000000
--- a/tests/Unit/Mock/Service/MockTopicCreateEMailService.php
+++ /dev/null
@@ -1,14 +0,0 @@
-with(lastActionAt: new DateTimeImmutable(TestConstants::TIME));
- }
-}
diff --git a/tests/Unit/Mock/Table/MockEventTable.php b/tests/Unit/Mock/Table/MockEventTable.php
deleted file mode 100644
index 9e5c739e..00000000
--- a/tests/Unit/Mock/Table/MockEventTable.php
+++ /dev/null
@@ -1,44 +0,0 @@
- [
- 'id' => $id,
- 'ratingCompleted' => true,
- ] + EventTestEntity::getDefaultEventValue(),
-
- TestConstants::EVENT_ID_RATING_NOT_COMPLETED => [
- 'id' => $id,
- 'ratingCompleted' => false,
- ] + EventTestEntity::getDefaultEventValue(),
-
- default => []
- };
- }
-
- public function findByTitle(string $title): array
- {
- return match ($title) {
- TestConstants::EVENT_TITLE => [
- 'title' => $title,
- ] + EventTestEntity::getDefaultEventValue(),
-
- default => []
- };
- }
-}
diff --git a/tests/Unit/Mock/Table/MockParticipantTable.php b/tests/Unit/Mock/Table/MockParticipantTable.php
deleted file mode 100644
index fefab7f8..00000000
--- a/tests/Unit/Mock/Table/MockParticipantTable.php
+++ /dev/null
@@ -1,45 +0,0 @@
-id === TestConstants::PARTICIPANT_ID;
- }
-
- public function findById(int $id): array
- {
- return $id === TestConstants::PARTICIPANT_ID ? ['id' => $id]
- + ParticipantTestEntity::getDefaultParticipantValue() : [];
- }
-
- public function findByUserId(int $userId): array
- {
- return $userId === TestConstants::USER_ID
- ? ['userId' => $userId] + ParticipantTestEntity::getDefaultParticipantValue()
- : [];
- }
-
- public function findUserForAnEvent(int $userId, int $eventId): array
- {
- return $userId === TestConstants::USER_ID && $eventId === TestConstants::EVENT_ID
- ? [
- 'userId' => $userId,
- 'eventId' => $eventId,
- ] + ParticipantTestEntity::getDefaultParticipantValue()
- : [];
- }
-}
diff --git a/tests/Unit/Mock/Table/MockProjectTable.php b/tests/Unit/Mock/Table/MockProjectTable.php
deleted file mode 100644
index 8bde0afd..00000000
--- a/tests/Unit/Mock/Table/MockProjectTable.php
+++ /dev/null
@@ -1,28 +0,0 @@
- $id] + ProjectTestEntity::getDefaultProjectValue() : [];
- }
-
- public function findByParticipantId(int $id): array
- {
- return $id === TestConstants::PARTICIPANT_ID
- ? ['participantId' => $id] + ProjectTestEntity::getDefaultProjectValue()
- : [];
- }
-}
diff --git a/tests/Unit/Mock/Table/MockTopicPoolTable.php b/tests/Unit/Mock/Table/MockTopicPoolTable.php
deleted file mode 100644
index 4f567907..00000000
--- a/tests/Unit/Mock/Table/MockTopicPoolTable.php
+++ /dev/null
@@ -1,46 +0,0 @@
- $id] + TopicTestEntity::getDefaultTopicValue() : [];
- }
-
- public function findByEventId(int $eventId): array
- {
- return $eventId === TestConstants::EVENT_ID
- ? ['eventId' => $eventId] + TopicTestEntity::getDefaultTopicValue()
- : [];
- }
-
- public function findByTopic(string $topic): array
- {
- return $topic === TestConstants::TOPIC_TITLE
- ? ['topic' => $topic] + TopicTestEntity::getDefaultTopicValue()
- : [];
- }
-}
diff --git a/tests/Unit/Mock/Table/MockUserTable.php b/tests/Unit/Mock/Table/MockUserTable.php
deleted file mode 100644
index 15f26e44..00000000
--- a/tests/Unit/Mock/Table/MockUserTable.php
+++ /dev/null
@@ -1,50 +0,0 @@
-id !== TestConstants::USER_ID) {
- throw new InvalidArgumentException();
- }
-
- return 1;
- }
-
- public function findById(int $id): array
- {
- return $id === TestConstants::USER_ID ? ['id' => $id] + UserTestEntity::getDefaultUserValue() : [];
- }
-
- public function findByUuid(string $uuid): array
- {
- return $uuid === TestConstants::USER_UUID
- ? ['uuid' => UuidV7::fromString($uuid)] + UserTestEntity::getDefaultUserValue()
- : [];
- }
-
- public function findByName(string $name): array
- {
- return $name === TestConstants::USER_NAME ? ['name' => $name] + UserTestEntity::getDefaultUserValue() : [];
- }
-
- public function findByEMail(string $email): array
- {
- return $email === TestConstants::USER_EMAIL ? ['email' => $email] + UserTestEntity::getDefaultUserValue() : [];
- }
-}
diff --git a/tests/Unit/Mock/Validator/MockEventCreateValidator.php b/tests/Unit/Mock/Validator/MockEventCreateValidator.php
deleted file mode 100644
index 6599f0d0..00000000
--- a/tests/Unit/Mock/Validator/MockEventCreateValidator.php
+++ /dev/null
@@ -1,43 +0,0 @@
-data = $data;
-
- return $this;
- }
-
- public function isValid($context = null): bool
- {
- return $this->data[0];
- }
-
- public function getValues(): mixed
- {
- return $this->data;
- }
-}
diff --git a/tests/Unit/Mock/Validator/MockTopicCreateValidator.php b/tests/Unit/Mock/Validator/MockTopicCreateValidator.php
deleted file mode 100644
index 9a2c70d4..00000000
--- a/tests/Unit/Mock/Validator/MockTopicCreateValidator.php
+++ /dev/null
@@ -1,20 +0,0 @@
-request = new MockServerRequest();
- $this->hydrator = new ReflectionHydrator();
+
parent::setUp();
}
}
diff --git a/tests/UnitTest/AppTest/Handler/AuthenticationHandlerTest.php b/tests/UnitTest/AppTest/Handler/AuthenticationHandlerTest.php
new file mode 100644
index 00000000..c7825b14
--- /dev/null
+++ b/tests/UnitTest/AppTest/Handler/AuthenticationHandlerTest.php
@@ -0,0 +1,35 @@
+request->withAttribute(AccessToken::class, AccessToken::fromString(Token::ACCESS_TOKEN_VALID))
+ ->withAttribute(RefreshToken::class, RefreshToken::fromString(Token::REFRESH_TOKEN_VALID));
+
+ $authenticationHandler = new AuthenticationHandler();
+
+ $response = $authenticationHandler->handle($request);
+
+ $json = json_decode((string)$response->getBody(), null, 512, JSON_THROW_ON_ERROR);
+
+ $this->assertInstanceOf(JsonResponse::class, $response);
+ $this->assertSame(HTTP::STATUS_OK, $response->getStatusCode());
+ $this->assertTrue(property_exists($json, 'accessToken') && $json->accessToken === Token::ACCESS_TOKEN_VALID);
+ $this->assertTrue(property_exists($json, 'refreshToken') && $json->refreshToken === Token::REFRESH_TOKEN_VALID);
+ }
+}
diff --git a/tests/UnitTest/AppTest/Handler/PingHandlerTest.php b/tests/UnitTest/AppTest/Handler/PingHandlerTest.php
new file mode 100644
index 00000000..ba820e46
--- /dev/null
+++ b/tests/UnitTest/AppTest/Handler/PingHandlerTest.php
@@ -0,0 +1,29 @@
+handle(
+ $this->createMock(ServerRequestInterface::class)
+ );
+
+ $json = json_decode((string)$response->getBody(), null, 512, JSON_THROW_ON_ERROR);
+
+ self::assertInstanceOf(JsonResponse::class, $response);
+ self::assertTrue(property_exists($json, 'ack') && $json->ack !== null);
+ }
+}
diff --git a/tests/UnitTest/AppTest/Hydrator/AccountAccessAuthHydratorTest.php b/tests/UnitTest/AppTest/Hydrator/AccountAccessAuthHydratorTest.php
new file mode 100644
index 00000000..5675db67
--- /dev/null
+++ b/tests/UnitTest/AppTest/Hydrator/AccountAccessAuthHydratorTest.php
@@ -0,0 +1,55 @@
+hydrate(AccountAccessAuth::VALID_DATA);
+
+ $this->assertInstanceOf(AccountAccessAuthInterface::class, $account);
+ $this->assertSame(AccountAccessAuth::ID, $account->id);
+ }
+
+ public function testCanHydrateAccountAccessAuthCollection(): void
+ {
+ $hydrator = new AccountAccessAuthHydrator();
+
+ $accounts = $hydrator->hydrateCollection([AccountAccessAuth::VALID_DATA]);
+
+ $this->assertInstanceOf(AccountAccessAuthCollectionInterface::class, $accounts);
+ $this->assertInstanceOf(AccountAccessAuthInterface::class, $accounts[0]);
+ $this->assertSame(AccountAccessAuth::ID, $accounts[0]->id);
+ }
+
+ public function testCanExtractAccountAccessAuth(): void
+ {
+ $hydrator = new AccountAccessAuthHydrator();
+
+ $account = $hydrator->hydrate(AccountAccessAuth::VALID_DATA);
+ $account = $hydrator->extract($account);
+
+ $this->assertIsArray($account);
+ $this->assertSame(AccountAccessAuth::VALID_DATA, $account);
+ }
+
+ public function testCanExtractAccountAccessAuthCollection(): void
+ {
+ $hydrator = new AccountAccessAuthHydrator();
+ $accounts = $hydrator->hydrateCollection([AccountAccessAuth::VALID_DATA]);
+ $accounts = $hydrator->extractCollection($accounts);
+
+ $this->assertIsArray($accounts);
+ $this->assertArrayHasKey(0, $accounts);
+ $this->assertSame(AccountAccessAuth::VALID_DATA, $accounts[0]);
+ }
+}
diff --git a/tests/UnitTest/AppTest/Hydrator/AccountHydratorTest.php b/tests/UnitTest/AppTest/Hydrator/AccountHydratorTest.php
new file mode 100644
index 00000000..1b34dfea
--- /dev/null
+++ b/tests/UnitTest/AppTest/Hydrator/AccountHydratorTest.php
@@ -0,0 +1,66 @@
+uuidFactory = new UuidFactory();
+ }
+
+ public function testCanHydrateAccount(): void
+ {
+ $hydrator = new AccountHydrator($this->uuidFactory);
+
+ $account = $hydrator->hydrate(Account::VALID_DATA);
+
+ $this->assertInstanceOf(AccountInterface::class, $account);
+ $this->assertSame(Account::ID, $account->id);
+ }
+
+ public function testCanHydrateAccountCollection(): void
+ {
+ $hydrator = new AccountHydrator($this->uuidFactory);
+
+ /** @var AccountInterface[] $accounts | [] */
+ $accounts = $hydrator->hydrateCollection([Account::VALID_DATA]);
+
+ $this->assertInstanceOf(AccountCollectionInterface::class, $accounts);
+ $this->assertInstanceOf(AccountInterface::class, $accounts[0]);
+ $this->assertSame(Account::ID, $accounts[0]->id);
+ }
+
+ public function testCanExtractAccount(): void
+ {
+ $hydrator = new AccountHydrator($this->uuidFactory);
+
+ $account = $hydrator->hydrate(Account::VALID_DATA);
+ $account = $hydrator->extract($account);
+
+ $this->assertIsArray($account);
+ $this->assertSame(Account::VALID_DATA, $account);
+ }
+
+ public function testCanExtractAccountCollection(): void
+ {
+ $hydrator = new AccountHydrator($this->uuidFactory);
+ $accounts = $hydrator->hydrateCollection([Account::VALID_DATA]);
+ $accounts = $hydrator->extractCollection($accounts);
+
+ $this->assertIsArray($accounts);
+ $this->assertArrayHasKey(0, $accounts);
+ $this->assertSame(Account::VALID_DATA, $accounts[0]);
+ }
+}
diff --git a/tests/Unit/Core/Middleware/AbstractMiddleware.php b/tests/UnitTest/AppTest/Middleware/AbstractTestMiddleware.php
similarity index 59%
rename from tests/Unit/Core/Middleware/AbstractMiddleware.php
rename to tests/UnitTest/AppTest/Middleware/AbstractTestMiddleware.php
index 91735e95..cdd34f8b 100644
--- a/tests/Unit/Core/Middleware/AbstractMiddleware.php
+++ b/tests/UnitTest/AppTest/Middleware/AbstractTestMiddleware.php
@@ -1,25 +1,27 @@
request = new MockServerRequest();
$this->handler = new MockRequestHandler();
- $this->hydrator = new ReflectionHydrator();
parent::setUp();
}
diff --git a/tests/UnitTest/AppTest/Middleware/AccountAccessAuthPersistMiddlewareTest.php b/tests/UnitTest/AppTest/Middleware/AccountAccessAuthPersistMiddlewareTest.php
new file mode 100644
index 00000000..d51531b2
--- /dev/null
+++ b/tests/UnitTest/AppTest/Middleware/AccountAccessAuthPersistMiddlewareTest.php
@@ -0,0 +1,108 @@
+repository = new MockAccountAccessAuthRepository();
+ $this->hydrator = new AccountHydrator(new UuidFactory());
+ }
+
+ public function testCanPersistAccountAccessAuth(): void
+ {
+ $middleware = new PersistAuthenticationMiddleware($this->repository);
+ $account = $this->hydrator->hydrate(Account::VALID_DATA);
+ $clientData = ClientIdentificationData::create('1', 'default');
+ $clientIdent = ClientIdentification::create($clientData, '1234');
+ $refreshToken = RefreshToken::fromString('1234');
+
+ $request = $this->request->withAttribute(AccountInterface::AUTHENTICATED, $account)
+ ->withAttribute(ClientIdentification::class, $clientIdent)
+ ->withAttribute(RefreshToken::class, $refreshToken);
+
+ $response = $middleware->process($request, $this->handler);
+
+ $this->assertNotInstanceOf(JsonResponse::class, $response);
+ }
+
+ public function testFindMissingAccountEntity(): void
+ {
+ $middleware = new PersistAuthenticationMiddleware($this->repository);
+
+ $clientData = ClientIdentificationData::create('1', 'default');
+ $clientIdent = ClientIdentification::create($clientData, '1234');
+ $refreshToken = RefreshToken::fromString('1234');
+
+ $request = $this->request->withAttribute(ClientIdentification::class, $clientIdent)
+ ->withAttribute(RefreshToken::class, $refreshToken);
+
+ $this->expectException(HttpUnauthorizedException::class);
+ $middleware->process($request, $this->handler);
+ }
+
+ public function testFindMissingClientIdentification(): void
+ {
+ $middleware = new PersistAuthenticationMiddleware($this->repository);
+
+ $account = $this->hydrator->hydrate(Account::VALID_DATA);
+ $refreshToken = RefreshToken::fromString('1234');
+
+ $request = $this->request->withAttribute(AccountInterface::AUTHENTICATED, $account)
+ ->withAttribute(RefreshToken::class, $refreshToken);
+
+ $this->expectException(HttpUnauthorizedException::class);
+ $middleware->process($request, $this->handler);
+ }
+
+ public function testFindMissingRefreshToken(): void
+ {
+ $middleware = new PersistAuthenticationMiddleware($this->repository);
+
+ $account = $this->hydrator->hydrate(Account::VALID_DATA);
+ $clientData = ClientIdentificationData::create('1', 'default');
+ $clientIdent = ClientIdentification::create($clientData, '1234');
+
+ $request = $this->request->withAttribute(AccountInterface::AUTHENTICATED, $account)
+ ->withAttribute(ClientIdentification::class, $clientIdent);
+
+ $this->expectException(HttpUnauthorizedException::class);
+ $middleware->process($request, $this->handler);
+ }
+
+ public function testAccountAccessAuthHasDuplicat(): void
+ {
+ $middleware = new PersistAuthenticationMiddleware($this->repository);
+ $account = $this->hydrator->hydrate(Account::INVALID_DATA);
+ $clientData = ClientIdentificationData::create('1', 'default');
+ $clientIdent = ClientIdentification::create($clientData, '1234');
+ $refreshToken = RefreshToken::fromString('1234');
+
+ $request = $this->request->withAttribute(AccountInterface::AUTHENTICATED, $account)
+ ->withAttribute(ClientIdentification::class, $clientIdent)
+ ->withAttribute(RefreshToken::class, $refreshToken);
+
+ $this->expectException(HttpDuplicateEntryException::class);
+ $middleware->process($request, $this->handler);
+ }
+}
diff --git a/tests/UnitTest/AppTest/Middleware/AccountAuthenticationMiddlewareTest.php b/tests/UnitTest/AppTest/Middleware/AccountAuthenticationMiddlewareTest.php
new file mode 100644
index 00000000..a47c317c
--- /dev/null
+++ b/tests/UnitTest/AppTest/Middleware/AccountAuthenticationMiddlewareTest.php
@@ -0,0 +1,107 @@
+accessTokenService = new MockAccessTokenService();
+ $this->accountRepository = new MockAccountRepository();
+ $this->logger = new NullLogger();
+ $this->uuidFactory = new UuidFactory();
+ }
+
+ public function testAccountAuthenticatedIsGuest(): void
+ {
+ $middleware = new RequestAuthenticationMiddleware(
+ $this->accessTokenService,
+ $this->accountRepository,
+ $this->uuidFactory,
+ $this->logger,
+ );
+ $handler = new MockAccountAuthenticationMiddlewareRequestHandler();
+ $response = $middleware->process($this->request, $handler);
+ $header = $response->getHeaderLine('Authorization');
+
+ $this->assertInstanceOf(ResponseInterface::class, $response);
+ $this->assertNotInstanceOf(JsonResponse::class, $response);
+ $this->assertSame('', $header);
+ }
+
+ public function testAccountSuccessfulAuthenticated(): void
+ {
+ $accessToken = $this->accessTokenService->generate($this->uuidFactory->fromString(Account::UUID));
+ $request = $this->request->withHeader('Authorization', $accessToken);
+
+ $middleware = new RequestAuthenticationMiddleware(
+ $this->accessTokenService,
+ $this->accountRepository,
+ $this->uuidFactory,
+ $this->logger,
+ );
+
+ $handler = new MockAccountAuthenticationMiddlewareRequestHandler();
+ $response = $middleware->process($request, $handler);
+ $header = $response->getHeaderLine('Authorization');
+
+ $this->assertNotInstanceOf(JsonResponse::class, $response);
+ $this->assertSame('true', $header);
+ }
+
+ public function testTokenHasExpired(): void
+ {
+ $accessTokenService = new MockAccessTokenServiceWithoutDuration();
+ $accessToken = $accessTokenService->generate($this->uuidFactory->fromString(Account::UUID));
+ $request = $this->request->withHeader('Authorization', $accessToken);
+
+ $middleware = new RequestAuthenticationMiddleware(
+ $this->accessTokenService,
+ $this->accountRepository,
+ $this->uuidFactory,
+ $this->logger,
+ );
+
+ $this->expectException(HttpUnauthorizedException::class);
+ $middleware->process($request, $this->handler);
+ }
+
+ public function testTokenHasInvalid(): void
+ {
+ $accessToken = $this->accessTokenService->generate($this->uuidFactory->fromString(Account::UUID));
+ $request = $this->request->withHeader('Authorization', $accessToken);
+ $accountRepository = new MockAccountRepositoryAccountAuthenticationMiddlewareInvalidToken();
+ $middleware = new RequestAuthenticationMiddleware(
+ $this->accessTokenService,
+ $accountRepository,
+ $this->uuidFactory,
+ $this->logger,
+ );
+
+ $this->expectException(HttpUnauthorizedException::class);
+ $middleware->process($request, $this->handler);
+ }
+}
diff --git a/tests/UnitTest/AppTest/Middleware/AuthenticationConditionsMiddlewareTest.php b/tests/UnitTest/AppTest/Middleware/AuthenticationConditionsMiddlewareTest.php
new file mode 100644
index 00000000..2ea196ca
--- /dev/null
+++ b/tests/UnitTest/AppTest/Middleware/AuthenticationConditionsMiddlewareTest.php
@@ -0,0 +1,42 @@
+middleware = new AuthenticationConditionsMiddleware();
+ }
+
+ public function testIsSuccessfully(): void
+ {
+ $response = $this->middleware->process($this->request, $this->handler);
+
+ $this->assertInstanceOf(ResponseInterface::class, $response);
+ }
+
+ public function testRequestIsAuthenticated(): void
+ {
+ $request = $this->request->withHeader('Authentication', []);
+
+ $this->expectException(HttpUnauthorizedException::class);
+ $this->middleware->process($request, $this->handler);
+ }
+
+ public function testRequestIsAuthorized(): void
+ {
+ $request = $this->request->withHeader('Authorization', []);
+
+ $this->expectException(HttpUnauthorizedException::class);
+ $this->middleware->process($request, $this->handler);
+ }
+}
diff --git a/tests/UnitTest/AppTest/Middleware/AuthenticationMiddlewareTest.php b/tests/UnitTest/AppTest/Middleware/AuthenticationMiddlewareTest.php
new file mode 100644
index 00000000..8c7e8a12
--- /dev/null
+++ b/tests/UnitTest/AppTest/Middleware/AuthenticationMiddlewareTest.php
@@ -0,0 +1,65 @@
+middleware = new AuthenticationMiddleware(
+ new MockAuthenticationService(),
+ new MockAccountRepository(),
+ );
+ }
+
+ public function testCanAuthenticatedAccount(): void
+ {
+ $bodyData = [
+ 'email' => Account::EMAIL,
+ 'password' => Account::PASSWORD,
+ ];
+
+ $request = $this->request->withParsedBody($bodyData);
+ $response = $this->middleware->process($request, $this->handler);
+
+ $this->assertNotInstanceOf(JsonResponse::class, $response);
+ }
+
+ public function testCanNotFoundAccountWithEmail(): void
+ {
+ $bodyData = [
+ 'email' => Account::EMAIL_INVALID,
+ 'password' => Account::PASSWORD,
+ ];
+
+ $request = $this->request->withParsedBody($bodyData);
+
+ $this->expectException(HttpUnauthorizedException::class);
+ $this->middleware->process($request, $this->handler);
+ }
+
+ public function testRequestWithInvalidPassword(): void
+ {
+ $bodyData = [
+ 'email' => Account::EMAIL,
+ 'password' => Account::PASSWORD_INVALID,
+ ];
+
+ $request = $this->request->withParsedBody($bodyData);
+
+ $this->expectException(HttpUnauthorizedException::class);
+ $this->middleware->process($request, $this->handler);
+ }
+}
diff --git a/tests/UnitTest/AppTest/Middleware/AuthenticationValidationMiddlewareTest.php b/tests/UnitTest/AppTest/Middleware/AuthenticationValidationMiddlewareTest.php
new file mode 100644
index 00000000..fc230a00
--- /dev/null
+++ b/tests/UnitTest/AppTest/Middleware/AuthenticationValidationMiddlewareTest.php
@@ -0,0 +1,33 @@
+process($this->request, $this->handler);
+
+ $this->assertNotInstanceOf(JsonResponse::class, $response);
+ }
+
+ public function testValidationFailed(): void
+ {
+ $middleware = new AuthenticationValidationMiddleware(
+ new MockAuthenticationValidatorFailed(),
+ );
+
+ $this->expectException(HttpUnauthorizedException::class);
+ $middleware->process($this->request, $this->handler);
+ }
+}
diff --git a/tests/UnitTest/AppTest/Middleware/ClientIdentificationMiddlewareTest.php b/tests/UnitTest/AppTest/Middleware/ClientIdentificationMiddlewareTest.php
new file mode 100644
index 00000000..5c35eb83
--- /dev/null
+++ b/tests/UnitTest/AppTest/Middleware/ClientIdentificationMiddlewareTest.php
@@ -0,0 +1,36 @@
+middleware = new ClientIdentificationMiddleware(
+ new MockClientIdentificationService(),
+ );
+ }
+
+ public function testGenerateClientIdentification(): void
+ {
+ $request = $this->request->withHeader('x-ident', '1')
+ ->withHeader('user-agent', 'Test Browser Agent');
+
+ $response = $this->middleware->process($request, $this->handler);
+
+ $this->assertInstanceOf(ResponseInterface::class, $response);
+ $this->assertNotInstanceOf(JsonResponse::class, $response);
+ }
+
+ // ToDo Create test for error cases
+}
diff --git a/tests/UnitTest/AppTest/Middleware/GenerateAccessTokenMiddlewareTest.php b/tests/UnitTest/AppTest/Middleware/GenerateAccessTokenMiddlewareTest.php
new file mode 100644
index 00000000..c9230203
--- /dev/null
+++ b/tests/UnitTest/AppTest/Middleware/GenerateAccessTokenMiddlewareTest.php
@@ -0,0 +1,34 @@
+middleware = new GenerateAccessTokenMiddleware(
+ new MockAccessTokenService()
+ );
+ }
+
+ public function testCanGenerateAccessToken(): void
+ {
+ $request = $this->request->withAttribute(AccountInterface::AUTHENTICATED, new MockAccount());
+ $response = $this->middleware->process($request, $this->handler);
+
+ $this->assertInstanceOf(ResponseInterface::class, $response);
+ $this->assertNotInstanceOf(JsonResponse::class, $response);
+ }
+}
diff --git a/tests/UnitTest/AppTest/Middleware/GenerateRefreshTokenMiddlewareTest.php b/tests/UnitTest/AppTest/Middleware/GenerateRefreshTokenMiddlewareTest.php
new file mode 100644
index 00000000..94609118
--- /dev/null
+++ b/tests/UnitTest/AppTest/Middleware/GenerateRefreshTokenMiddlewareTest.php
@@ -0,0 +1,39 @@
+middleware = new GenerateRefreshTokenMiddleware(
+ new MockRefreshTokenService()
+ );
+ }
+
+ public function testCanGenerateRefreshToken(): void
+ {
+ $data = ClientIdentification::create(
+ ClientIdentificationData::create(null, 'defaul'),
+ '1'
+ );
+
+ $request = $this->request->withAttribute(ClientIdentification::class, $data);
+ $response = $this->middleware->process($request, $this->handler);
+
+ $this->assertInstanceOf(ResponseInterface::class, $response);
+ $this->assertNotInstanceOf(JsonResponse::class, $response);
+ }
+}
diff --git a/tests/UnitTest/AppTest/Repository/AccountAccessAuthRepositoryTest.php b/tests/UnitTest/AppTest/Repository/AccountAccessAuthRepositoryTest.php
new file mode 100644
index 00000000..a2d503b3
--- /dev/null
+++ b/tests/UnitTest/AppTest/Repository/AccountAccessAuthRepositoryTest.php
@@ -0,0 +1,194 @@
+repository = new AccountAccessAuthRepository(new MockAccountAccessAuthTable());
+ $this->hydrator = new AccountAccessAuthHydrator();
+ }
+
+ public function testCanInsertAccountAccessAuth(): void
+ {
+ $result = $this->repository->insert($this->hydrator->hydrate(AccountAccessAuth::VALID_DATA));
+
+ $this->assertIsBool($result);
+ $this->assertTrue($result);
+ }
+
+ public function testInsertAccountAccessAuthThrowDuplicateEntryException(): void
+ {
+ $this->expectException(DuplicateEntryException::class);
+
+ $this->repository->insert($this->hydrator->hydrate(AccountAccessAuth::INVALID_DATA));
+ }
+
+ public function testCanUpdateAccountAccessAuth(): void
+ {
+ $result = $this->repository->update($this->hydrator->hydrate(AccountAccessAuth::VALID_DATA));
+
+ $this->assertIsBool($result);
+ $this->assertTrue($result);
+ }
+
+ public function testUpdateAccountAccessAuthThrowInvalidArgumentException(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $this->repository->update($this->hydrator->hydrate(AccountAccessAuth::INVALID_DATA));
+ }
+
+ public function testCanDeleteById(): void
+ {
+ $result = $this->repository->deleteById(AccountAccessAuth::ID);
+
+ $this->assertIsBool($result);
+ $this->assertTrue($result);
+ }
+
+ public function testDeleteByIdThrowInvalidArgumentException(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $this->repository->deleteById(AccountAccessAuth::ID_INVALID);
+ }
+
+ public function testCanFindById(): void
+ {
+ $result = $this->repository->findById(AccountAccessAuth::ID);
+
+ $this->assertInstanceOf(AccountAccessAuthInterface::class, $result);
+ $this->assertSame(AccountAccessAuth::VALID_DATA, $this->hydrator->extract($result));
+ }
+
+ public function testFindByIdIsEmpty(): void
+ {
+ $result = $this->repository->findById(AccountAccessAuth::ID_INVALID);
+
+ $this->assertNull($result);
+ }
+
+ public function testCanFindByUserId(): void
+ {
+ $result = $this->repository->findByAccountId(AccountAccessAuth::USER_ID);
+
+ $this->assertInstanceOf(AccountAccessAuthCollectionInterface::class, $result);
+ $this->assertArrayHasKey(0, $result);
+ $this->assertInstanceOf(AccountAccessAuthInterface::class, $result[0]);
+ $this->assertSame([0 => AccountAccessAuth::VALID_DATA], $this->hydrator->extractCollection($result));
+ }
+
+ public function testFindByUserIdIsEmpty(): void
+ {
+ $result = $this->repository->findByAccountId(AccountAccessAuth::USER_ID_INVALID);
+
+ $this->assertInstanceOf(AccountAccessAuthCollection::class, $result);
+ $this->assertEmpty($result);
+ }
+
+ public function testCanFindByLabel(): void
+ {
+ $result = $this->repository->findByLabel(AccountAccessAuth::LABEL);
+
+ $this->assertInstanceOf(AccountAccessAuthCollectionInterface::class, $result);
+ $this->assertArrayHasKey(0, $result);
+ $this->assertInstanceOf(AccountAccessAuthInterface::class, $result[0]);
+ $this->assertSame([0 => AccountAccessAuth::VALID_DATA], $this->hydrator->extractCollection($result));
+ }
+
+ public function testFindByLabelIsEmpty(): void
+ {
+ $result = $this->repository->findByLabel(AccountAccessAuth::LABEL_INVALID);
+
+ $this->assertInstanceOf(AccountAccessAuthCollection::class, $result);
+ $this->assertEmpty($result);
+ }
+
+ public function testCanFindByRefreshToken(): void
+ {
+ $result = $this->repository->findByRefreshToken(AccountAccessAuth::REFRESH_TOKEN);
+
+ $this->assertInstanceOf(AccountAccessAuthInterface::class, $result);
+ $this->assertSame(AccountAccessAuth::VALID_DATA, $this->hydrator->extract($result));
+ }
+
+ public function testFindByRefreshTokenIsEmpty(): void
+ {
+ $result = $this->repository->findByRefreshToken(AccountAccessAuth::REFRESH_TOKEN_INVALID);
+
+ $this->assertNull($result);
+ }
+
+ public function testCanFindByUserAgent(): void
+ {
+ $result = $this->repository->findByUserAgent(AccountAccessAuth::USER_AGENT);
+
+ $this->assertInstanceOf(AccountAccessAuthCollectionInterface::class, $result);
+ $this->assertArrayHasKey(0, $result);
+ $this->assertInstanceOf(AccountAccessAuthInterface::class, $result[0]);
+ $this->assertSame([0 => AccountAccessAuth::VALID_DATA], $this->hydrator->extractCollection($result));
+ }
+
+ public function testCanFindByUserAgentIsEmpty(): void
+ {
+ $result = $this->repository->findByUserAgent(AccountAccessAuth::USER_AGENT_INVALID);
+
+ $this->assertInstanceOf(AccountAccessAuthCollection::class, $result);
+ $this->assertEmpty($result);
+ }
+
+ public function testCanFindByClientIdentHash(): void
+ {
+ $result = $this->repository->findByClientIdentHash(AccountAccessAuth::CLIENT_IDENT_HASH);
+
+ $this->assertInstanceOf(AccountAccessAuthInterface::class, $result);
+ $this->assertSame(AccountAccessAuth::VALID_DATA, $this->hydrator->extract($result));
+ }
+
+ public function testFindByClientIdentHashIsEmpty(): void
+ {
+ $result = $this->repository->findByClientIdentHash(AccountAccessAuth::CLIENT_IDENT_HASH_INVALID);
+
+ $this->assertNull($result);
+ }
+
+ public function testCanFindAll(): void
+ {
+ $result = $this->repository->findAll();
+
+ $this->assertInstanceOf(AccountAccessAuthCollectionInterface::class, $result);
+ $this->assertArrayHasKey(0, $result);
+ $this->assertInstanceOf(AccountAccessAuthInterface::class, $result[0]);
+ $this->assertSame([0 => AccountAccessAuth::VALID_DATA], $this->hydrator->extractCollection($result));
+ }
+
+ public function testFindAllIsEmpty(): void
+ {
+ $repository = new AccountAccessAuthRepository(new MockAccountAccessAuthTableFailed());
+
+ $result = $repository->findAll();
+
+ $this->assertInstanceOf(AccountAccessAuthCollection::class, $result);
+ $this->assertEmpty($result);
+ }
+}
diff --git a/tests/UnitTest/AppTest/Repository/AccountRepositoryTest.php b/tests/UnitTest/AppTest/Repository/AccountRepositoryTest.php
new file mode 100644
index 00000000..a1047935
--- /dev/null
+++ b/tests/UnitTest/AppTest/Repository/AccountRepositoryTest.php
@@ -0,0 +1,161 @@
+uuidFactory = new UuidFactory();
+ $this->repository = new AccountRepository(new MockAccountTable());
+ $this->hydrator = new AccountHydrator($this->uuidFactory);
+ }
+
+ public function testCanInsertAccount(): void
+ {
+ $result = $this->repository->insert($this->hydrator->hydrate(Account::VALID_DATA));
+
+ $this->assertIsBool($result);
+ $this->assertTrue($result);
+ }
+
+ public function testInsertAccountThrowsException(): void
+ {
+ $this->expectException(DuplicateEntryException::class);
+
+ $this->repository->insert($this->hydrator->hydrate(Account::INVALID_DATA));
+ }
+
+ public function testCanUpdateAccount(): void
+ {
+ $result = $this->repository->update($this->hydrator->hydrate(Account::VALID_DATA));
+
+ $this->assertIsBool($result);
+ $this->assertTrue($result);
+ }
+
+ public function testUpdateAccountThrowsException(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $this->repository->update($this->hydrator->hydrate(Account::INVALID_DATA));
+ }
+
+ public function testCanDeleteAccountById(): void
+ {
+ $result = $this->repository->deleteById(Account::ID);
+
+ $this->assertIsBool($result);
+ $this->assertTrue($result);
+ }
+
+ public function testDeleteAccountByIdThrowsInvalidArgumentException(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $this->repository->deleteById(Account::ID_INVALID);
+ }
+
+ public function testCanFindById(): void
+ {
+ $result = $this->repository->findById(Account::ID);
+
+ $this->assertInstanceOf(AccountInterface::class, $result);
+ $this->assertSame(Account::VALID_DATA, $this->hydrator->extract($result));
+ }
+
+ public function testFindByIdIsEmpty(): void
+ {
+ $result = $this->repository->findById(Account::ID_INVALID);
+
+ $this->assertNull($result);
+ }
+
+ public function testCanFindByUuid(): void
+ {
+ $uuid = $this->uuidFactory->fromString(Account::UUID);
+ $result = $this->repository->findByUuid($uuid);
+
+ $this->assertInstanceOf(AccountInterface::class, $result);
+ $this->assertSame(Account::VALID_DATA, $this->hydrator->extract($result));
+ }
+
+ public function testFindByUuidIsEmtpy(): void
+ {
+ $uuid = $this->uuidFactory->fromString(Account::UUID_INVALID);
+
+ $result = $this->repository->findByUuid($uuid);
+
+ $this->assertNull($result);
+ }
+
+ public function testCanFindByName(): void
+ {
+ $result = $this->repository->findByName(Account::NAME);
+
+ $this->assertInstanceOf(AccountInterface::class, $result);
+ $this->assertSame(Account::VALID_DATA, $this->hydrator->extract($result));
+ }
+
+ public function testFindByNameIsEmpty(): void
+ {
+ $result = $this->repository->findByName(Account::NAME_INVALID);
+
+ $this->assertNull($result);
+ }
+
+ public function testCanFindByEmail(): void
+ {
+ $result = $this->repository->findByEmail(new Email(Account::EMAIL));
+
+ $this->assertInstanceOf(AccountInterface::class, $result);
+ $this->assertSame(Account::VALID_DATA, $this->hydrator->extract($result));
+ }
+
+ public function testFindByEmailIsEmpty(): void
+ {
+ $result = $this->repository->findByEmail(new Email(Account::EMAIL_INVALID));
+
+ $this->assertNull($result);
+ }
+
+ public function testCanFindAll(): void
+ {
+ $result = $this->repository->findAll();
+
+ $this->assertInstanceOf(AccountCollectionInterface::class, $result);
+ $this->assertArrayHasKey(0, $result);
+ $this->assertInstanceOf(AccountInterface::class, $result[0]);
+ $this->assertSame([0 => Account::VALID_DATA], $this->hydrator->extractCollection($result));
+ }
+
+ public function testFindAllIsEmpty(): void
+ {
+ $repository = new AccountRepository(new MockAccountTableFailed());
+
+ $result = $repository->findAll();
+
+ $this->assertInstanceOf(AccountCollectionInterface::class, $result);
+ $this->assertEmpty($result);
+ }
+}
diff --git a/tests/UnitTest/AppTest/Service/AccessTokenServiceTest.php b/tests/UnitTest/AppTest/Service/AccessTokenServiceTest.php
new file mode 100644
index 00000000..4a8d0ca0
--- /dev/null
+++ b/tests/UnitTest/AppTest/Service/AccessTokenServiceTest.php
@@ -0,0 +1,48 @@
+account = new MockAccount();
+ }
+
+ public function testGenerateValidAccessToken(): void
+ {
+ $config = Token::getTokenStruct();
+ $jwtTokenConfig = JwtTokenConfig::createFromArray($config);
+
+ $service = new AccessTokenService($jwtTokenConfig);
+
+ $token = $service->generate($this->account->uuid);
+
+ $isValid = $service->isValid($token);
+
+ $this->assertTrue($isValid);
+ }
+
+ public function testGenerateValidAccessTokenFails(): void
+ {
+ $config = Token::getTokenStruct();
+ $config['algorithmus'] = '';
+ $jwtTokenConfig = JwtTokenConfig::createFromArray($config);
+
+ $service = new AccessTokenService($jwtTokenConfig);
+
+ $this->expectException(DomainException::class);
+
+ $service->generate($this->account->uuid);
+ }
+}
diff --git a/tests/UnitTest/AppTest/Service/AuthenticationServiceTest.php b/tests/UnitTest/AppTest/Service/AuthenticationServiceTest.php
new file mode 100644
index 00000000..ebc0eb06
--- /dev/null
+++ b/tests/UnitTest/AppTest/Service/AuthenticationServiceTest.php
@@ -0,0 +1,31 @@
+service = new AuthenticationService();
+ }
+
+ public function testPasswordComparisonIsSuccessful(): void
+ {
+ $compare = $this->service->isPasswordMatch(Account::PASSWORD_STRING, Account::PASSWORD);
+
+ $this->assertTrue($compare);
+ }
+
+ public function testPasswordComparisonFails(): void
+ {
+ $compare = $this->service->isPasswordMatch(Account::PASSWORD_STRING, Account::PASSWORD_INVALID);
+
+ $this->assertFalse($compare);
+ }
+}
diff --git a/tests/UnitTest/AppTest/Service/RefreshTokenServiceTest.php b/tests/UnitTest/AppTest/Service/RefreshTokenServiceTest.php
new file mode 100644
index 00000000..568af821
--- /dev/null
+++ b/tests/UnitTest/AppTest/Service/RefreshTokenServiceTest.php
@@ -0,0 +1,51 @@
+client = ClientIdentification::create(
+ ClientIdentificationData::create(null, 'default'),
+ '1'
+ );
+ }
+
+ public function testGenerateValidRefreshToken(): void
+ {
+ $config = Token::getTokenStruct();
+ $jwtTokenConfig = JwtTokenConfig::createFromArray($config);
+
+ $service = new RefreshTokenService($jwtTokenConfig);
+
+ $token = $service->generate($this->client);
+
+ $isValid = $service->isValid($token);
+
+ $this->assertTrue($isValid);
+ }
+
+ public function testGenerateValidRefreshTokenFails(): void
+ {
+ $config = Token::getTokenStruct();
+ $config['algorithmus'] = '';
+ $jwtTokenConfig = JwtTokenConfig::createFromArray($config);
+
+ $service = new RefreshTokenService($jwtTokenConfig);
+
+ $this->expectException(DomainException::class);
+
+ $service->generate($this->client);
+ }
+}
diff --git a/tests/UnitTest/AppTest/Table/AccountAccessAuthTableTest.php b/tests/UnitTest/AppTest/Table/AccountAccessAuthTableTest.php
new file mode 100644
index 00000000..c8ad6c3a
--- /dev/null
+++ b/tests/UnitTest/AppTest/Table/AccountAccessAuthTableTest.php
@@ -0,0 +1,226 @@
+query = new MockQuery();
+ $this->hydrator = new AccountAccessAuthHydrator();
+ $this->table = new AccountAccessAuthTable($this->query, $this->hydrator);
+ }
+
+ public function testCanGetTableName(): void
+ {
+ $this->assertSame('AccountAccessAuth', $this->table->getTableName());
+ }
+
+ public function testCanInsertAccountAccessAuth(): void
+ {
+ $accountAccessAuth = $this->hydrator->hydrate(AccountAccessAuth::VALID_DATA);
+
+ $result = $this->table->insert($accountAccessAuth);
+
+ $this->assertIsBool($result);
+ $this->assertTrue($result);
+ }
+
+ public function testInsertAccountAccessAuthThrowsException(): void
+ {
+ $accountAccessAuth = $this->hydrator->hydrate(AccountAccessAuth::VALID_DATA);
+ $table = new AccountAccessAuthTable(new MockQueryFailed(), $this->hydrator);
+
+ $this->expectException(DuplicateEntryException::class);
+
+ $table->insert($accountAccessAuth);
+ }
+
+ public function testCanUpdateAccountAccessAuth(): void
+ {
+ $accountAccessAuth = $this->hydrator->hydrate(AccountAccessAuth::VALID_DATA);
+
+ $result = $this->table->update($accountAccessAuth);
+
+ $this->assertIsBool($result);
+ $this->assertTrue($result);
+ }
+
+ public function testUpdateAccountAccessAuthThrowsException(): void
+ {
+ $accountAccessAuth = $this->hydrator->hydrate(AccountAccessAuth::VALID_DATA);
+ $table = new AccountAccessAuthTable(new MockQueryFailed(), $this->hydrator);
+
+ $this->expectException(InvalidArgumentException::class);
+
+ $table->update($accountAccessAuth);
+ }
+
+ public function testCanDeleteById(): void
+ {
+ $result = $this->table->deleteById(AccountAccessAuth::ID);
+
+ $this->assertIsBool($result);
+ $this->assertTrue($result);
+ }
+
+ public function testDeleteAccountThrowsException(): void
+ {
+ $table = new AccountAccessAuthTable(new MockQueryFailed(), $this->hydrator);
+
+ $this->expectException(InvalidArgumentException::class);
+
+ $table->deleteById(AccountAccessAuth::ID);
+ }
+
+ public function testCanFindById(): void
+ {
+ $result = $this->table->findById(AccountAccessAuth::ID);
+
+ $this->assertInstanceOf(AccountAccessAuthInterface::class, $result);
+ $this->assertSame(AccountAccessAuth::ID, $result->id);
+ }
+
+ public function testFindByIdIsEmpty(): void
+ {
+ $table = new AccountAccessAuthTable(new MockQueryFailed(), $this->hydrator);
+
+ $result = $table->findById(AccountAccessAuth::ID);
+
+ $this->assertNull($result);
+ }
+
+ public function testCanFindByUserId(): void
+ {
+ /** @var AccountAccessAuthCollectionInterface $result */
+ $result = $this->table->findByAccountId(AccountAccessAuth::USER_ID);
+
+ $this->assertInstanceOf(AccountAccessAuthCollectionInterface::class, $result);
+ $this->assertArrayHasKey(0, $result);
+ $this->assertSame(AccountAccessAuth::USER_ID, $result[0]->accountId);
+ }
+
+ public function testFindByUserIdIsEmpty(): void
+ {
+ $table = new AccountAccessAuthTable(new MockQueryFailed(), $this->hydrator);
+
+ $result = $table->findByAccountId(AccountAccessAuth::USER_ID);
+
+ $this->assertInstanceOf(AccountAccessAuthCollection::class, $result);
+ $this->assertEmpty($result);
+ }
+
+ public function testCanFindByLabel(): void
+ {
+ /** @var AccountAccessAuthCollectionInterface $result */
+ $result = $this->table->findByLabel(AccountAccessAuth::LABEL);
+
+ $this->assertInstanceOf(AccountAccessAuthCollectionInterface::class, $result);
+ $this->assertArrayHasKey(0, $result);
+ $this->assertSame(AccountAccessAuth::LABEL, $result[0]->label);
+ }
+
+ public function testFindByLabelIsEmpty(): void
+ {
+ $table = new AccountAccessAuthTable(new MockQueryFailed(), $this->hydrator);
+
+ $result = $table->findByLabel(AccountAccessAuth::LABEL);
+
+ $this->assertInstanceOf(AccountAccessAuthCollectionInterface::class, $result);
+ $this->assertEmpty($result);
+ }
+
+ public function testCanFindByRefreshToken(): void
+ {
+ /** @var AccountAccessAuthInterface $result */
+ $result = $this->table->findByRefreshToken(AccountAccessAuth::REFRESH_TOKEN);
+
+ $this->assertInstanceOf(AccountAccessAuthInterface::class, $result);
+ $this->assertSame(AccountAccessAuth::REFRESH_TOKEN, $result->refreshToken);
+ }
+
+ public function testFindByRefreshTokenIsEmpty(): void
+ {
+ $table = new AccountAccessAuthTable(new MockQueryFailed(), $this->hydrator);
+
+ $result = $table->findByRefreshToken(AccountAccessAuth::REFRESH_TOKEN);
+
+ $this->assertNull($result);
+ }
+
+ public function testCanFindByUserAgent(): void
+ {
+ /** @var AccountAccessAuthCollectionInterface $result */
+ $result = $this->table->findByUserAgent(AccountAccessAuth::USER_AGENT);
+
+ $this->assertInstanceOf(AccountAccessAuthCollectionInterface::class, $result);
+ $this->assertArrayHasKey(0, $result);
+ $this->assertSame(AccountAccessAuth::USER_AGENT, $result[0]->userAgent);
+ }
+
+ public function testFindByUserAgentIsEmpty(): void
+ {
+ $table = new AccountAccessAuthTable(new MockQueryFailed(), $this->hydrator);
+
+ $result = $table->findByUserAgent(AccountAccessAuth::USER_AGENT);
+
+ $this->assertInstanceOf(AccountAccessAuthCollectionInterface::class, $result);
+ $this->assertEmpty($result);
+ }
+
+ public function testCanFindByClientIdentHash(): void
+ {
+ /** @var AccountAccessAuthInterface $result */
+ $result = $this->table->findByClientIdentHash(AccountAccessAuth::CLIENT_IDENT_HASH);
+
+ $this->assertInstanceOf(AccountAccessAuthInterface::class, $result);
+ $this->assertSame(AccountAccessAuth::CLIENT_IDENT_HASH, $result->clientIdentHash);
+ }
+
+ public function testFindByClientIdentHashIsEmpty(): void
+ {
+ $table = new AccountAccessAuthTable(new MockQueryFailed(), $this->hydrator);
+
+ $result = $table->findByClientIdentHash(AccountAccessAuth::CLIENT_IDENT_HASH);
+
+ $this->assertNull($result);
+ }
+
+ public function testCanFindAll(): void
+ {
+ /** @var AccountAccessAuthCollectionInterface $result */
+ $result = $this->table->findAll();
+
+ $this->assertInstanceOf(AccountAccessAuthCollectionInterface::class, $result);
+ $this->assertArrayHasKey(0, $result);
+ $this->assertSame(AccountAccessAuth::ID, $result[0]->id);
+ }
+
+ public function testFindAllIsEmpty(): void
+ {
+ $table = new AccountAccessAuthTable(new MockQueryFailed(), $this->hydrator);
+
+ $result = $table->findAll();
+
+ $this->assertInstanceOf(AccountAccessAuthCollectionInterface::class, $result);
+ $this->assertEmpty($result);
+ }
+}
diff --git a/tests/UnitTest/AppTest/Table/AccountTableTest.php b/tests/UnitTest/AppTest/Table/AccountTableTest.php
new file mode 100644
index 00000000..30d74c66
--- /dev/null
+++ b/tests/UnitTest/AppTest/Table/AccountTableTest.php
@@ -0,0 +1,189 @@
+uuidFactory = new UuidFactory();
+ $this->hydrator = new AccountHydrator($this->uuidFactory);
+ $this->table = new AccountTable($query, $this->hydrator);
+ }
+
+ public function testCanGetTableName(): void
+ {
+ $this->assertSame('Account', $this->table->getTableName());
+ }
+
+ public function testCanInsertAccount(): void
+ {
+ $account = $this->hydrator->hydrate(Account::VALID_DATA);
+
+ $result = $this->table->insert($account);
+
+ $this->assertIsBool($result);
+ $this->assertTrue($result);
+ }
+
+ public function testInsertAccountThrowsException(): void
+ {
+ $table = new AccountTable(new MockQueryFailed(), $this->hydrator);
+
+ $account = $this->hydrator->hydrate(Account::VALID_DATA);
+
+ $this->expectException(DuplicateEntryException::class);
+
+ $table->insert($account);
+ }
+
+ public function testCanUpdateAccount(): void
+ {
+ $account = $this->hydrator->hydrate(Account::VALID_DATA);
+
+ $result = $this->table->update($account);
+
+ $this->assertIsBool($result);
+ $this->assertTrue($result);
+ }
+
+ public function testUpdateAccountThrowsException(): void
+ {
+ $table = new AccountTable(new MockQueryFailed(), $this->hydrator);
+ $account = $this->hydrator->hydrate(Account::VALID_DATA);
+
+ $this->expectException(InvalidArgumentException::class);
+
+ $table->update($account);
+ }
+
+ public function testCanDeleteById(): void
+ {
+ $result = $this->table->deleteById(Account::ID);
+
+ $this->assertIsBool($result);
+ $this->assertTrue($result);
+ }
+
+ public function testDeleteAccountThrowsException(): void
+ {
+ $table = new AccountTable(new MockQueryFailed(), $this->hydrator);
+
+ $this->expectException(InvalidArgumentException::class);
+
+ $table->deleteById(Account::ID);
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function testCanFindById(): void
+ {
+ $account = $this->table->findById(Account::ID);
+
+ $this->assertInstanceOf(AccountInterface::class, $account);
+ $this->assertSame(Account::VALID_DATA, $this->hydrator->extract($account));
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function testFindByIdIsEmpty(): void
+ {
+ $result = $this->table->findById(Account::ID_INVALID);
+
+ $this->assertNull($result);
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function testCanFindByUuid(): void
+ {
+ $uuid = $this->uuidFactory->fromString(Account::UUID);
+ $account = $this->table->findByUuid($uuid);
+
+ $this->assertInstanceOf(AccountInterface::class, $account);
+ $this->assertSame(Account::VALID_DATA, $this->hydrator->extract($account));
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function testFindByUuidIsEmpty(): void
+ {
+ $uuid = $this->uuidFactory->fromString(Account::UUID_INVALID);
+ $result = $this->table->findByUuid($uuid);
+
+ $this->assertNull($result);
+ }
+
+ public function testCanFindByName(): void
+ {
+ $account = $this->table->findByName(Account::NAME);
+
+ $this->assertInstanceOf(AccountInterface::class, $account);
+ $this->assertSame(Account::VALID_DATA, $this->hydrator->extract($account));
+ }
+
+ public function testFindByNameIsEmpty(): void
+ {
+ $result = $this->table->findByName(Account::NAME_INVALID);
+
+ $this->assertNull($result);
+ }
+
+ public function testCanFindByEmail(): void
+ {
+ $account = $this->table->findByEmail(new Email(Account::EMAIL));
+
+ $this->assertInstanceOf(AccountInterface::class, $account);
+ $this->assertSame(Account::VALID_DATA, $this->hydrator->extract($account));
+ }
+
+ public function testFindByEmailIsEmpty(): void
+ {
+ $result = $this->table->findByEmail(new Email(Account::EMAIL_INVALID));
+
+ $this->assertNull($result);
+ }
+
+ public function testCanFindAllAccount(): void
+ {
+ $accounts = $this->table->findAll();
+
+ $this->assertInstanceOf(AccountCollectionInterface::class, $accounts);
+ $this->assertSame([0 => Account::VALID_DATA], $this->hydrator->extractCollection($accounts));
+ }
+
+ public function testFindAllAccountIsEmpty(): void
+ {
+ $table = new AccountTable(new MockQueryFailed(), $this->hydrator);
+
+ $result = $table->findAll();
+
+ $this->assertInstanceOf(AccountCollectionInterface::class, $result);
+ $this->assertEmpty($result);
+ }
+}
diff --git a/tests/Unit/Core/Factory/DatabaseFactoryTest.php b/tests/UnitTest/CoreTest/Factory/DatabaseFactoryTest.php
similarity index 50%
rename from tests/Unit/Core/Factory/DatabaseFactoryTest.php
rename to tests/UnitTest/CoreTest/Factory/DatabaseFactoryTest.php
index 54c9a3f5..b0097fc4 100644
--- a/tests/Unit/Core/Factory/DatabaseFactoryTest.php
+++ b/tests/UnitTest/CoreTest/Factory/DatabaseFactoryTest.php
@@ -1,18 +1,22 @@
expectException(PDOException::class);
@@ -25,31 +29,15 @@ public function testThrowPdoException(): void
'port' => 3306,
'dbname' => 'example_db',
'error' => PDO::ERRMODE_EXCEPTION,
-
+ 'emulate_prepares' => false,
],
];
$container = new MockContainer();
$container->add('config', $config);
- (new DatabaseFactory())($container);
- }
-
- public function testCanInitiatePdoConnection(): void
- {
- system('touch ' . dirname(__FILE__) . '/../../../../database/database.sqlite');
- $config = require dirname(__FILE__) . '/../../../config/autoload/database.testing.local.php';
-
- $container = new MockContainer();
- $container->add('config', $config);
-
$pdo = (new DatabaseFactory())($container);
- self::assertInstanceOf(PDO::class, $pdo);
- }
-
- public function tearDown(): void
- {
- system('rm ' . dirname(__FILE__) . '/../../../../database/database.sqlite');
+ $this->assertInstanceOf(PDO::class, $pdo);
}
}
diff --git a/tests/Unit/Core/Factory/QueryFactoryTest.php b/tests/UnitTest/CoreTest/Factory/QueryFactoryTest.php
similarity index 52%
rename from tests/Unit/Core/Factory/QueryFactoryTest.php
rename to tests/UnitTest/CoreTest/Factory/QueryFactoryTest.php
index 6e6971d0..d42a487b 100644
--- a/tests/Unit/Core/Factory/QueryFactoryTest.php
+++ b/tests/UnitTest/CoreTest/Factory/QueryFactoryTest.php
@@ -1,16 +1,22 @@
assertInstanceOf(Query::class, $query);
}
}
diff --git a/tests/UnitTest/GameTest/.gitkeep b/tests/UnitTest/GameTest/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Functional/JsonRequestHelper.php b/tests/UnitTest/JsonRequestHelper.php
similarity index 91%
rename from tests/Functional/JsonRequestHelper.php
rename to tests/UnitTest/JsonRequestHelper.php
index 0661e7c9..265a9fc0 100644
--- a/tests/Functional/JsonRequestHelper.php
+++ b/tests/UnitTest/JsonRequestHelper.php
@@ -1,6 +1,6 @@
self::ID,
+ 'uuid' => self::UUID,
+ 'name' => self::NAME,
+ 'password' => self::PASSWORD,
+ 'email' => self::EMAIL,
+ 'registeredAt' => self::REGISTERED,
+ 'lastActionAt' => self::LAST_ACTION,
+ ];
+
+ public const array INVALID_DATA
+ = [
+ 'id' => self::ID_INVALID,
+ 'uuid' => self::UUID_INVALID,
+ 'name' => self::NAME_INVALID,
+ 'password' => self::PASSWORD_INVALID,
+ 'email' => self::EMAIL_INVALID,
+ 'registeredAt' => self::REGISTERED,
+ 'lastActionAt' => self::LAST_ACTION,
+ ];
+}
diff --git a/tests/UnitTest/Mock/Constants/AccountAccessAuth.php b/tests/UnitTest/Mock/Constants/AccountAccessAuth.php
new file mode 100644
index 00000000..5bfa113b
--- /dev/null
+++ b/tests/UnitTest/Mock/Constants/AccountAccessAuth.php
@@ -0,0 +1,54 @@
+ self::ID,
+ 'accountId' => self::USER_ID,
+ 'label' => self::LABEL,
+ 'refreshToken' => self::REFRESH_TOKEN,
+ 'userAgent' => self::USER_AGENT,
+ 'clientIdentHash' => self::CLIENT_IDENT_HASH,
+ 'createdAt' => self::CREATED_AT,
+ ];
+
+ public const array INVALID_DATA
+ = [
+ 'id' => self::ID_INVALID,
+ 'accountId' => self::USER_ID_INVALID,
+ 'label' => self::LABEL_INVALID,
+ 'refreshToken' => self::REFRESH_TOKEN_INVALID,
+ 'userAgent' => self::USER_AGENT_INVALID,
+ 'clientIdentHash' => self::CLIENT_IDENT_HASH_INVALID,
+ 'createdAt' => self::CREATED_AT,
+ ];
+}
diff --git a/tests/UnitTest/Mock/Constants/Token.php b/tests/UnitTest/Mock/Constants/Token.php
new file mode 100644
index 00000000..3924a447
--- /dev/null
+++ b/tests/UnitTest/Mock/Constants/Token.php
@@ -0,0 +1,21 @@
+ 'token secret',
+ 'algorithmus' => 'HS512',
+ 'duration' => 60 * 60 * 24 * 7 * 12,
+ 'iss' => 'Issuer of the token',
+ 'aud' => 'recipients of the token',
+ ];
+ }
+}
diff --git a/tests/Unit/Mock/Database/MockDelete.php b/tests/UnitTest/Mock/Database/MockDelete.php
similarity index 62%
rename from tests/Unit/Mock/Database/MockDelete.php
rename to tests/UnitTest/Mock/Database/MockDelete.php
index b903e5cb..e8c9188e 100644
--- a/tests/Unit/Mock/Database/MockDelete.php
+++ b/tests/UnitTest/Mock/Database/MockDelete.php
@@ -1,10 +1,9 @@
$this->handleEvent($where, $value),
+ 'Account', 'AccountAccessAuth' => true,
default => false,
};
}
-
- private function handleEvent(array $where, array $value): bool
- {
- if ($where[0][1] === 'id = ?' && $value[0] === TestConstants::EVENT_ID) {
- return true;
- }
-
- return false;
- }
}
diff --git a/tests/UnitTest/Mock/Database/MockDeleteFailed.php b/tests/UnitTest/Mock/Database/MockDeleteFailed.php
new file mode 100644
index 00000000..e72df7a3
--- /dev/null
+++ b/tests/UnitTest/Mock/Database/MockDeleteFailed.php
@@ -0,0 +1,24 @@
+handle($this->statements['DELETE FROM'], $this->statements['WHERE'], $this->parameters['WHERE']);
+ }
+
+ private function handle(string $table, array $where, array $value): bool
+ {
+ return false;
+ }
+}
diff --git a/tests/UnitTest/Mock/Database/MockInsert.php b/tests/UnitTest/Mock/Database/MockInsert.php
new file mode 100644
index 00000000..c3e9b2ae
--- /dev/null
+++ b/tests/UnitTest/Mock/Database/MockInsert.php
@@ -0,0 +1,27 @@
+handle($this->statements['INSERT INTO'], $this->statements['VALUES']);
+ }
+
+ private function handle(string $table, array $values): bool
+ {
+ return match($table) {
+ 'Account', 'AccountAccessAuth' => true,
+ default => false,
+ };
+ }
+}
diff --git a/tests/UnitTest/Mock/Database/MockInsertFailed.php b/tests/UnitTest/Mock/Database/MockInsertFailed.php
new file mode 100644
index 00000000..f64f2fea
--- /dev/null
+++ b/tests/UnitTest/Mock/Database/MockInsertFailed.php
@@ -0,0 +1,25 @@
+handle($this->statements['INSERT INTO'], $this->statements['VALUES']);
+ }
+
+ private function handle(string $table, array $values): bool
+ {
+ throw new PDOException();
+ }
+}
diff --git a/tests/Unit/Mock/Database/MockPDO.php b/tests/UnitTest/Mock/Database/MockPDO.php
similarity index 88%
rename from tests/Unit/Mock/Database/MockPDO.php
rename to tests/UnitTest/Mock/Database/MockPDO.php
index 80a828fc..51c8ad13 100644
--- a/tests/Unit/Mock/Database/MockPDO.php
+++ b/tests/UnitTest/Mock/Database/MockPDO.php
@@ -1,6 +1,6 @@
statements)) {
+ return $this->handle($this->statements['FROM'], $this->statements['WHERE'], $this->parameters['WHERE']);
+ }
+
+ return [];
+ }
+
+ public function fetchAll($index = '', $selectOnly = ''): false|array
+ {
+ return match ($this->getFromTable()) {
+ 'Account' => [0 => Account::VALID_DATA],
+ 'AccountAccessAuth' => [0 => AccountAccessAuth::VALID_DATA],
+ default => false
+ };
+ }
+
+ private function handle(string $from, array $where, array $params): false|array
+ {
+ return match ($from) {
+ 'Account' => $this->handleAccount($where, $params),
+ 'AccountAccessAuth' => $this->handleAccountAccessAuth($where, $params),
+ default => false
+ };
+ }
+
+ private function handleAccount(array $where, array $params): false|array
+ {
+ if ($where[0][1] === 'id = ?' && $params[0] === Account::ID) {
+ return Account::VALID_DATA;
+ }
+
+ if ($where[0][1] === 'uuid = ?' && $params[0] === Account::UUID) {
+ return Account::VALID_DATA;
+ }
+
+ if ($where[0][1] === 'name = ?' && $params[0] === Account::NAME) {
+ return Account::VALID_DATA;
+ }
+
+ if ($where[0][1] === 'email = ?' && $params[0] === Account::EMAIL) {
+ return Account::VALID_DATA;
+ }
+
+ return false;
+ }
+
+ private function handleAccountAccessAuth(array $where, array $params): false|array
+ {
+ if ($where[0][1] === 'id = ?' && $params[0] === AccountAccessAuth::ID) {
+ return AccountAccessAuth::VALID_DATA;
+ }
+
+ if ($where[0][1] === 'userId = ?' && $params[0] === AccountAccessAuth::USER_ID) {
+ return [0 => AccountAccessAuth::VALID_DATA];
+ }
+
+ if ($where[0][1] === 'label = ?' && $params[0] === AccountAccessAuth::LABEL) {
+ return [0 => AccountAccessAuth::VALID_DATA];
+ }
+
+ if ($where[0][1] === 'refreshToken = ?' && $params[0] === AccountAccessAuth::REFRESH_TOKEN) {
+ return AccountAccessAuth::VALID_DATA;
+ }
+
+ if ($where[0][1] === 'userAgent = ?' && $params[0] === AccountAccessAuth::USER_AGENT) {
+ return [0 => AccountAccessAuth::VALID_DATA];
+ }
+
+ if ($where[0][1] === 'clientIdentHash = ?' && $params[0] === AccountAccessAuth::CLIENT_IDENT_HASH) {
+ return AccountAccessAuth::VALID_DATA;
+ }
+
+ return false;
+ }
+}
diff --git a/tests/UnitTest/Mock/Database/MockSelectFailed.php b/tests/UnitTest/Mock/Database/MockSelectFailed.php
new file mode 100644
index 00000000..860c6e17
--- /dev/null
+++ b/tests/UnitTest/Mock/Database/MockSelectFailed.php
@@ -0,0 +1,36 @@
+statements)) {
+ return $this->handle($this->statements['FROM'], $this->statements['WHERE'], $this->parameters['WHERE']);
+ }
+
+ return [];
+ }
+
+ public function fetchAll($index = '', $selectOnly = ''): false|array
+ {
+ return false;
+ }
+
+ private function handle(string $from, array $where, array $params): false|array
+ {
+ return false;
+ }
+}
diff --git a/tests/UnitTest/Mock/Database/MockUpdate.php b/tests/UnitTest/Mock/Database/MockUpdate.php
new file mode 100644
index 00000000..0f13c7ef
--- /dev/null
+++ b/tests/UnitTest/Mock/Database/MockUpdate.php
@@ -0,0 +1,22 @@
+statements['UPDATE']) {
+ 'Account', 'AccountAccessAuth' => true,
+ default => false
+ };
+ }
+}
diff --git a/tests/UnitTest/Mock/Database/MockUpdateFailed.php b/tests/UnitTest/Mock/Database/MockUpdateFailed.php
new file mode 100644
index 00000000..b755be43
--- /dev/null
+++ b/tests/UnitTest/Mock/Database/MockUpdateFailed.php
@@ -0,0 +1,19 @@
+getAttribute(AccountInterface::AUTHENTICATED);
+ $response = new MockResponse();
+
+ if ($account instanceof AccountInterface) {
+ return $response->withHeader('Authorization', 'true');
+ }
+
+ return $response;
+ }
+}
diff --git a/tests/Unit/Mock/MockContainer.php b/tests/UnitTest/Mock/MockContainer.php
similarity index 95%
rename from tests/Unit/Mock/MockContainer.php
rename to tests/UnitTest/Mock/MockContainer.php
index 36e6f697..0ed0ee37 100644
--- a/tests/Unit/Mock/MockContainer.php
+++ b/tests/UnitTest/Mock/MockContainer.php
@@ -1,6 +1,6 @@
headers[$name] ?? '';
+ }
+
+ public function withHeader($name, $value): MessageInterface
+ {
+ $header = clone $this;
+ $header->headers[$name] = $value;
+ return $header;
+ }
+
+ public function getProtocolVersion(): string
+ {
+ // TODO: Implement getProtocolVersion() method.
+ }
+
+ public function withProtocolVersion(string $version): MessageInterface
+ {
+ // TODO: Implement withProtocolVersion() method.
+ }
+
+ public function getHeaders(): array
+ {
+ // TODO: Implement getHeaders() method.
+ }
+
+ public function hasHeader(string $name): bool
+ {
+ // TODO: Implement hasHeader() method.
+ }
+
+ public function getHeader(string $name): array
+ {
+ // TODO: Implement getHeader() method.
+ }
+
+ public function withAddedHeader(string $name, $value): MessageInterface
+ {
+ // TODO: Implement withAddedHeader() method.
+ }
+
+ public function withoutHeader(string $name): MessageInterface
+ {
+ // TODO: Implement withoutHeader() method.
+ }
+
+ public function getBody(): StreamInterface
+ {
+ // TODO: Implement getBody() method.
+ }
+
+ public function withBody(StreamInterface $body): MessageInterface
+ {
+ // TODO: Implement withBody() method.
+ }
+
+ public function getStatusCode(): int
+ {
+ // TODO: Implement getStatusCode() method.
+ }
+
+ public function withStatus(int $code, string $reasonPhrase = ''): ResponseInterface
+ {
+ // TODO: Implement withStatus() method.
+ }
+
+ public function getReasonPhrase(): string
+ {
+ // TODO: Implement getReasonPhrase() method.
+ }
+}
diff --git a/tests/UnitTest/Mock/MockServerRequest.php b/tests/UnitTest/Mock/MockServerRequest.php
new file mode 100644
index 00000000..0f3c4122
--- /dev/null
+++ b/tests/UnitTest/Mock/MockServerRequest.php
@@ -0,0 +1,192 @@
+headers;
+ }
+
+ public function hasHeader($name): bool
+ {
+ return array_key_exists($name, $this->headers);
+ }
+
+ public function getHeader($name): array
+ {
+ return array_key_exists($name, $this->headers) ? $this->headers[$name] : [];
+ }
+
+ public function getHeaderLine($name): string
+ {
+ return $this->headers[$name] ?? '';
+ }
+
+ public function withHeader($name, $value): MessageInterface
+ {
+ $header = clone $this;
+ $header->headers[$name] = $value;
+
+ return $header;
+ }
+
+ /**
+ * @return StreamInterface|array
+ */
+ public function getBody(): StreamInterface
+ {
+ return $this->body;
+ }
+
+ public function getQueryParams(): array
+ {
+ return $this->queryParams;
+ }
+
+ public function withQueryParams(array $query): self
+ {
+ $queryParams = clone $this;
+
+ $queryParams->queryParams = $query;
+
+ return $queryParams;
+ }
+
+ public function getParsedBody(): object|array|null
+ {
+ return $this->body;
+ }
+
+ public function withParsedBody($data): ServerRequestInterface
+ {
+ $body = clone $this;
+ $body->body = $data;
+
+ return $body;
+ }
+
+ public function getAttribute($name, $default = null)
+ {
+ if (array_key_exists($name, $this->attributes)) {
+ return $this->attributes[$name];
+ }
+
+ return $default;
+ }
+
+ public function withAttribute($name, $value): MockServerRequest
+ {
+ $attributes = clone $this;
+ $attributes->attributes[$name] = $value;
+
+ return $attributes;
+ }
+
+ public function getProtocolVersion(): string
+ {
+ // TODO: Implement getProtocolVersion() method.
+ }
+
+ public function withProtocolVersion(string $version): MessageInterface
+ {
+ // TODO: Implement withProtocolVersion() method.
+ }
+
+ public function withAddedHeader(string $name, $value): MessageInterface
+ {
+ // TODO: Implement withAddedHeader() method.
+ }
+
+ public function withoutHeader(string $name): MessageInterface
+ {
+ // TODO: Implement withoutHeader() method.
+ }
+
+ public function withBody(StreamInterface $body): MessageInterface
+ {
+ // TODO: Implement withBody() method.
+ }
+
+ public function getRequestTarget(): string
+ {
+ // TODO: Implement getRequestTarget() method.
+ }
+
+ public function withRequestTarget(string $requestTarget): RequestInterface
+ {
+ // TODO: Implement withRequestTarget() method.
+ }
+
+ public function getMethod(): string
+ {
+ // TODO: Implement getMethod() method.
+ }
+
+ public function withMethod(string $method): RequestInterface
+ {
+ // TODO: Implement withMethod() method.
+ }
+
+ public function getUri(): UriInterface
+ {
+ return new \Laminas\Diactoros\Uri('http://example.com/');
+ }
+
+ public function withUri(UriInterface $uri, bool $preserveHost = false): RequestInterface
+ {
+ // TODO: Implement withUri() method.
+ }
+
+ public function getServerParams(): array
+ {
+ return [];
+ }
+
+ public function getCookieParams(): array
+ {
+ // TODO: Implement getCookieParams() method.
+ }
+
+ public function withCookieParams(array $cookies): ServerRequestInterface
+ {
+ // TODO: Implement withCookieParams() method.
+ }
+
+ public function getUploadedFiles(): array
+ {
+ // TODO: Implement getUploadedFiles() method.
+ }
+
+ public function withUploadedFiles(array $uploadedFiles): ServerRequestInterface
+ {
+ // TODO: Implement withUploadedFiles() method.
+ }
+
+ public function getAttributes(): array
+ {
+ // TODO: Implement getAttributes() method.
+ }
+
+ public function withoutAttribute(string $name): ServerRequestInterface
+ {
+ // TODO: Implement withoutAttribute() method.
+ }
+}
diff --git a/tests/UnitTest/Mock/Repository/MockAccountAccessAuthRepository.php b/tests/UnitTest/Mock/Repository/MockAccountAccessAuthRepository.php
new file mode 100644
index 00000000..8cbcaa52
--- /dev/null
+++ b/tests/UnitTest/Mock/Repository/MockAccountAccessAuthRepository.php
@@ -0,0 +1,14 @@
+ $this->config->iss,
+ 'aud' => $this->config->aud,
+ 'iat' => $now,
+ 'exp' => $now + $this->config->duration,
+ 'uuid' => $uuid->getHex()->toString(),
+ ];
+
+ return JWT::encode($payload, $this->config->key, $this->config->algorithmus);
+ }
+}
diff --git a/tests/UnitTest/Mock/Service/MockAccessTokenServiceWithoutDuration.php b/tests/UnitTest/Mock/Service/MockAccessTokenServiceWithoutDuration.php
new file mode 100644
index 00000000..dc442e4b
--- /dev/null
+++ b/tests/UnitTest/Mock/Service/MockAccessTokenServiceWithoutDuration.php
@@ -0,0 +1,35 @@
+ $this->config->iss,
+ 'aud' => $this->config->aud,
+ 'iat' => $now,
+ 'exp' => $now + $this->config->duration,
+ 'uuid' => $uuid->getHex()->toString(),
+ ];
+
+ return JWT::encode($payload, $this->config->key, $this->config->algorithmus);
+ }
+}
diff --git a/tests/UnitTest/Mock/Service/MockAuthenticationService.php b/tests/UnitTest/Mock/Service/MockAuthenticationService.php
new file mode 100644
index 00000000..ed819dba
--- /dev/null
+++ b/tests/UnitTest/Mock/Service/MockAuthenticationService.php
@@ -0,0 +1,14 @@
+accountId !== Account::ID) {
+ throw new DuplicateEntryException('AccountAccessAuth', $data->id);
+ }
+
+ return true;
+ }
+
+ public function update(AccountAccessAuthInterface $data): true
+ {
+ if ($data->id !== AccountAccessAuth::ID) {
+ throw new InvalidArgumentException();
+ }
+
+ return true;
+ }
+
+ public function deleteById(int $id): true
+ {
+ if ($id !== AccountAccessAuth::ID) {
+ throw new InvalidArgumentException();
+ }
+
+ return true;
+ }
+
+ public function findById(int $id): ?AccountAccessAuthInterface
+ {
+ return $id === AccountAccessAuth::ID ? $this->hydrator->hydrate(AccountAccessAuth::VALID_DATA) : null;
+ }
+
+ public function findByAccountId(int $accountId): AccountAccessAuthCollectionInterface
+ {
+ return $accountId === AccountAccessAuth::USER_ID
+ ? $this->hydrator->hydrateCollection([0 => AccountAccessAuth::VALID_DATA])
+ : $this->hydrator->hydrateCollection(
+ []
+ );
+ }
+
+ public function findByLabel(string $label): AccountAccessAuthCollectionInterface
+ {
+ return $label === AccountAccessAuth::LABEL
+ ? $this->hydrator->hydrateCollection([0 => AccountAccessAuth::VALID_DATA])
+ : $this->hydrator->hydrateCollection(
+ []
+ );
+ }
+
+ public function findByRefreshToken(string $refreshToken): ?AccountAccessAuthInterface
+ {
+ return $refreshToken === AccountAccessAuth::REFRESH_TOKEN ? $this->hydrator->hydrate(
+ AccountAccessAuth::VALID_DATA
+ ) : null;
+ }
+
+ public function findByUserAgent(string $userAgent): AccountAccessAuthCollectionInterface
+ {
+ return $userAgent === AccountAccessAuth::USER_AGENT
+ ? $this->hydrator->hydrateCollection([0 => AccountAccessAuth::VALID_DATA])
+ : $this->hydrator->hydrateCollection(
+ []
+ );
+ }
+
+ public function findByClientIdentHash(string $clientIdentHash): ?AccountAccessAuthInterface
+ {
+ return $clientIdentHash === AccountAccessAuth::CLIENT_IDENT_HASH ? $this->hydrator->hydrate(
+ AccountAccessAuth::VALID_DATA
+ ) : null;
+ }
+
+ public function findAll(): AccountAccessAuthCollectionInterface
+ {
+ return $this->hydrator->hydrateCollection([0 => AccountAccessAuth::VALID_DATA]);
+ }
+}
diff --git a/tests/UnitTest/Mock/Table/MockAccountAccessAuthTableFailed.php b/tests/UnitTest/Mock/Table/MockAccountAccessAuthTableFailed.php
new file mode 100644
index 00000000..d184590d
--- /dev/null
+++ b/tests/UnitTest/Mock/Table/MockAccountAccessAuthTableFailed.php
@@ -0,0 +1,25 @@
+hydrator->hydrateCollection([]);
+ }
+}
diff --git a/tests/UnitTest/Mock/Table/MockAccountTable.php b/tests/UnitTest/Mock/Table/MockAccountTable.php
new file mode 100644
index 00000000..8b9e6a63
--- /dev/null
+++ b/tests/UnitTest/Mock/Table/MockAccountTable.php
@@ -0,0 +1,84 @@
+id !== Account::ID) {
+ throw new DuplicateEntryException('Account', $data->id);
+ }
+
+ return true;
+ }
+
+ public function update(AccountInterface $data): true
+ {
+ if ($data->id !== Account::ID) {
+ throw new InvalidArgumentException();
+ }
+
+ return true;
+ }
+
+ public function deleteById(int $id): true
+ {
+ if ($id !== Account::ID) {
+ throw new InvalidArgumentException();
+ }
+
+ return true;
+ }
+
+ public function findById(int $id): ?AccountInterface
+ {
+ return $id === Account::ID ? $this->hydrator->hydrate(Account::VALID_DATA) : null;
+ }
+
+ public function findByUuid(UuidInterface $uuid): ?AccountInterface
+ {
+ return $uuid->getHex()->toString() === Account::UUID ? $this->hydrator->hydrate(Account::VALID_DATA) : null;
+ }
+
+ public function findByName(string $name): ?AccountInterface
+ {
+ return $name === Account::NAME ? $this->hydrator->hydrate(Account::VALID_DATA) : null;
+ }
+
+ public function findByEmail(Email $email): ?AccountInterface
+ {
+ return $email->toString() === Account::EMAIL ? $this->hydrator->hydrate(Account::VALID_DATA) : null;
+ }
+
+ public function findAll(): AccountCollection
+ {
+ return $this->hydrator->hydrateCollection([Account::VALID_DATA]);
+ }
+}
diff --git a/tests/UnitTest/Mock/Table/MockAccountTableAccountAuthenticationMiddlewareInvalidToken.php b/tests/UnitTest/Mock/Table/MockAccountTableAccountAuthenticationMiddlewareInvalidToken.php
new file mode 100644
index 00000000..8edb8323
--- /dev/null
+++ b/tests/UnitTest/Mock/Table/MockAccountTableAccountAuthenticationMiddlewareInvalidToken.php
@@ -0,0 +1,84 @@
+id !== Account::ID) {
+ throw new DuplicateEntryException('Account', $data->id);
+ }
+
+ return true;
+ }
+
+ public function update(AccountInterface $data): true
+ {
+ if ($data->id !== Account::ID) {
+ throw new InvalidArgumentException();
+ }
+
+ return true;
+ }
+
+ public function deleteById(int $id): true
+ {
+ if ($id !== Account::ID) {
+ throw new InvalidArgumentException();
+ }
+
+ return true;
+ }
+
+ public function findById(int $id): ?AccountInterface
+ {
+ return $id === Account::ID ? $this->hydrator->hydrate(Account::VALID_DATA) : null;
+ }
+
+ public function findByUuid(UuidInterface $uuid): ?AccountInterface
+ {
+ return null;
+ }
+
+ public function findByName(string $name): ?AccountInterface
+ {
+ return $name === Account::NAME ? $this->hydrator->hydrate(Account::VALID_DATA) : null;
+ }
+
+ public function findByEmail(Email $email): ?AccountInterface
+ {
+ return $email->toString() === Account::EMAIL ? $this->hydrator->hydrate(Account::VALID_DATA) : null;
+ }
+
+ public function findAll(): AccountCollection
+ {
+ return $this->hydrator->hydrateCollection([Account::VALID_DATA]);
+ }
+}
diff --git a/tests/UnitTest/Mock/Table/MockAccountTableFailed.php b/tests/UnitTest/Mock/Table/MockAccountTableFailed.php
new file mode 100644
index 00000000..c5b78ad8
--- /dev/null
+++ b/tests/UnitTest/Mock/Table/MockAccountTableFailed.php
@@ -0,0 +1,26 @@
+hydrator->hydrateCollection([]);
+ }
+}
diff --git a/tests/UnitTest/Mock/Validator/MockAuthenticationValidator.php b/tests/UnitTest/Mock/Validator/MockAuthenticationValidator.php
new file mode 100644
index 00000000..c5b696ff
--- /dev/null
+++ b/tests/UnitTest/Mock/Validator/MockAuthenticationValidator.php
@@ -0,0 +1,20 @@
+ [
- 'driver' => 'sqlite',
- 'host' => __DIR__ . '/../../../database/database.sqlite',
- 'port' => '3306',
- 'user' => 'dev',
- 'password' => 'dev',
- 'dbname' => 'db',
- 'charset' => 'utf8mb4',
- 'error' => PDO::ERRMODE_EXCEPTION,
- ]
-];
diff --git a/tests/config/autoload/dependencies.testing.local.php b/tests/config/autoload/dependencies.testing.local.php
deleted file mode 100644
index e407b412..00000000
--- a/tests/config/autoload/dependencies.testing.local.php
+++ /dev/null
@@ -1,22 +0,0 @@
- [
- 'aliases' => [
- PDO::class => 'database',
- Envms\FluentPDO\Query::class => 'query',
- Ramsey\Uuid\Uuid::class => 'uuid',
- Symfony\Component\Mailer\Mailer::class => 'mailer',
- Psr\Log\LoggerInterface::class => 'logger',
- ],
- 'invokables' => [
- ],
- 'factories' => [
- 'database' => Core\Factory\DatabaseFactory::class,
- 'query' => Core\Factory\QueryFactory::class,
- 'uuid' => Core\Factory\UuidFactory::class,
- 'mailer' => Core\Factory\MailFactory::class,
- 'logger' => Test\Functional\Mock\NullLoggerFactory::class,
- ],
- ],
-];
diff --git a/tests/config/autoload/token.testing.local.php b/tests/config/autoload/token.testing.local.php
deleted file mode 100644
index 4e474e4e..00000000
--- a/tests/config/autoload/token.testing.local.php
+++ /dev/null
@@ -1,18 +0,0 @@
- [
- 'auth' => [
- 'secret' => 'Oqaf673OLS380moI',
- 'algorithmus' => 'HS512',
- 'duration' => 60 * 60,
- 'refresh' => 24 * 60 * 60,
- ],
- 'csrf' => [
- 'secret' => '09asd7fuIhfoUiashfo',
- 'algorithmus' => 'HS512',
- 'duration' => 60 * 60,
- 'refresh' => 24 * 60 * 60,
- ],
- ],
-];
diff --git a/tests/config/config.php b/tests/config/config.php
deleted file mode 100644
index 59e06248..00000000
--- a/tests/config/config.php
+++ /dev/null
@@ -1,24 +0,0 @@
-getMergedConfig();
diff --git a/tests/config/container.php b/tests/config/container.php
deleted file mode 100644
index 3bae2980..00000000
--- a/tests/config/container.php
+++ /dev/null
@@ -1,14 +0,0 @@
-pipe(ErrorHandler::class);
- $app->pipe(RouteMiddleware::class);
- $app->pipe(JwtAuthenticationMiddleware::class);
- $app->pipe(DispatchMiddleware::class);
- $app->pipe(NotFoundHandler::class);
-};
diff --git a/tests/config/routes.php b/tests/config/routes.php
deleted file mode 100644
index 09a31d37..00000000
--- a/tests/config/routes.php
+++ /dev/null
@@ -1,19 +0,0 @@
-get('/api/ping[/]', PingHandler::class, PingHandler::class);
-
- $app->get(
- '/api/user/me[/]',
- [
- ApiMeHandler::class,
- ],
- ApiMeHandler::class
- );
-};