$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
new file mode 100644
index 00000000..a75c54c1
--- /dev/null
+++ b/src/App/Handler/Event/EventListHandler.php
@@ -0,0 +1,47 @@
+
+ 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
new file mode 100644
index 00000000..8730357c
--- /dev/null
+++ b/src/App/Handler/Event/EventNameHandler.php
@@ -0,0 +1,27 @@
+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
new file mode 100644
index 00000000..e1da6b66
--- /dev/null
+++ b/src/App/Handler/Event/EventParticipantSubscribeHandler.php
@@ -0,0 +1,53 @@
+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
new file mode 100644
index 00000000..d0747b0c
--- /dev/null
+++ b/src/App/Handler/Event/EventParticipantUnsubscribeHandler.php
@@ -0,0 +1,22 @@
+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/SwaggerUIHandler.php b/src/App/Handler/SwaggerUIHandler.php
deleted file mode 100644
index f114ab17..00000000
--- a/src/App/Handler/SwaggerUIHandler.php
+++ /dev/null
@@ -1,57 +0,0 @@
- []], ['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
new file mode 100644
index 00000000..60378705
--- /dev/null
+++ b/src/App/Handler/System/ApiMeHandler.php
@@ -0,0 +1,57 @@
+ []]],
+)]
+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/PingHandler.php b/src/App/Handler/System/PingHandler.php
similarity index 72%
rename from src/App/Handler/PingHandler.php
rename to src/App/Handler/System/PingHandler.php
index be50fa47..74b9ec0a 100644
--- a/src/App/Handler/PingHandler.php
+++ b/src/App/Handler/System/PingHandler.php
@@ -1,12 +1,10 @@
value,
+ description: 'Success',
content: [
new OA\JsonContent(
properties: [
new OA\Property(
property: 'ack',
- description: 'actually request time',
- type: DataType::STRING->value,
+ description: 'actually time',
+ type: 'string'
),
]
),
]
),
- ]
+ ],
+ deprecated: true
)]
public function handle(ServerRequestInterface $request): ResponseInterface
{
diff --git a/src/App/Handler/System/TestMailHandler.php b/src/App/Handler/System/TestMailHandler.php
new file mode 100644
index 00000000..97ff1d0a
--- /dev/null
+++ b/src/App/Handler/System/TestMailHandler.php
@@ -0,0 +1,32 @@
+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
new file mode 100644
index 00000000..012d432e
--- /dev/null
+++ b/src/App/Handler/Topic/TopicCreateHandler.php
@@ -0,0 +1,59 @@
+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
new file mode 100644
index 00000000..c1ceba35
--- /dev/null
+++ b/src/App/Handler/Topic/TopicListAvailableHandler.php
@@ -0,0 +1,38 @@
+ $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
deleted file mode 100644
index 882507c4..00000000
--- a/src/App/Hydrator/AccountAccessAuthHydrator.php
+++ /dev/null
@@ -1,68 +0,0 @@
-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
deleted file mode 100644
index 1b16b3f7..00000000
--- a/src/App/Hydrator/AccountAccessAuthHydratorInterface.php
+++ /dev/null
@@ -1,14 +0,0 @@
-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
deleted file mode 100644
index aad28f48..00000000
--- a/src/App/Hydrator/AccountActivationHydratorInterface.php
+++ /dev/null
@@ -1,14 +0,0 @@
-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
deleted file mode 100644
index 3379238b..00000000
--- a/src/App/Hydrator/AccountHydratorInterface.php
+++ /dev/null
@@ -1,14 +0,0 @@
-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
deleted file mode 100644
index c1ac0358..00000000
--- a/src/App/Hydrator/TokenHydratorInterface.php
+++ /dev/null
@@ -1,14 +0,0 @@
-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
deleted file mode 100644
index 9a533b97..00000000
--- a/src/App/Middleware/Account/LastAktivityUpdaterMiddleware.php
+++ /dev/null
@@ -1,35 +0,0 @@
-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
deleted file mode 100644
index c804b372..00000000
--- a/src/App/Middleware/Account/LoginAuthentication/AuthenticationConditionsMiddleware.php
+++ /dev/null
@@ -1,30 +0,0 @@
-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
deleted file mode 100644
index bfc41663..00000000
--- a/src/App/Middleware/Account/LoginAuthentication/AuthenticationMiddleware.php
+++ /dev/null
@@ -1,72 +0,0 @@
-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
deleted file mode 100644
index 9291538e..00000000
--- a/src/App/Middleware/Account/LoginAuthentication/AuthenticationValidationMiddleware.php
+++ /dev/null
@@ -1,40 +0,0 @@
-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
deleted file mode 100644
index 25155700..00000000
--- a/src/App/Middleware/Account/LoginAuthentication/PersistAuthenticationMiddleware.php
+++ /dev/null
@@ -1,79 +0,0 @@
-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
deleted file mode 100644
index ad9d9d46..00000000
--- a/src/App/Middleware/Account/LogoutMiddleware.php
+++ /dev/null
@@ -1,63 +0,0 @@
-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
deleted file mode 100644
index 31013d8d..00000000
--- a/src/App/Middleware/Account/PasswordChangeMiddleware.php
+++ /dev/null
@@ -1,68 +0,0 @@
-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
deleted file mode 100644
index f72db6be..00000000
--- a/src/App/Middleware/Account/PasswordForgottenMiddleware.php
+++ /dev/null
@@ -1,42 +0,0 @@
-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
deleted file mode 100644
index 3a9e16b9..00000000
--- a/src/App/Middleware/Account/RegisterMiddleware.php
+++ /dev/null
@@ -1,58 +0,0 @@
-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
deleted file mode 100644
index 6330b90f..00000000
--- a/src/App/Middleware/Account/RequestAuthenticationMiddleware.php
+++ /dev/null
@@ -1,76 +0,0 @@
-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
deleted file mode 100644
index 7c87bcd2..00000000
--- a/src/App/Middleware/Account/Validation/ActivationInputValidatorMiddleware.php
+++ /dev/null
@@ -1,45 +0,0 @@
-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
deleted file mode 100644
index 0913cf04..00000000
--- a/src/App/Middleware/Account/Validation/EmailInputValidatorMiddleware.php
+++ /dev/null
@@ -1,47 +0,0 @@
-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
deleted file mode 100644
index 8cea3ba0..00000000
--- a/src/App/Middleware/Account/Validation/PasswordInputValidatorMiddleware.php
+++ /dev/null
@@ -1,39 +0,0 @@
-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
deleted file mode 100644
index a251414a..00000000
--- a/src/App/Middleware/ClientIdentification/ClientIdentificationMiddleware.php
+++ /dev/null
@@ -1,31 +0,0 @@
-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
new file mode 100644
index 00000000..a5bfb842
--- /dev/null
+++ b/src/App/Middleware/Event/EventCreateMiddleware.php
@@ -0,0 +1,44 @@
+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
new file mode 100644
index 00000000..96d8247a
--- /dev/null
+++ b/src/App/Middleware/Event/EventCreateMiddlewareFactory.php
@@ -0,0 +1,42 @@
+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
new file mode 100644
index 00000000..3d136eb6
--- /dev/null
+++ b/src/App/Middleware/Event/EventCreateValidationMiddleware.php
@@ -0,0 +1,35 @@
+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
new file mode 100644
index 00000000..466b77fb
--- /dev/null
+++ b/src/App/Middleware/Event/EventListMiddleware.php
@@ -0,0 +1,67 @@
+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
new file mode 100644
index 00000000..4dfc01ef
--- /dev/null
+++ b/src/App/Middleware/Event/EventMiddleware.php
@@ -0,0 +1,27 @@
+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
new file mode 100644
index 00000000..a9d3258c
--- /dev/null
+++ b/src/App/Middleware/Event/EventNameMiddleware.php
@@ -0,0 +1,32 @@
+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
new file mode 100644
index 00000000..0d76d5a2
--- /dev/null
+++ b/src/App/Middleware/Event/EventParticipantSubscribeMiddleware.php
@@ -0,0 +1,50 @@
+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
new file mode 100644
index 00000000..6072ffb4
--- /dev/null
+++ b/src/App/Middleware/Event/EventParticipantUnsubscribeMiddleware.php
@@ -0,0 +1,42 @@
+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
new file mode 100644
index 00000000..39bddb68
--- /dev/null
+++ b/src/App/Middleware/Project/ProjectMiddleware.php
@@ -0,0 +1,27 @@
+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
new file mode 100644
index 00000000..16779bb4
--- /dev/null
+++ b/src/App/Middleware/Project/ProjectOwnerMiddleware.php
@@ -0,0 +1,30 @@
+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
new file mode 100644
index 00000000..9182cd33
--- /dev/null
+++ b/src/App/Middleware/Project/ProjectParticipantMiddleware.php
@@ -0,0 +1,31 @@
+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
deleted file mode 100644
index 747eb58d..00000000
--- a/src/App/Middleware/Token/AccessTokenValidationMiddleware.php
+++ /dev/null
@@ -1,47 +0,0 @@
-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
deleted file mode 100644
index 3c94050c..00000000
--- a/src/App/Middleware/Token/GenerateAccessTokenMiddleware.php
+++ /dev/null
@@ -1,31 +0,0 @@
-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
deleted file mode 100644
index bbbc10cc..00000000
--- a/src/App/Middleware/Token/GenerateRefreshTokenMiddleware.php
+++ /dev/null
@@ -1,30 +0,0 @@
-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
deleted file mode 100644
index 428ea70c..00000000
--- a/src/App/Middleware/Token/RefreshTokenAccountMiddleware.php
+++ /dev/null
@@ -1,46 +0,0 @@
-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
deleted file mode 100644
index b2883911..00000000
--- a/src/App/Middleware/Token/RefreshTokenDatabaseExistenceMiddleware.php
+++ /dev/null
@@ -1,43 +0,0 @@
-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
deleted file mode 100644
index 265b1a93..00000000
--- a/src/App/Middleware/Token/RefreshTokenMatchClientIdentificationMiddleware.php
+++ /dev/null
@@ -1,43 +0,0 @@
-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
deleted file mode 100644
index 0ccdc0cf..00000000
--- a/src/App/Middleware/Token/RefreshTokenValidationMiddleware.php
+++ /dev/null
@@ -1,40 +0,0 @@
-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
new file mode 100644
index 00000000..3d1589ce
--- /dev/null
+++ b/src/App/Middleware/Topic/TopicCreateSubmitMiddleware.php
@@ -0,0 +1,46 @@
+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
new file mode 100644
index 00000000..9d2ac799
--- /dev/null
+++ b/src/App/Middleware/Topic/TopicCreateValidationMiddleware.php
@@ -0,0 +1,34 @@
+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
new file mode 100644
index 00000000..3008b7f0
--- /dev/null
+++ b/src/App/Middleware/Topic/TopicEntryStatisticMiddleware.php
@@ -0,0 +1,24 @@
+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
new file mode 100644
index 00000000..f5249469
--- /dev/null
+++ b/src/App/Middleware/Topic/TopicListAvailableMiddleware.php
@@ -0,0 +1,26 @@
+topicPoolService->findAvailable();
+ $topics = new TopicListDto($topics);
+
+ return $handler->handle($request->withAttribute(TopicListDto::class, $topics));
+ }
+}
diff --git a/src/Core/Middleware/RouteNotFoundMiddleware.php b/src/App/Middleware/Topic/TopicListMiddleware.php
similarity index 54%
rename from src/Core/Middleware/RouteNotFoundMiddleware.php
rename to src/App/Middleware/Topic/TopicListMiddleware.php
index aa37efe6..3d647d38 100644
--- a/src/Core/Middleware/RouteNotFoundMiddleware.php
+++ b/src/App/Middleware/Topic/TopicListMiddleware.php
@@ -1,24 +1,24 @@
logger->notice('Route not found');
+ $topics = $this->topicPoolService->findAll();
- return $handler->handle($request);
+ return $handler->handle($request->withAttribute('topics', $topics));
}
}
diff --git a/src/App/Repository/AccountAccessAuthRepository.php b/src/App/Repository/AccountAccessAuthRepository.php
deleted file mode 100644
index ae69bc9c..00000000
--- a/src/App/Repository/AccountAccessAuthRepository.php
+++ /dev/null
@@ -1,71 +0,0 @@
-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
deleted file mode 100644
index a87a19e0..00000000
--- a/src/App/Repository/AccountActivationRepository.php
+++ /dev/null
@@ -1,57 +0,0 @@
-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
deleted file mode 100644
index 1fbe69e4..00000000
--- a/src/App/Repository/AccountRepository.php
+++ /dev/null
@@ -1,58 +0,0 @@
-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
new file mode 100644
index 00000000..2c0a69dc
--- /dev/null
+++ b/src/App/Repository/EventRepository.php
@@ -0,0 +1,21 @@
+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
new file mode 100644
index 00000000..e5e19714
--- /dev/null
+++ b/src/App/Repository/TopicPoolRepository.php
@@ -0,0 +1,27 @@
+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
deleted file mode 100644
index bf48bac5..00000000
--- a/src/App/Service/Authentication/AuthenticationService.php
+++ /dev/null
@@ -1,11 +0,0 @@
-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
new file mode 100644
index 00000000..1ae4f642
--- /dev/null
+++ b/src/App/Service/EMail/EMailServiceInterface.php
@@ -0,0 +1,10 @@
+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
new file mode 100644
index 00000000..b231a896
--- /dev/null
+++ b/src/App/Service/EMail/TopicCreateEMailServiceFactory.php
@@ -0,0 +1,20 @@
+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
new file mode 100644
index 00000000..cd685c3c
--- /dev/null
+++ b/src/App/Service/Event/EventService.php
@@ -0,0 +1,94 @@
+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
new file mode 100644
index 00000000..2efb2f32
--- /dev/null
+++ b/src/App/Service/Event/EventServiceFactory.php
@@ -0,0 +1,48 @@
+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
new file mode 100644
index 00000000..f1ce23d1
--- /dev/null
+++ b/src/App/Service/Participant/ParticipantService.php
@@ -0,0 +1,77 @@
+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
new file mode 100644
index 00000000..eb8e157a
--- /dev/null
+++ b/src/App/Service/Participant/ParticipantServiceFactory.php
@@ -0,0 +1,30 @@
+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
new file mode 100644
index 00000000..f340cb6d
--- /dev/null
+++ b/src/App/Service/Project/ProjectService.php
@@ -0,0 +1,41 @@
+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
new file mode 100644
index 00000000..784ded97
--- /dev/null
+++ b/src/App/Service/Project/ProjectServiceFactory.php
@@ -0,0 +1,36 @@
+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
deleted file mode 100644
index 016a53aa..00000000
--- a/src/App/Service/Token/AccessTokenService.php
+++ /dev/null
@@ -1,34 +0,0 @@
- $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
deleted file mode 100644
index ba0b2d36..00000000
--- a/src/App/Service/Token/AccessTokenServiceFactory.php
+++ /dev/null
@@ -1,17 +0,0 @@
-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
deleted file mode 100644
index c7444652..00000000
--- a/src/App/Service/Token/ActivationTokenService.php
+++ /dev/null
@@ -1,30 +0,0 @@
-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
deleted file mode 100644
index db9d14a9..00000000
--- a/src/App/Service/Token/JwtTokenTrait.php
+++ /dev/null
@@ -1,42 +0,0 @@
-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
deleted file mode 100644
index 962fc064..00000000
--- a/src/App/Service/Token/PasswordTokenService.php
+++ /dev/null
@@ -1,31 +0,0 @@
-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
deleted file mode 100644
index 3863e2bb..00000000
--- a/src/App/Service/Token/RefreshTokenService.php
+++ /dev/null
@@ -1,34 +0,0 @@
- $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
deleted file mode 100644
index 9f0877f8..00000000
--- a/src/App/Service/Token/RefreshTokenServiceFactory.php
+++ /dev/null
@@ -1,17 +0,0 @@
-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
new file mode 100644
index 00000000..37f907e0
--- /dev/null
+++ b/src/App/Service/Topic/TopicPoolService.php
@@ -0,0 +1,112 @@
+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
new file mode 100644
index 00000000..f1d579a2
--- /dev/null
+++ b/src/App/Service/Topic/TopicPoolServiceFactory.php
@@ -0,0 +1,27 @@
+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
new file mode 100644
index 00000000..9cff7f00
--- /dev/null
+++ b/src/App/Service/User/UserService.php
@@ -0,0 +1,95 @@
+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
new file mode 100644
index 00000000..21b3e213
--- /dev/null
+++ b/src/App/Service/User/UserServiceFactory.php
@@ -0,0 +1,52 @@
+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
deleted file mode 100644
index 859829c5..00000000
--- a/src/App/Table/AbstractTable.php
+++ /dev/null
@@ -1,44 +0,0 @@
-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
deleted file mode 100644
index f0aa363c..00000000
--- a/src/App/Table/AccountAccessAuthTable.php
+++ /dev/null
@@ -1,143 +0,0 @@
-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
deleted file mode 100644
index 137b1823..00000000
--- a/src/App/Table/AccountActivationTable.php
+++ /dev/null
@@ -1,105 +0,0 @@
-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
deleted file mode 100644
index 2bc5dca5..00000000
--- a/src/App/Table/AccountTable.php
+++ /dev/null
@@ -1,105 +0,0 @@
-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
new file mode 100644
index 00000000..d789fec6
--- /dev/null
+++ b/src/App/Table/EventTable.php
@@ -0,0 +1,75 @@
+ $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
new file mode 100644
index 00000000..65a8532f
--- /dev/null
+++ b/src/App/Table/ParticipantTable.php
@@ -0,0 +1,69 @@
+ $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
new file mode 100644
index 00000000..f6ecdc73
--- /dev/null
+++ b/src/App/Table/ProjectTable.php
@@ -0,0 +1,16 @@
+query->from($this->table)
+ ->where('participantId', $id)
+ ->fetch();
+ }
+}
diff --git a/src/App/Table/TokenTable.php b/src/App/Table/TokenTable.php
deleted file mode 100644
index 63425c1e..00000000
--- a/src/App/Table/TokenTable.php
+++ /dev/null
@@ -1,104 +0,0 @@
-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
new file mode 100644
index 00000000..4189adb1
--- /dev/null
+++ b/src/App/Table/TopicPoolTable.php
@@ -0,0 +1,89 @@
+ $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
deleted file mode 100644
index 9a9ad148..00000000
--- a/src/App/Validator/AccountActivationValidator.php
+++ /dev/null
@@ -1,18 +0,0 @@
-add($this->accountNameInput);
- $this->add($this->passwordInput);
- }
-}
diff --git a/src/App/Validator/AuthenticationValidator.php b/src/App/Validator/AuthenticationValidator.php
deleted file mode 100644
index f01eca9c..00000000
--- a/src/App/Validator/AuthenticationValidator.php
+++ /dev/null
@@ -1,18 +0,0 @@
-add($this->emailInput);
- $this->add($this->passwordInput);
- }
-}
diff --git a/src/App/Validator/EventCreateValidator.php b/src/App/Validator/EventCreateValidator.php
new file mode 100644
index 00000000..e375eb59
--- /dev/null
+++ b/src/App/Validator/EventCreateValidator.php
@@ -0,0 +1,27 @@
+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/Event/EventDescriptionInput.php b/src/App/Validator/Input/Event/EventDescriptionInput.php
new file mode 100644
index 00000000..1fa4114c
--- /dev/null
+++ b/src/App/Validator/Input/Event/EventDescriptionInput.php
@@ -0,0 +1,27 @@
+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
new file mode 100644
index 00000000..689f0fad
--- /dev/null
+++ b/src/App/Validator/Input/Event/EventDurationInput.php
@@ -0,0 +1,26 @@
+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
new file mode 100644
index 00000000..5d7f8b52
--- /dev/null
+++ b/src/App/Validator/Input/Event/EventStartTimeInput.php
@@ -0,0 +1,27 @@
+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
new file mode 100644
index 00000000..d8f70f34
--- /dev/null
+++ b/src/App/Validator/Input/Event/EventTextInput.php
@@ -0,0 +1,27 @@
+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
new file mode 100644
index 00000000..5dbdeded
--- /dev/null
+++ b/src/App/Validator/Input/Event/EventTitleInput.php
@@ -0,0 +1,27 @@
+setRequired(true);
+
+ $this->getFilterChain()->attachByName('StringTrim');
+
+ $this->getValidatorChain()->attachByName(
+ 'StringLength',
+ [
+ 'encoding' => 'UTF-8',
+ 'min' => 3,
+ 'max' => 50,
+ 'inclusive' => true,
+ ]
+ );
+ }
+}
diff --git a/src/App/Validator/Input/Topic/TopicDescriptionInput.php b/src/App/Validator/Input/Topic/TopicDescriptionInput.php
new file mode 100644
index 00000000..d7a16a79
--- /dev/null
+++ b/src/App/Validator/Input/Topic/TopicDescriptionInput.php
@@ -0,0 +1,26 @@
+setRequired(true);
+
+ $this->getFilterChain()->attachByName('StringTrim');
+
+ $this->getValidatorChain()->attachByName(
+ 'StringLength',
+ [
+ 'encoding' => 'UTF-8',
+ 'min' => 20,
+ 'max' => 8096,
+ ]
+ );
+ }
+}
diff --git a/src/App/Validator/Input/AccountNameInput.php b/src/App/Validator/Input/Topic/TopicInput.php
similarity index 73%
rename from src/App/Validator/Input/AccountNameInput.php
rename to src/App/Validator/Input/Topic/TopicInput.php
index efedd759..e2591493 100644
--- a/src/App/Validator/Input/AccountNameInput.php
+++ b/src/App/Validator/Input/Topic/TopicInput.php
@@ -1,14 +1,14 @@
setRequired(true);
@@ -19,7 +19,7 @@ public function __construct()
[
'encoding' => 'UTF-8',
'min' => 3,
- 'max' => 64,
+ 'max' => 50,
]
);
}
diff --git a/src/App/Validator/TopicCreateValidator.php b/src/App/Validator/TopicCreateValidator.php
new file mode 100644
index 00000000..1d8516fb
--- /dev/null
+++ b/src/App/Validator/TopicCreateValidator.php
@@ -0,0 +1,18 @@
+add($this->topicInput);
+ $this->add($this->topicDescriptionInput);
+ }
+}
diff --git a/src/Core/ConfigProvider.php b/src/Core/ConfigProvider.php
index 17e6d5ca..264b8db6 100644
--- a/src/Core/ConfigProvider.php
+++ b/src/Core/ConfigProvider.php
@@ -2,10 +2,29 @@
namespace Core;
-use App\Validator\Input\EmailInput;
-use App\Validator\Input\PasswordInput;
+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 Laminas\ServiceManager\AbstractFactory\ConfigAbstractFactory;
-use Psr\Log\LoggerInterface;
class ConfigProvider
{
@@ -21,16 +40,50 @@ public function getDependencies(): array
{
return [
'invokables' => [
- EmailInput::class => EmailInput::class,
- PasswordInput::class => PasswordInput::class,
+ ReflectionHydrator::class,
+
+ Validator\Input\EmailInput::class,
+ Validator\Input\PasswordInput::class,
+ Validator\Input\UsernameInput::class,
],
'aliases' => [
+ UserRepository::class => UserTable::class,
],
'factories' => [
- Factory\ErrorResponseFactory::class => ConfigAbstractFactory::class,
- Middleware\ApiErrorHandlerMiddleware::class => ConfigAbstractFactory::class,
- Middleware\RouteNotFoundMiddleware::class => ConfigAbstractFactory::class,
+ 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,
+ 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,
],
];
}
@@ -38,14 +91,65 @@ public function getDependencies(): array
public function getAbstractFactoryConfig(): array
{
return [
- Factory\ErrorResponseFactory::class => [
- LoggerInterface::class,
+ 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,
],
- Middleware\ApiErrorHandlerMiddleware::class => [
- Factory\ErrorResponseFactory::class,
+ Validator\RegisterValidator::class => [
+ Validator\Input\EmailInput::class,
],
- Middleware\RouteNotFoundMiddleware::class => [
- LoggerInterface::class,
+ Validator\UserPasswordChangeValidator::class => [
+ Validator\Input\PasswordInput::class,
],
];
}
diff --git a/src/Core/Dto/ApiMeDto.php b/src/Core/Dto/ApiMeDto.php
new file mode 100644
index 00000000..21e1747f
--- /dev/null
+++ b/src/Core/Dto/ApiMeDto.php
@@ -0,0 +1,38 @@
+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
new file mode 100644
index 00000000..781c960f
--- /dev/null
+++ b/src/Core/Dto/HttpStatusCodeMessage.php
@@ -0,0 +1,35 @@
+status = $status;
+ $this->message = $message;
+ $this->data = $data;
+ }
+}
diff --git a/src/Core/Dto/SimpleMessageDto.php b/src/Core/Dto/SimpleMessageDto.php
new file mode 100644
index 00000000..0ff6ba79
--- /dev/null
+++ b/src/Core/Dto/SimpleMessageDto.php
@@ -0,0 +1,20 @@
+message = $message;
+ }
+}
diff --git a/src/Core/Dto/User/LoginTokenDto.php b/src/Core/Dto/User/LoginTokenDto.php
new file mode 100644
index 00000000..76034da5
--- /dev/null
+++ b/src/Core/Dto/User/LoginTokenDto.php
@@ -0,0 +1,20 @@
+token = $token;
+ }
+}
diff --git a/src/Core/Dto/User/LoginValidationFailureMessageDto.php b/src/Core/Dto/User/LoginValidationFailureMessageDto.php
new file mode 100644
index 00000000..5e2868c6
--- /dev/null
+++ b/src/Core/Dto/User/LoginValidationFailureMessageDto.php
@@ -0,0 +1,36 @@
+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
new file mode 100644
index 00000000..e5c8b902
--- /dev/null
+++ b/src/Core/Dto/User/UserLogInDataDto.php
@@ -0,0 +1,27 @@
+username = $username;
+ $this->password = $password;
+ }
+}
diff --git a/src/Core/Entity/Account/AccountAccessAuthCollectionInterface.php b/src/Core/Entity/Account/AccountAccessAuthCollectionInterface.php
deleted file mode 100644
index 173da23d..00000000
--- a/src/Core/Entity/Account/AccountAccessAuthCollectionInterface.php
+++ /dev/null
@@ -1,16 +0,0 @@
- '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
deleted file mode 100644
index f0d1095f..00000000
--- a/src/Core/Enum/AccountVisibleStatus.php
+++ /dev/null
@@ -1,23 +0,0 @@
- '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
deleted file mode 100644
index fca7e15b..00000000
--- a/src/Core/Enum/DataType.php
+++ /dev/null
@@ -1,19 +0,0 @@
-value, $this->getHttpStatusCode(), $previous);
- $this->context = $context;
- $this->responseMessage = $responseMessage;
- $this->logLevel = $loglevel;
+ $this->jsonMessage = $jsonMessage;
+ parent::__construct('', $code, $previous);
}
- abstract public function getHttpStatusCode(): int;
-
- public function getContext(): array
- {
- return $this->context;
- }
-
- public function getResponseMessage(): StatusMessage
- {
- return $this->responseMessage;
- }
-
- public function getLogLevel(): Level
+ public function getJSonMessage(): array
{
- return $this->logLevel;
+ return $this->jsonMessage;
}
}
diff --git a/src/Core/Middleware/ApiErrorHandlerMiddleware.php b/src/Core/Exception/HttpExceptionMiddleware.php
similarity index 52%
rename from src/Core/Middleware/ApiErrorHandlerMiddleware.php
rename to src/Core/Exception/HttpExceptionMiddleware.php
index a9371244..33f814df 100644
--- a/src/Core/Middleware/ApiErrorHandlerMiddleware.php
+++ b/src/Core/Exception/HttpExceptionMiddleware.php
@@ -1,27 +1,21 @@
handle($request);
- } catch (Throwable $e) {
- return $this->errorResponseFactory->createFromThrowable($e);
+ } catch (HttpException $e) {
+ return new JsonResponse($e->getJSonMessage(), $e->getCode());
}
}
}
diff --git a/src/Core/Exception/HttpHandledInvalidArgumentAsSuccessException.php b/src/Core/Exception/HttpHandledInvalidArgumentAsSuccessException.php
deleted file mode 100644
index 5ea924b6..00000000
--- a/src/Core/Exception/HttpHandledInvalidArgumentAsSuccessException.php
+++ /dev/null
@@ -1,27 +0,0 @@
-get('config')['database'];
+ $settings = $container->get('config');
+ $settings = $settings['database'];
$dsn = $settings['driver'] === 'mysql'
? 'mysql:dbname=' . $settings['dbname'] . ';host=' . $settings['host'] . ';port=' . $settings['port']
@@ -25,7 +20,7 @@ public function __invoke(ContainerInterface $container): PDO
$password = $settings['password'];
$options = [
PDO::ATTR_ERRMODE => $settings['error'],
- PDO::ATTR_EMULATE_PREPARES => $settings['emulate_prepares'],
+ PDO::ATTR_EMULATE_PREPARES => false,
];
return new PDO($dsn, $user, $password, $options);
diff --git a/src/Core/Factory/ErrorResponseFactory.php b/src/Core/Factory/ErrorResponseFactory.php
deleted file mode 100644
index d0c2222a..00000000
--- a/src/Core/Factory/ErrorResponseFactory.php
+++ /dev/null
@@ -1,51 +0,0 @@
-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
new file mode 100644
index 00000000..35978e94
--- /dev/null
+++ b/src/Core/Factory/LoggerFactory.php
@@ -0,0 +1,53 @@
+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 140c2c3e..ce2fde8a 100644
--- a/src/Core/Factory/MailFactory.php
+++ b/src/Core/Factory/MailFactory.php
@@ -4,12 +4,11 @@
use Psr\Container\ContainerInterface;
use Symfony\Component\Mailer\Mailer;
-use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mailer\Transport;
-class MailFactory
+readonly class MailFactory
{
- public function __invoke(ContainerInterface $container): MailerInterface
+ public function __invoke(ContainerInterface $container): Mailer
{
$settings = $container->get('config');
diff --git a/src/Core/Factory/QueryFactory.php b/src/Core/Factory/QueryFactory.php
index 063a6deb..4b88cd3b 100644
--- a/src/Core/Factory/QueryFactory.php
+++ b/src/Core/Factory/QueryFactory.php
@@ -4,16 +4,10 @@
use Envms\FluentPDO\Query;
use PDO;
-use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
-use Psr\Container\NotFoundExceptionInterface;
-class QueryFactory
+readonly 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 cf9e115e..6d926697 100644
--- a/src/Core/Factory/UuidFactory.php
+++ b/src/Core/Factory/UuidFactory.php
@@ -2,12 +2,14 @@
namespace Core\Factory;
-use Core\Utils\UuidFactoryInterface;
+use Psr\Container\ContainerInterface;
+use Ramsey\Uuid\Uuid;
+use Ramsey\Uuid\UuidInterface;
-class UuidFactory
+readonly class UuidFactory
{
- public function __invoke(): UuidFactoryInterface
+ public function __invoke(ContainerInterface $container): UuidInterface
{
- return new \Core\Utils\UuidFactory();
+ return Uuid::uuid7();
}
}
diff --git a/src/Core/Handler/LoginHandler.php b/src/Core/Handler/LoginHandler.php
new file mode 100644
index 00000000..31f3f544
--- /dev/null
+++ b/src/Core/Handler/LoginHandler.php
@@ -0,0 +1,64 @@
+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
new file mode 100644
index 00000000..05b90f7f
--- /dev/null
+++ b/src/Core/Handler/LoginHandlerFactory.php
@@ -0,0 +1,15 @@
+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
new file mode 100644
index 00000000..c2e37e24
--- /dev/null
+++ b/src/Core/Handler/LogoutHandler.php
@@ -0,0 +1,32 @@
+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
new file mode 100644
index 00000000..47a8cf03
--- /dev/null
+++ b/src/Core/Handler/UserPasswordChangeHandler.php
@@ -0,0 +1,17 @@
+ 'Password was changed'], HTTP::STATUS_OK);
+ }
+}
diff --git a/src/Core/Handler/UserPasswordForgottonHandler.php b/src/Core/Handler/UserPasswordForgottonHandler.php
new file mode 100644
index 00000000..0b2d2e5d
--- /dev/null
+++ b/src/Core/Handler/UserPasswordForgottonHandler.php
@@ -0,0 +1,48 @@
+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
new file mode 100644
index 00000000..b19bb54f
--- /dev/null
+++ b/src/Core/Handler/UserPasswordForgottonHandlerFactory.php
@@ -0,0 +1,18 @@
+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
new file mode 100644
index 00000000..a9c0b05f
--- /dev/null
+++ b/src/Core/Handler/UserPasswordVerifyTokenHandler.php
@@ -0,0 +1,17 @@
+ 'Token verification successful'], HTTP::STATUS_OK);
+ }
+}
diff --git a/src/Core/Handler/UserRegisterSubmitHandler.php b/src/Core/Handler/UserRegisterSubmitHandler.php
new file mode 100644
index 00000000..148ad2ea
--- /dev/null
+++ b/src/Core/Handler/UserRegisterSubmitHandler.php
@@ -0,0 +1,33 @@
+ 'Account was created'], HTTP::STATUS_OK);
+ }
+}
diff --git a/src/Core/Hydrator/ClassMethodsHydratorFactory.php b/src/Core/Hydrator/ClassMethodsHydratorFactory.php
new file mode 100644
index 00000000..b19b4cd7
--- /dev/null
+++ b/src/Core/Hydrator/ClassMethodsHydratorFactory.php
@@ -0,0 +1,14 @@
+get(DateTimeFormatterStrategy::class);
+
+ return new NullableStrategy($dateTimeFormatterStrategy);
+ }
+}
diff --git a/src/Core/Hydrator/ReflectionHydrator.php b/src/Core/Hydrator/ReflectionHydrator.php
new file mode 100644
index 00000000..db839053
--- /dev/null
+++ b/src/Core/Hydrator/ReflectionHydrator.php
@@ -0,0 +1,49 @@
+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
new file mode 100644
index 00000000..0bd5a9a9
--- /dev/null
+++ b/src/Core/Hydrator/Strategy/UuidStrategy.php
@@ -0,0 +1,47 @@
+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
new file mode 100644
index 00000000..2c4d3148
--- /dev/null
+++ b/src/Core/Listener/LoggingErrorListener.php
@@ -0,0 +1,32 @@
+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
new file mode 100644
index 00000000..3fc7da4b
--- /dev/null
+++ b/src/Core/Listener/LoggingErrorListenerDelegatorFactory.php
@@ -0,0 +1,17 @@
+get(LoggingErrorListener::class);
+ $errorHandler = $callback();
+ $errorHandler->attachListener($listener);
+ return $errorHandler;
+ }
+}
diff --git a/src/Core/Listener/LoggingErrorListenerFactory.php b/src/Core/Listener/LoggingErrorListenerFactory.php
new file mode 100644
index 00000000..2e56cf95
--- /dev/null
+++ b/src/Core/Listener/LoggingErrorListenerFactory.php
@@ -0,0 +1,16 @@
+get(LoggerInterface::class);
+
+ return new LoggingErrorListener($logger);
+ }
+}
diff --git a/src/Core/Logger/BaseInformationProcessor.php b/src/Core/Logger/BaseInformationProcessor.php
new file mode 100644
index 00000000..470baa38
--- /dev/null
+++ b/src/Core/Logger/BaseInformationProcessor.php
@@ -0,0 +1,29 @@
+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
deleted file mode 100644
index ff02b90f..00000000
--- a/src/Core/Logger/MetaDataProcessor.php
+++ /dev/null
@@ -1,29 +0,0 @@
-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
new file mode 100644
index 00000000..7df0c0ab
--- /dev/null
+++ b/src/Core/Middleware/ApiAccessMiddleware.php
@@ -0,0 +1,30 @@
+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/Middleware/IsLoggedInAuthenticationMiddleware.php b/src/Core/Middleware/IsLoggedInAuthenticationMiddleware.php
new file mode 100644
index 00000000..96feafb5
--- /dev/null
+++ b/src/Core/Middleware/IsLoggedInAuthenticationMiddleware.php
@@ -0,0 +1,29 @@
+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
new file mode 100644
index 00000000..2cae4b3d
--- /dev/null
+++ b/src/Core/Middleware/JwtAuthenticationMiddleware.php
@@ -0,0 +1,60 @@
+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
new file mode 100644
index 00000000..1d916e19
--- /dev/null
+++ b/src/Core/Middleware/JwtAuthenticationMiddlewareFactory.php
@@ -0,0 +1,24 @@
+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
new file mode 100644
index 00000000..ab4efbda
--- /dev/null
+++ b/src/Core/Middleware/LoginAuthenticationMiddleware.php
@@ -0,0 +1,41 @@
+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
new file mode 100644
index 00000000..5acb8896
--- /dev/null
+++ b/src/Core/Middleware/LoginValidationMiddleware.php
@@ -0,0 +1,37 @@
+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/Core/Middleware/UpdateLastUserActionTimeMiddleware.php b/src/Core/Middleware/UpdateLastUserActionTimeMiddleware.php
new file mode 100644
index 00000000..368b5e9b
--- /dev/null
+++ b/src/Core/Middleware/UpdateLastUserActionTimeMiddleware.php
@@ -0,0 +1,29 @@
+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
new file mode 100644
index 00000000..ef4aa663
--- /dev/null
+++ b/src/Core/Middleware/UserMiddleware.php
@@ -0,0 +1,33 @@
+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
new file mode 100644
index 00000000..41e7e0b6
--- /dev/null
+++ b/src/Core/Middleware/UserPasswordChangeMiddleware.php
@@ -0,0 +1,43 @@
+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
new file mode 100644
index 00000000..f0e7e4df
--- /dev/null
+++ b/src/Core/Middleware/UserPasswordChangeValidatorMiddleware.php
@@ -0,0 +1,35 @@
+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
new file mode 100644
index 00000000..93e7e94f
--- /dev/null
+++ b/src/Core/Middleware/UserPasswordForgottenMiddleware.php
@@ -0,0 +1,40 @@
+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
new file mode 100644
index 00000000..73a07a27
--- /dev/null
+++ b/src/Core/Middleware/UserPasswordForgottenValidator.php
@@ -0,0 +1,35 @@
+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
new file mode 100644
index 00000000..e28ece53
--- /dev/null
+++ b/src/Core/Middleware/UserPasswordVerifyTokenMiddleware.php
@@ -0,0 +1,37 @@
+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
new file mode 100644
index 00000000..a70aa2ba
--- /dev/null
+++ b/src/Core/Middleware/UserRegisterMiddleware.php
@@ -0,0 +1,64 @@
+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
new file mode 100644
index 00000000..ba4e1510
--- /dev/null
+++ b/src/Core/Middleware/UserRegisterValidationMiddleware.php
@@ -0,0 +1,39 @@
+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
deleted file mode 100644
index 6258aa2e..00000000
--- a/src/Core/Repository/AccountAccessAuthRepositoryInterface.php
+++ /dev/null
@@ -1,29 +0,0 @@
-apiAccessConfig['domain']['whitelist'], true);
+ }
+}
diff --git a/src/Core/Service/ApiAccessServiceFactory.php b/src/Core/Service/ApiAccessServiceFactory.php
new file mode 100644
index 00000000..32f7ecb9
--- /dev/null
+++ b/src/Core/Service/ApiAccessServiceFactory.php
@@ -0,0 +1,15 @@
+get('config')['api']['access'];
+
+ return new ApiAccessService($apiAccessConfig);
+ }
+}
diff --git a/src/Core/Service/LoginAuthenticationService.php b/src/Core/Service/LoginAuthenticationService.php
new file mode 100644
index 00000000..6c006da3
--- /dev/null
+++ b/src/Core/Service/LoginAuthenticationService.php
@@ -0,0 +1,19 @@
+password);
+ }
+}
diff --git a/src/Core/Store/AccountAccessAuthStoreInterface.php b/src/Core/Store/AccountAccessAuthStoreInterface.php
deleted file mode 100644
index 73487b96..00000000
--- a/src/Core/Store/AccountAccessAuthStoreInterface.php
+++ /dev/null
@@ -1,29 +0,0 @@
-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
new file mode 100644
index 00000000..fca4e705
--- /dev/null
+++ b/src/Core/Table/UserTable.php
@@ -0,0 +1,93 @@
+ $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
new file mode 100644
index 00000000..fca83751
--- /dev/null
+++ b/src/Core/Token/JwtTokenGeneratorTrait.php
@@ -0,0 +1,26 @@
+ $now,
+ 'exp' => $now + $timeout,
+
+ 'uuid' => $uuid,
+ ],
+ $tokenSecret,
+ $alg
+ );
+ }
+}
diff --git a/src/Core/Token/TokenService.php b/src/Core/Token/TokenService.php
new file mode 100644
index 00000000..0d55c8cf
--- /dev/null
+++ b/src/Core/Token/TokenService.php
@@ -0,0 +1,14 @@
+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
deleted file mode 100644
index 7f7c9ae9..00000000
--- a/src/Core/Type/TypeInterface.php
+++ /dev/null
@@ -1,13 +0,0 @@
- $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
deleted file mode 100644
index 9e838aa7..00000000
--- a/src/Core/Utils/CollectionInterface.php
+++ /dev/null
@@ -1,12 +0,0 @@
-setRequired(true);
diff --git a/src/App/Validator/Input/PasswordInput.php b/src/Core/Validator/Input/PasswordInput.php
similarity index 88%
rename from src/App/Validator/Input/PasswordInput.php
rename to src/Core/Validator/Input/PasswordInput.php
index 02a447d2..0327d695 100644
--- a/src/App/Validator/Input/PasswordInput.php
+++ b/src/Core/Validator/Input/PasswordInput.php
@@ -1,6 +1,6 @@
'UTF-8',
'min' => 6,
- 'max' => 255,
]
);
}
diff --git a/src/Core/Validator/Input/UsernameInput.php b/src/Core/Validator/Input/UsernameInput.php
new file mode 100644
index 00000000..fe2bff05
--- /dev/null
+++ b/src/Core/Validator/Input/UsernameInput.php
@@ -0,0 +1,26 @@
+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
new file mode 100644
index 00000000..f8584b4a
--- /dev/null
+++ b/src/Core/Validator/LoginValidator.php
@@ -0,0 +1,18 @@
+add($this->usernameInput);
+ $this->add($this->passwordInput);
+ }
+}
diff --git a/src/Core/Validator/PasswordForgottenEmailValidator.php b/src/Core/Validator/PasswordForgottenEmailValidator.php
new file mode 100644
index 00000000..d032a063
--- /dev/null
+++ b/src/Core/Validator/PasswordForgottenEmailValidator.php
@@ -0,0 +1,15 @@
+add($this->emailInput);
+ }
+}
diff --git a/src/App/Validator/EMailValidator.php b/src/Core/Validator/RegisterValidator.php
similarity index 66%
rename from src/App/Validator/EMailValidator.php
rename to src/Core/Validator/RegisterValidator.php
index a0b1e404..203ec41a 100644
--- a/src/App/Validator/EMailValidator.php
+++ b/src/Core/Validator/RegisterValidator.php
@@ -1,11 +1,11 @@
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
new file mode 100644
index 00000000..f0bf7e23
--- /dev/null
+++ b/tests/Data/Entity/ParticipantTestEntity.php
@@ -0,0 +1,21 @@
+ 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
new file mode 100644
index 00000000..3490b844
--- /dev/null
+++ b/tests/Data/Entity/ProjectTestEntity.php
@@ -0,0 +1,24 @@
+ 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
new file mode 100644
index 00000000..21f57716
--- /dev/null
+++ b/tests/Data/Entity/RoleTestEntity.php
@@ -0,0 +1,19 @@
+ 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
new file mode 100644
index 00000000..9ea733a0
--- /dev/null
+++ b/tests/Data/Entity/TopicTestEntity.php
@@ -0,0 +1,21 @@
+ 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
new file mode 100644
index 00000000..d5e79eda
--- /dev/null
+++ b/tests/Data/Entity/UserTestEntity.php
@@ -0,0 +1,25 @@
+ 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
new file mode 100644
index 00000000..d2513be7
--- /dev/null
+++ b/tests/Data/TestConstants.php
@@ -0,0 +1,110 @@
+app = new MezzioTestEnvironment($basePath);
+ }
+}
diff --git a/tests/UnitTest/JsonRequestHelper.php b/tests/Functional/JsonRequestHelper.php
similarity index 91%
rename from tests/UnitTest/JsonRequestHelper.php
rename to tests/Functional/JsonRequestHelper.php
index 265a9fc0..0661e7c9 100644
--- a/tests/UnitTest/JsonRequestHelper.php
+++ b/tests/Functional/JsonRequestHelper.php
@@ -1,6 +1,6 @@
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
new file mode 100644
index 00000000..ea361784
--- /dev/null
+++ b/tests/Functional/UserControl/UserMeTest.php
@@ -0,0 +1,54 @@
+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
deleted file mode 100644
index bdbd8b9b..00000000
--- a/tests/FunctionalTest/AbstractFunctional.php
+++ /dev/null
@@ -1,83 +0,0 @@
-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/FunctionalTest/Mock/NullMailerFactory.php b/tests/FunctionalTest/Mock/NullMailerFactory.php
deleted file mode 100644
index d48d61ab..00000000
--- a/tests/FunctionalTest/Mock/NullMailerFactory.php
+++ /dev/null
@@ -1,14 +0,0 @@
-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
deleted file mode 100644
index 1a0e1e82..00000000
--- a/tests/FunctionalTest/Root/Account/AccountActivationHandlerTest.php
+++ /dev/null
@@ -1,119 +0,0 @@
-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
deleted file mode 100644
index edf80a39..00000000
--- a/tests/FunctionalTest/Root/Account/AccountPasswordForgottenHandlerTest.php
+++ /dev/null
@@ -1,61 +0,0 @@
-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
deleted file mode 100644
index 4a14ea84..00000000
--- a/tests/FunctionalTest/Root/Account/AccountPasswordHandlerTest.php
+++ /dev/null
@@ -1,134 +0,0 @@
-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
deleted file mode 100644
index 949af802..00000000
--- a/tests/FunctionalTest/Root/Account/AccountRegisterHandlerTest.php
+++ /dev/null
@@ -1,104 +0,0 @@
-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
deleted file mode 100644
index 973dee06..00000000
--- a/tests/FunctionalTest/Root/Account/AuthenticationHandlerTest.php
+++ /dev/null
@@ -1,180 +0,0 @@
-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
deleted file mode 100644
index 36bb2927..00000000
--- a/tests/FunctionalTest/Root/Account/InvalidEMailAddressProviderTrait.php
+++ /dev/null
@@ -1,54 +0,0 @@
-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
deleted file mode 100644
index 7c861301..00000000
--- a/tests/FunctionalTest/Root/PingHandlerTest.php
+++ /dev/null
@@ -1,29 +0,0 @@
-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
deleted file mode 100644
index aba6b5ec..00000000
--- a/tests/FunctionalTest/bootstrap.php
+++ /dev/null
@@ -1,10 +0,0 @@
-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
new file mode 100644
index 00000000..7b7e1305
--- /dev/null
+++ b/tests/Unit/App/Handler/Topic/TopicCreateHandlerTest.php
@@ -0,0 +1,32 @@
+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
new file mode 100644
index 00000000..f6c950de
--- /dev/null
+++ b/tests/Unit/App/Handler/Topic/TopicListAvailableHandlerTest.php
@@ -0,0 +1,34 @@
+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
new file mode 100644
index 00000000..14cb11dd
--- /dev/null
+++ b/tests/Unit/App/Middleware/Event/EventCreateMiddlewareFactoryTest.php
@@ -0,0 +1,35 @@
+ 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
new file mode 100644
index 00000000..0c8a7652
--- /dev/null
+++ b/tests/Unit/App/Middleware/Event/EventCreateMiddlewareTest.php
@@ -0,0 +1,53 @@
+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
new file mode 100644
index 00000000..11698a75
--- /dev/null
+++ b/tests/Unit/App/Middleware/Event/EventCreateValidationMiddlewareTest.php
@@ -0,0 +1,42 @@
+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
new file mode 100644
index 00000000..1350136e
--- /dev/null
+++ b/tests/Unit/App/Middleware/Event/EventListMiddlewareTest.php
@@ -0,0 +1,60 @@
+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
new file mode 100644
index 00000000..16cc4e92
--- /dev/null
+++ b/tests/Unit/App/Middleware/Event/EventMiddlewareTest.php
@@ -0,0 +1,41 @@
+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
new file mode 100644
index 00000000..48046c92
--- /dev/null
+++ b/tests/Unit/App/Middleware/Event/EventNameMiddlewareTest.php
@@ -0,0 +1,44 @@
+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
new file mode 100644
index 00000000..d62fe159
--- /dev/null
+++ b/tests/Unit/App/Middleware/Topic/TopicCreateSubmitMiddlewareTest.php
@@ -0,0 +1,45 @@
+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
new file mode 100644
index 00000000..e45e2ffc
--- /dev/null
+++ b/tests/Unit/App/Middleware/Topic/TopicCreateValidationMiddlewareTest.php
@@ -0,0 +1,43 @@
+ '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
new file mode 100644
index 00000000..ec67e4f8
--- /dev/null
+++ b/tests/Unit/App/Middleware/Topic/TopicListMiddlewareTest.php
@@ -0,0 +1,20 @@
+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
new file mode 100644
index 00000000..a3e91a2f
--- /dev/null
+++ b/tests/Unit/App/Service/EventServiceFactoryTest.php
@@ -0,0 +1,30 @@
+ 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
new file mode 100644
index 00000000..e2978828
--- /dev/null
+++ b/tests/Unit/App/Service/EventServiceTest.php
@@ -0,0 +1,98 @@
+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
new file mode 100644
index 00000000..6a0cb91d
--- /dev/null
+++ b/tests/Unit/App/Service/ParticipantServiceFactoryTest.php
@@ -0,0 +1,30 @@
+ 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
new file mode 100644
index 00000000..d949b914
--- /dev/null
+++ b/tests/Unit/App/Service/ParticipantServiceTest.php
@@ -0,0 +1,109 @@
+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
new file mode 100644
index 00000000..177101b4
--- /dev/null
+++ b/tests/Unit/App/Service/ProjectServiceFactoryTest.php
@@ -0,0 +1,30 @@
+ 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
new file mode 100644
index 00000000..62608ee9
--- /dev/null
+++ b/tests/Unit/App/Service/ProjectServiceTest.php
@@ -0,0 +1,51 @@
+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
new file mode 100644
index 00000000..eacd6470
--- /dev/null
+++ b/tests/Unit/App/Service/TopicPoolServiceTest.php
@@ -0,0 +1,113 @@
+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
new file mode 100644
index 00000000..e121aee6
--- /dev/null
+++ b/tests/Unit/App/Table/EventTableTest.php
@@ -0,0 +1,137 @@
+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
new file mode 100644
index 00000000..2f708567
--- /dev/null
+++ b/tests/Unit/App/Table/ParticipantTableTest.php
@@ -0,0 +1,125 @@
+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
new file mode 100644
index 00000000..25cd3981
--- /dev/null
+++ b/tests/Unit/App/Table/ProjectTableTest.php
@@ -0,0 +1,47 @@
+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
new file mode 100644
index 00000000..800af161
--- /dev/null
+++ b/tests/Unit/App/Table/TopicPoolTableTest.php
@@ -0,0 +1,108 @@
+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/UnitTest/CoreTest/Factory/DatabaseFactoryTest.php b/tests/Unit/Core/Factory/DatabaseFactoryTest.php
similarity index 50%
rename from tests/UnitTest/CoreTest/Factory/DatabaseFactoryTest.php
rename to tests/Unit/Core/Factory/DatabaseFactoryTest.php
index b0097fc4..54c9a3f5 100644
--- a/tests/UnitTest/CoreTest/Factory/DatabaseFactoryTest.php
+++ b/tests/Unit/Core/Factory/DatabaseFactoryTest.php
@@ -1,22 +1,18 @@
expectException(PDOException::class);
@@ -29,15 +25,31 @@ 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);
- $this->assertInstanceOf(PDO::class, $pdo);
+ self::assertInstanceOf(PDO::class, $pdo);
+ }
+
+ public function tearDown(): void
+ {
+ system('rm ' . dirname(__FILE__) . '/../../../../database/database.sqlite');
}
}
diff --git a/tests/Unit/Core/Factory/MailFactoryTest.php b/tests/Unit/Core/Factory/MailFactoryTest.php
new file mode 100644
index 00000000..d90bb92e
--- /dev/null
+++ b/tests/Unit/Core/Factory/MailFactoryTest.php
@@ -0,0 +1,28 @@
+ [
+ '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/UnitTest/CoreTest/Factory/QueryFactoryTest.php b/tests/Unit/Core/Factory/QueryFactoryTest.php
similarity index 52%
rename from tests/UnitTest/CoreTest/Factory/QueryFactoryTest.php
rename to tests/Unit/Core/Factory/QueryFactoryTest.php
index d42a487b..6e6971d0 100644
--- a/tests/UnitTest/CoreTest/Factory/QueryFactoryTest.php
+++ b/tests/Unit/Core/Factory/QueryFactoryTest.php
@@ -1,22 +1,16 @@
assertInstanceOf(Query::class, $query);
+ self::assertInstanceOf(Query::class, $query);
}
}
diff --git a/tests/Unit/Core/Factory/UuidFactoryTest.php b/tests/Unit/Core/Factory/UuidFactoryTest.php
new file mode 100644
index 00000000..6075280f
--- /dev/null
+++ b/tests/Unit/Core/Factory/UuidFactoryTest.php
@@ -0,0 +1,20 @@
+request = new MockServerRequest();
-
+ $this->hydrator = new ReflectionHydrator();
parent::setUp();
}
}
diff --git a/tests/Unit/Core/Handler/LoginHandlerTest.php b/tests/Unit/Core/Handler/LoginHandlerTest.php
new file mode 100644
index 00000000..f2b91f8c
--- /dev/null
+++ b/tests/Unit/Core/Handler/LoginHandlerTest.php
@@ -0,0 +1,32 @@
+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
new file mode 100644
index 00000000..e3e2a999
--- /dev/null
+++ b/tests/Unit/Core/Hydrator/ClassMethodsHydratorFactoryTest.php
@@ -0,0 +1,18 @@
+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
new file mode 100644
index 00000000..a6ea4b66
--- /dev/null
+++ b/tests/Unit/Core/Hydrator/ReflectionHydratorTest.php
@@ -0,0 +1,49 @@
+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/UnitTest/AppTest/Middleware/AbstractTestMiddleware.php b/tests/Unit/Core/Middleware/AbstractMiddleware.php
similarity index 59%
rename from tests/UnitTest/AppTest/Middleware/AbstractTestMiddleware.php
rename to tests/Unit/Core/Middleware/AbstractMiddleware.php
index cdd34f8b..91735e95 100644
--- a/tests/UnitTest/AppTest/Middleware/AbstractTestMiddleware.php
+++ b/tests/Unit/Core/Middleware/AbstractMiddleware.php
@@ -1,27 +1,25 @@
request = new MockServerRequest();
$this->handler = new MockRequestHandler();
+ $this->hydrator = new ReflectionHydrator();
parent::setUp();
}
diff --git a/tests/Unit/Core/Middleware/ApiAccessMiddlewareTest.php b/tests/Unit/Core/Middleware/ApiAccessMiddlewareTest.php
new file mode 100644
index 00000000..2a01e12f
--- /dev/null
+++ b/tests/Unit/Core/Middleware/ApiAccessMiddlewareTest.php
@@ -0,0 +1,57 @@
+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
new file mode 100644
index 00000000..62b5d97f
--- /dev/null
+++ b/tests/Unit/Core/Middleware/UpdateLastUserActionTimeMiddlewareTest.php
@@ -0,0 +1,36 @@
+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
new file mode 100644
index 00000000..04379e44
--- /dev/null
+++ b/tests/Unit/Core/Middleware/UserMiddlewareTest.php
@@ -0,0 +1,48 @@
+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
new file mode 100644
index 00000000..0f725b8d
--- /dev/null
+++ b/tests/Unit/Core/Service/AbstractService.php
@@ -0,0 +1,33 @@
+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
new file mode 100644
index 00000000..578c66be
--- /dev/null
+++ b/tests/Unit/Core/Service/ApiAccessServiceFactoryTest.php
@@ -0,0 +1,37 @@
+ [
+ '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
new file mode 100644
index 00000000..a92ed312
--- /dev/null
+++ b/tests/Unit/Core/Service/ApiAccessServiceTest.php
@@ -0,0 +1,38 @@
+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
new file mode 100644
index 00000000..b2603e1a
--- /dev/null
+++ b/tests/Unit/Core/Service/TokenServiceTest.php
@@ -0,0 +1,18 @@
+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
new file mode 100644
index 00000000..70381c4f
--- /dev/null
+++ b/tests/Unit/Core/Service/UserServiceFactoryTest.php
@@ -0,0 +1,33 @@
+ 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
new file mode 100644
index 00000000..f564953c
--- /dev/null
+++ b/tests/Unit/Core/Service/UserServiceTest.php
@@ -0,0 +1,134 @@
+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
new file mode 100644
index 00000000..1cf05318
--- /dev/null
+++ b/tests/Unit/Core/Table/AbstractTable.php
@@ -0,0 +1,39 @@
+ 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
new file mode 100644
index 00000000..6a6d5fd7
--- /dev/null
+++ b/tests/Unit/Core/Table/UserTableTest.php
@@ -0,0 +1,158 @@
+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/UnitTest/Mock/Database/MockDelete.php b/tests/Unit/Mock/Database/MockDelete.php
similarity index 62%
rename from tests/UnitTest/Mock/Database/MockDelete.php
rename to tests/Unit/Mock/Database/MockDelete.php
index e8c9188e..b903e5cb 100644
--- a/tests/UnitTest/Mock/Database/MockDelete.php
+++ b/tests/Unit/Mock/Database/MockDelete.php
@@ -1,9 +1,10 @@
true,
+ 'Event', 'MockEvent' => $this->handleEvent($where, $value),
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/Unit/Mock/Database/MockInsert.php b/tests/Unit/Mock/Database/MockInsert.php
new file mode 100644
index 00000000..c7409a2b
--- /dev/null
+++ b/tests/Unit/Mock/Database/MockInsert.php
@@ -0,0 +1,58 @@
+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/UnitTest/Mock/Database/MockPDO.php b/tests/Unit/Mock/Database/MockPDO.php
similarity index 88%
rename from tests/UnitTest/Mock/Database/MockPDO.php
rename to tests/Unit/Mock/Database/MockPDO.php
index 51c8ad13..80a828fc 100644
--- a/tests/UnitTest/Mock/Database/MockPDO.php
+++ b/tests/Unit/Mock/Database/MockPDO.php
@@ -1,6 +1,6 @@
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
new file mode 100644
index 00000000..7936b6c9
--- /dev/null
+++ b/tests/Unit/Mock/Database/MockSelectForFetchAll.php
@@ -0,0 +1,109 @@
+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
new file mode 100644
index 00000000..5824db9f
--- /dev/null
+++ b/tests/Unit/Mock/Database/MockUpdate.php
@@ -0,0 +1,46 @@
+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
new file mode 100644
index 00000000..0826c8ec
--- /dev/null
+++ b/tests/Unit/Mock/Database/MockUpdateForNotUpdate.php
@@ -0,0 +1,46 @@
+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/FunctionalTest/Mock/NullMailer.php b/tests/Unit/Mock/Mailer/MockMailer.php
similarity index 68%
rename from tests/FunctionalTest/Mock/NullMailer.php
rename to tests/Unit/Mock/Mailer/MockMailer.php
index 5f05e41f..e069d46c 100644
--- a/tests/FunctionalTest/Mock/NullMailer.php
+++ b/tests/Unit/Mock/Mailer/MockMailer.php
@@ -1,15 +1,15 @@
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
new file mode 100644
index 00000000..f599f871
--- /dev/null
+++ b/tests/Unit/Mock/Service/MockApiAccessService.php
@@ -0,0 +1,18 @@
+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
new file mode 100644
index 00000000..c1026981
--- /dev/null
+++ b/tests/Unit/Mock/Service/MockTopicCreateEMailService.php
@@ -0,0 +1,14 @@
+with(lastActionAt: new DateTimeImmutable(TestConstants::TIME));
+ }
+}
diff --git a/tests/Unit/Mock/Table/MockEventTable.php b/tests/Unit/Mock/Table/MockEventTable.php
new file mode 100644
index 00000000..9e5c739e
--- /dev/null
+++ b/tests/Unit/Mock/Table/MockEventTable.php
@@ -0,0 +1,44 @@
+ [
+ '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
new file mode 100644
index 00000000..fefab7f8
--- /dev/null
+++ b/tests/Unit/Mock/Table/MockParticipantTable.php
@@ -0,0 +1,45 @@
+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
new file mode 100644
index 00000000..8bde0afd
--- /dev/null
+++ b/tests/Unit/Mock/Table/MockProjectTable.php
@@ -0,0 +1,28 @@
+ $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
new file mode 100644
index 00000000..4f567907
--- /dev/null
+++ b/tests/Unit/Mock/Table/MockTopicPoolTable.php
@@ -0,0 +1,46 @@
+ $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
new file mode 100644
index 00000000..15f26e44
--- /dev/null
+++ b/tests/Unit/Mock/Table/MockUserTable.php
@@ -0,0 +1,50 @@
+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
new file mode 100644
index 00000000..6599f0d0
--- /dev/null
+++ b/tests/Unit/Mock/Validator/MockEventCreateValidator.php
@@ -0,0 +1,43 @@
+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
new file mode 100644
index 00000000..9a2c70d4
--- /dev/null
+++ b/tests/Unit/Mock/Validator/MockTopicCreateValidator.php
@@ -0,0 +1,20 @@
+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
deleted file mode 100644
index ba820e46..00000000
--- a/tests/UnitTest/AppTest/Handler/PingHandlerTest.php
+++ /dev/null
@@ -1,29 +0,0 @@
-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
deleted file mode 100644
index 5675db67..00000000
--- a/tests/UnitTest/AppTest/Hydrator/AccountAccessAuthHydratorTest.php
+++ /dev/null
@@ -1,55 +0,0 @@
-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
deleted file mode 100644
index 1b34dfea..00000000
--- a/tests/UnitTest/AppTest/Hydrator/AccountHydratorTest.php
+++ /dev/null
@@ -1,66 +0,0 @@
-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/UnitTest/AppTest/Middleware/AccountAccessAuthPersistMiddlewareTest.php b/tests/UnitTest/AppTest/Middleware/AccountAccessAuthPersistMiddlewareTest.php
deleted file mode 100644
index d51531b2..00000000
--- a/tests/UnitTest/AppTest/Middleware/AccountAccessAuthPersistMiddlewareTest.php
+++ /dev/null
@@ -1,108 +0,0 @@
-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
deleted file mode 100644
index a47c317c..00000000
--- a/tests/UnitTest/AppTest/Middleware/AccountAuthenticationMiddlewareTest.php
+++ /dev/null
@@ -1,107 +0,0 @@
-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
deleted file mode 100644
index 2ea196ca..00000000
--- a/tests/UnitTest/AppTest/Middleware/AuthenticationConditionsMiddlewareTest.php
+++ /dev/null
@@ -1,42 +0,0 @@
-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
deleted file mode 100644
index 8c7e8a12..00000000
--- a/tests/UnitTest/AppTest/Middleware/AuthenticationMiddlewareTest.php
+++ /dev/null
@@ -1,65 +0,0 @@
-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
deleted file mode 100644
index fc230a00..00000000
--- a/tests/UnitTest/AppTest/Middleware/AuthenticationValidationMiddlewareTest.php
+++ /dev/null
@@ -1,33 +0,0 @@
-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
deleted file mode 100644
index 5c35eb83..00000000
--- a/tests/UnitTest/AppTest/Middleware/ClientIdentificationMiddlewareTest.php
+++ /dev/null
@@ -1,36 +0,0 @@
-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
deleted file mode 100644
index c9230203..00000000
--- a/tests/UnitTest/AppTest/Middleware/GenerateAccessTokenMiddlewareTest.php
+++ /dev/null
@@ -1,34 +0,0 @@
-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
deleted file mode 100644
index 94609118..00000000
--- a/tests/UnitTest/AppTest/Middleware/GenerateRefreshTokenMiddlewareTest.php
+++ /dev/null
@@ -1,39 +0,0 @@
-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
deleted file mode 100644
index a2d503b3..00000000
--- a/tests/UnitTest/AppTest/Repository/AccountAccessAuthRepositoryTest.php
+++ /dev/null
@@ -1,194 +0,0 @@
-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
deleted file mode 100644
index a1047935..00000000
--- a/tests/UnitTest/AppTest/Repository/AccountRepositoryTest.php
+++ /dev/null
@@ -1,161 +0,0 @@
-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
deleted file mode 100644
index 4a8d0ca0..00000000
--- a/tests/UnitTest/AppTest/Service/AccessTokenServiceTest.php
+++ /dev/null
@@ -1,48 +0,0 @@
-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
deleted file mode 100644
index ebc0eb06..00000000
--- a/tests/UnitTest/AppTest/Service/AuthenticationServiceTest.php
+++ /dev/null
@@ -1,31 +0,0 @@
-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
deleted file mode 100644
index 568af821..00000000
--- a/tests/UnitTest/AppTest/Service/RefreshTokenServiceTest.php
+++ /dev/null
@@ -1,51 +0,0 @@
-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
deleted file mode 100644
index c8ad6c3a..00000000
--- a/tests/UnitTest/AppTest/Table/AccountAccessAuthTableTest.php
+++ /dev/null
@@ -1,226 +0,0 @@
-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
deleted file mode 100644
index 30d74c66..00000000
--- a/tests/UnitTest/AppTest/Table/AccountTableTest.php
+++ /dev/null
@@ -1,189 +0,0 @@
-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/UnitTest/GameTest/.gitkeep b/tests/UnitTest/GameTest/.gitkeep
deleted file mode 100644
index e69de29b..00000000
diff --git a/tests/UnitTest/Mock/Constants/Account.php b/tests/UnitTest/Mock/Constants/Account.php
deleted file mode 100644
index e3242a7a..00000000
--- a/tests/UnitTest/Mock/Constants/Account.php
+++ /dev/null
@@ -1,60 +0,0 @@
- 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
deleted file mode 100644
index 5bfa113b..00000000
--- a/tests/UnitTest/Mock/Constants/AccountAccessAuth.php
+++ /dev/null
@@ -1,54 +0,0 @@
- 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
deleted file mode 100644
index 3924a447..00000000
--- a/tests/UnitTest/Mock/Constants/Token.php
+++ /dev/null
@@ -1,21 +0,0 @@
- 'token secret',
- 'algorithmus' => 'HS512',
- 'duration' => 60 * 60 * 24 * 7 * 12,
- 'iss' => 'Issuer of the token',
- 'aud' => 'recipients of the token',
- ];
- }
-}
diff --git a/tests/UnitTest/Mock/Database/MockDeleteFailed.php b/tests/UnitTest/Mock/Database/MockDeleteFailed.php
deleted file mode 100644
index e72df7a3..00000000
--- a/tests/UnitTest/Mock/Database/MockDeleteFailed.php
+++ /dev/null
@@ -1,24 +0,0 @@
-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
deleted file mode 100644
index c3e9b2ae..00000000
--- a/tests/UnitTest/Mock/Database/MockInsert.php
+++ /dev/null
@@ -1,27 +0,0 @@
-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
deleted file mode 100644
index f64f2fea..00000000
--- a/tests/UnitTest/Mock/Database/MockInsertFailed.php
+++ /dev/null
@@ -1,25 +0,0 @@
-handle($this->statements['INSERT INTO'], $this->statements['VALUES']);
- }
-
- private function handle(string $table, array $values): bool
- {
- throw new PDOException();
- }
-}
diff --git a/tests/UnitTest/Mock/Database/MockSelect.php b/tests/UnitTest/Mock/Database/MockSelect.php
deleted file mode 100644
index 62794cc8..00000000
--- a/tests/UnitTest/Mock/Database/MockSelect.php
+++ /dev/null
@@ -1,96 +0,0 @@
-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
deleted file mode 100644
index 860c6e17..00000000
--- a/tests/UnitTest/Mock/Database/MockSelectFailed.php
+++ /dev/null
@@ -1,36 +0,0 @@
-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
deleted file mode 100644
index 0f13c7ef..00000000
--- a/tests/UnitTest/Mock/Database/MockUpdate.php
+++ /dev/null
@@ -1,22 +0,0 @@
-statements['UPDATE']) {
- 'Account', 'AccountAccessAuth' => true,
- default => false
- };
- }
-}
diff --git a/tests/UnitTest/Mock/Database/MockUpdateFailed.php b/tests/UnitTest/Mock/Database/MockUpdateFailed.php
deleted file mode 100644
index b755be43..00000000
--- a/tests/UnitTest/Mock/Database/MockUpdateFailed.php
+++ /dev/null
@@ -1,19 +0,0 @@
-getAttribute(AccountInterface::AUTHENTICATED);
- $response = new MockResponse();
-
- if ($account instanceof AccountInterface) {
- return $response->withHeader('Authorization', 'true');
- }
-
- return $response;
- }
-}
diff --git a/tests/UnitTest/Mock/MockResponse.php b/tests/UnitTest/Mock/MockResponse.php
deleted file mode 100644
index 3c6aaa10..00000000
--- a/tests/UnitTest/Mock/MockResponse.php
+++ /dev/null
@@ -1,84 +0,0 @@
-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
deleted file mode 100644
index 0f3c4122..00000000
--- a/tests/UnitTest/Mock/MockServerRequest.php
+++ /dev/null
@@ -1,192 +0,0 @@
-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
deleted file mode 100644
index 8cbcaa52..00000000
--- a/tests/UnitTest/Mock/Repository/MockAccountAccessAuthRepository.php
+++ /dev/null
@@ -1,14 +0,0 @@
- $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
deleted file mode 100644
index dc442e4b..00000000
--- a/tests/UnitTest/Mock/Service/MockAccessTokenServiceWithoutDuration.php
+++ /dev/null
@@ -1,35 +0,0 @@
- $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
deleted file mode 100644
index ed819dba..00000000
--- a/tests/UnitTest/Mock/Service/MockAuthenticationService.php
+++ /dev/null
@@ -1,14 +0,0 @@
-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
deleted file mode 100644
index d184590d..00000000
--- a/tests/UnitTest/Mock/Table/MockAccountAccessAuthTableFailed.php
+++ /dev/null
@@ -1,25 +0,0 @@
-hydrator->hydrateCollection([]);
- }
-}
diff --git a/tests/UnitTest/Mock/Table/MockAccountTable.php b/tests/UnitTest/Mock/Table/MockAccountTable.php
deleted file mode 100644
index 8b9e6a63..00000000
--- a/tests/UnitTest/Mock/Table/MockAccountTable.php
+++ /dev/null
@@ -1,84 +0,0 @@
-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
deleted file mode 100644
index 8edb8323..00000000
--- a/tests/UnitTest/Mock/Table/MockAccountTableAccountAuthenticationMiddlewareInvalidToken.php
+++ /dev/null
@@ -1,84 +0,0 @@
-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
deleted file mode 100644
index c5b78ad8..00000000
--- a/tests/UnitTest/Mock/Table/MockAccountTableFailed.php
+++ /dev/null
@@ -1,26 +0,0 @@
-hydrator->hydrateCollection([]);
- }
-}
diff --git a/tests/UnitTest/Mock/Validator/MockAuthenticationValidator.php b/tests/UnitTest/Mock/Validator/MockAuthenticationValidator.php
deleted file mode 100644
index c5b696ff..00000000
--- a/tests/UnitTest/Mock/Validator/MockAuthenticationValidator.php
+++ /dev/null
@@ -1,20 +0,0 @@
- [
+ '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
new file mode 100644
index 00000000..e407b412
--- /dev/null
+++ b/tests/config/autoload/dependencies.testing.local.php
@@ -0,0 +1,22 @@
+ [
+ '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
new file mode 100644
index 00000000..4e474e4e
--- /dev/null
+++ b/tests/config/autoload/token.testing.local.php
@@ -0,0 +1,18 @@
+ [
+ '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
new file mode 100644
index 00000000..59e06248
--- /dev/null
+++ b/tests/config/config.php
@@ -0,0 +1,24 @@
+getMergedConfig();
diff --git a/tests/config/container.php b/tests/config/container.php
new file mode 100644
index 00000000..3bae2980
--- /dev/null
+++ b/tests/config/container.php
@@ -0,0 +1,14 @@
+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
new file mode 100644
index 00000000..09a31d37
--- /dev/null
+++ b/tests/config/routes.php
@@ -0,0 +1,19 @@
+get('/api/ping[/]', PingHandler::class, PingHandler::class);
+
+ $app->get(
+ '/api/user/me[/]',
+ [
+ ApiMeHandler::class,
+ ],
+ ApiMeHandler::class
+ );
+};