From 5706b7910d8f6277b0ff6b9bdd01ca10eeea0be0 Mon Sep 17 00:00:00 2001 From: Volodymyr Minchenko Date: Thu, 6 Jun 2024 11:04:28 +0300 Subject: [PATCH 01/28] thjs-122: * prepare packages/shared workspace --- {shared => packages/shared}/.eslintrc.yml | 0 {shared => packages/shared}/package.json | 7 ++-- packages/shared/src/index.ts | 6 ++++ .../shared/src/libs/enums/api-path.enum.ts | 5 +++ .../shared}/src/libs/enums/app-environment.ts | 0 .../shared}/src/libs/enums/enums.ts | 2 +- .../src/libs/enums/exception-message.enum.ts | 0 .../src/libs/enums/exception-name.enum.ts | 0 .../shared}/src/libs/exceptions/exceptions.ts | 0 .../http-error/http-error.exception.ts | 2 +- .../invalid-credentials-error.exception.ts | 0 .../shared}/src/libs/helpers/date/date.ts | 0 .../src/libs/helpers/date/dayjs/dayjs.ts | 0 .../helpers/date/get-diff/get-diff.helper.ts | 0 .../get-from-now-time.helper.ts | 0 .../shared}/src/libs/helpers/helpers.ts | 0 .../shared/src/libs/modules}/config/config.ts | 0 .../config/libs/types/configurable.type.ts | 0 .../libs/modules}/config/libs/types/types.ts | 0 .../shared/src/libs/modules}/http/http.ts | 0 .../libs/modules}/http/libs/enums/enums.ts | 0 .../http/libs/enums/http-code.enum.ts | 0 .../http/libs/enums/http-header.enum.ts | 0 .../http/libs/enums/http-method.enum.ts | 0 .../shared}/src/libs/types/generic/generic.ts | 0 .../src/libs/types/generic/value-of.type.ts | 0 .../shared}/src/libs/types/types.ts | 0 .../validation/validation-schema.type.ts | 0 .../src/libs/types/validation/validation.ts | 0 packages/shared/src/modules/auth/auth.ts | 2 ++ .../auth/libs/enums/auth-api-path.enum.ts | 5 +++ .../src/modules}/auth/libs/enums/enums.ts | 0 .../registration.validation-schema.ts | 0 .../validation-schemas/validation-schemas.ts | 1 - .../src/modules}/user/libs/enums/enums.ts | 1 - .../user/libs/enums/user-payload-key.enum.ts | 0 .../enums/user-validation-message.enum.ts | 0 .../libs/enums/user-validation-rule.enum.ts | 0 .../src/modules/user/libs/types/types.ts | 3 ++ .../types/user-register-request-dto.type.ts | 0 .../types/user-register-response-dto.type.ts | 5 +++ .../src/modules}/user/libs/types/user.type.ts | 0 .../shared/src/modules}/user/user.ts | 8 +---- packages/shared/tsconfig.json | 12 +++++++ shared/src/libs/enums/api-path.enum.ts | 10 ------ .../libs/packages/socket/libs/enums/enums.ts | 3 -- .../enums/notification-socket-event.enum.ts | 6 ---- .../socket/libs/enums/socket-event.enum.ts | 7 ---- .../libs/enums/socket-namespace.enum.ts | 5 --- shared/src/libs/packages/socket/socket.ts | 5 --- shared/src/packages/auth/auth.ts | 5 --- .../auth/libs/enums/auth-api-path.enum.ts | 7 ---- .../login.validation-schema.ts | 32 ------------------- shared/src/packages/comment/comment.ts | 7 ---- .../libs/enums/comment-payload-key.enum.ts | 5 --- .../libs/enums/comments-api-path.enum.ts | 7 ---- .../src/packages/comment/libs/enums/enums.ts | 2 -- ...comment-with-user-nested-relations.type.ts | 8 ----- .../comment/libs/types/comment.type.ts | 10 ------ .../types/create-comment-request-dto.type.ts | 5 --- .../get-comment-by-id-response-dto.type.ts | 5 --- .../src/packages/comment/libs/types/types.ts | 4 --- shared/src/packages/image/image.ts | 2 -- shared/src/packages/image/libs/enums/enums.ts | 2 -- .../libs/enums/image-payload-key.enum.ts | 5 --- .../image/libs/enums/images-api-path.enum.ts | 5 --- .../packages/image/libs/types/image.type.ts | 8 ----- shared/src/packages/image/libs/types/types.ts | 2 -- .../types/upload-image-response-dto.type.ts | 5 --- .../src/packages/password/libs/enums/enums.ts | 1 - .../libs/enums/password-api-path.enum.ts | 6 ---- shared/src/packages/password/password.ts | 1 - shared/src/packages/post/libs/enums/enums.ts | 3 -- .../post/libs/enums/filter-user-mode.enum.ts | 8 ----- .../post/libs/enums/post-payload-key.enum.ts | 5 --- .../post/libs/enums/posts-api-path.enum.ts | 7 ---- .../create-post-reaction-request-dto.type.ts | 5 --- .../create-post-reaction-response-dto.type.ts | 7 ---- .../types/create-post-request-dto.type.ts | 5 --- .../types/get-post-by-id-response-dto.type.ts | 6 ---- .../get-posts-by-filter-request-dto.type.ts | 5 --- .../get-posts-by-filter-response-dto.type.ts | 5 --- .../post/libs/types/post-filter.type.ts | 7 ---- .../post-reaction-with-post-relation.type.ts | 7 ---- .../post/libs/types/post-reaction.type.ts | 10 ------ ...e-user-nested-relations-with-count.type.ts | 9 ------ ...e-user-nested-relations-with-count.type.ts | 14 -------- .../src/packages/post/libs/types/post.type.ts | 10 ------ shared/src/packages/post/libs/types/types.ts | 12 ------- shared/src/packages/post/post.ts | 19 ----------- .../user/libs/enums/users-api-path.enum.ts | 5 --- shared/src/packages/user/libs/types/types.ts | 8 ----- .../libs/types/user-auth-response.type.ts | 5 --- .../libs/types/user-login-request-dto.type.ts | 6 ---- .../types/user-login-response-dto.type.ts | 8 ----- .../types/user-register-response-dto.type.ts | 5 --- .../types/user-with-image-relation.type.ts | 9 ------ .../libs/types/user-with-password.type.ts | 5 --- shared/tsconfig.json | 21 ------------ 99 files changed, 46 insertions(+), 399 deletions(-) rename {shared => packages/shared}/.eslintrc.yml (100%) rename {shared => packages/shared}/package.json (58%) create mode 100644 packages/shared/src/index.ts create mode 100644 packages/shared/src/libs/enums/api-path.enum.ts rename {shared => packages/shared}/src/libs/enums/app-environment.ts (100%) rename {shared => packages/shared}/src/libs/enums/enums.ts (79%) rename {shared => packages/shared}/src/libs/enums/exception-message.enum.ts (100%) rename {shared => packages/shared}/src/libs/enums/exception-name.enum.ts (100%) rename {shared => packages/shared}/src/libs/exceptions/exceptions.ts (100%) rename {shared => packages/shared}/src/libs/exceptions/http-error/http-error.exception.ts (90%) rename {shared => packages/shared}/src/libs/exceptions/invalid-credentials-error/invalid-credentials-error.exception.ts (100%) rename {shared => packages/shared}/src/libs/helpers/date/date.ts (100%) rename {shared => packages/shared}/src/libs/helpers/date/dayjs/dayjs.ts (100%) rename {shared => packages/shared}/src/libs/helpers/date/get-diff/get-diff.helper.ts (100%) rename {shared => packages/shared}/src/libs/helpers/date/get-from-now-time/get-from-now-time.helper.ts (100%) rename {shared => packages/shared}/src/libs/helpers/helpers.ts (100%) rename {shared/src/libs/packages => packages/shared/src/libs/modules}/config/config.ts (100%) rename {shared/src/libs/packages => packages/shared/src/libs/modules}/config/libs/types/configurable.type.ts (100%) rename {shared/src/libs/packages => packages/shared/src/libs/modules}/config/libs/types/types.ts (100%) rename {shared/src/libs/packages => packages/shared/src/libs/modules}/http/http.ts (100%) rename {shared/src/libs/packages => packages/shared/src/libs/modules}/http/libs/enums/enums.ts (100%) rename {shared/src/libs/packages => packages/shared/src/libs/modules}/http/libs/enums/http-code.enum.ts (100%) rename {shared/src/libs/packages => packages/shared/src/libs/modules}/http/libs/enums/http-header.enum.ts (100%) rename {shared/src/libs/packages => packages/shared/src/libs/modules}/http/libs/enums/http-method.enum.ts (100%) rename {shared => packages/shared}/src/libs/types/generic/generic.ts (100%) rename {shared => packages/shared}/src/libs/types/generic/value-of.type.ts (100%) rename {shared => packages/shared}/src/libs/types/types.ts (100%) rename {shared => packages/shared}/src/libs/types/validation/validation-schema.type.ts (100%) rename {shared => packages/shared}/src/libs/types/validation/validation.ts (100%) create mode 100644 packages/shared/src/modules/auth/auth.ts create mode 100644 packages/shared/src/modules/auth/libs/enums/auth-api-path.enum.ts rename {shared/src/packages => packages/shared/src/modules}/auth/libs/enums/enums.ts (100%) rename {shared/src/packages => packages/shared/src/modules}/auth/libs/validation-schemas/registration.validation-schema.ts (100%) rename {shared/src/packages => packages/shared/src/modules}/auth/libs/validation-schemas/validation-schemas.ts (55%) rename {shared/src/packages => packages/shared/src/modules}/user/libs/enums/enums.ts (78%) rename {shared/src/packages => packages/shared/src/modules}/user/libs/enums/user-payload-key.enum.ts (100%) rename {shared/src/packages => packages/shared/src/modules}/user/libs/enums/user-validation-message.enum.ts (100%) rename {shared/src/packages => packages/shared/src/modules}/user/libs/enums/user-validation-rule.enum.ts (100%) create mode 100644 packages/shared/src/modules/user/libs/types/types.ts rename {shared/src/packages => packages/shared/src/modules}/user/libs/types/user-register-request-dto.type.ts (100%) create mode 100644 packages/shared/src/modules/user/libs/types/user-register-response-dto.type.ts rename {shared/src/packages => packages/shared/src/modules}/user/libs/types/user.type.ts (100%) rename {shared/src/packages => packages/shared/src/modules}/user/user.ts (50%) create mode 100644 packages/shared/tsconfig.json delete mode 100644 shared/src/libs/enums/api-path.enum.ts delete mode 100644 shared/src/libs/packages/socket/libs/enums/enums.ts delete mode 100644 shared/src/libs/packages/socket/libs/enums/notification-socket-event.enum.ts delete mode 100644 shared/src/libs/packages/socket/libs/enums/socket-event.enum.ts delete mode 100644 shared/src/libs/packages/socket/libs/enums/socket-namespace.enum.ts delete mode 100644 shared/src/libs/packages/socket/socket.ts delete mode 100644 shared/src/packages/auth/auth.ts delete mode 100644 shared/src/packages/auth/libs/enums/auth-api-path.enum.ts delete mode 100644 shared/src/packages/auth/libs/validation-schemas/login.validation-schema.ts delete mode 100644 shared/src/packages/comment/comment.ts delete mode 100644 shared/src/packages/comment/libs/enums/comment-payload-key.enum.ts delete mode 100644 shared/src/packages/comment/libs/enums/comments-api-path.enum.ts delete mode 100644 shared/src/packages/comment/libs/enums/enums.ts delete mode 100644 shared/src/packages/comment/libs/types/comment-with-user-nested-relations.type.ts delete mode 100644 shared/src/packages/comment/libs/types/comment.type.ts delete mode 100644 shared/src/packages/comment/libs/types/create-comment-request-dto.type.ts delete mode 100644 shared/src/packages/comment/libs/types/get-comment-by-id-response-dto.type.ts delete mode 100644 shared/src/packages/comment/libs/types/types.ts delete mode 100644 shared/src/packages/image/image.ts delete mode 100644 shared/src/packages/image/libs/enums/enums.ts delete mode 100644 shared/src/packages/image/libs/enums/image-payload-key.enum.ts delete mode 100644 shared/src/packages/image/libs/enums/images-api-path.enum.ts delete mode 100644 shared/src/packages/image/libs/types/image.type.ts delete mode 100644 shared/src/packages/image/libs/types/types.ts delete mode 100644 shared/src/packages/image/libs/types/upload-image-response-dto.type.ts delete mode 100644 shared/src/packages/password/libs/enums/enums.ts delete mode 100644 shared/src/packages/password/libs/enums/password-api-path.enum.ts delete mode 100644 shared/src/packages/password/password.ts delete mode 100644 shared/src/packages/post/libs/enums/enums.ts delete mode 100644 shared/src/packages/post/libs/enums/filter-user-mode.enum.ts delete mode 100644 shared/src/packages/post/libs/enums/post-payload-key.enum.ts delete mode 100644 shared/src/packages/post/libs/enums/posts-api-path.enum.ts delete mode 100644 shared/src/packages/post/libs/types/create-post-reaction-request-dto.type.ts delete mode 100644 shared/src/packages/post/libs/types/create-post-reaction-response-dto.type.ts delete mode 100644 shared/src/packages/post/libs/types/create-post-request-dto.type.ts delete mode 100644 shared/src/packages/post/libs/types/get-post-by-id-response-dto.type.ts delete mode 100644 shared/src/packages/post/libs/types/get-posts-by-filter-request-dto.type.ts delete mode 100644 shared/src/packages/post/libs/types/get-posts-by-filter-response-dto.type.ts delete mode 100644 shared/src/packages/post/libs/types/post-filter.type.ts delete mode 100644 shared/src/packages/post/libs/types/post-reaction-with-post-relation.type.ts delete mode 100644 shared/src/packages/post/libs/types/post-reaction.type.ts delete mode 100644 shared/src/packages/post/libs/types/post-with-comment-image-user-nested-relations-with-count.type.ts delete mode 100644 shared/src/packages/post/libs/types/post-with-image-user-nested-relations-with-count.type.ts delete mode 100644 shared/src/packages/post/libs/types/post.type.ts delete mode 100644 shared/src/packages/post/libs/types/types.ts delete mode 100644 shared/src/packages/post/post.ts delete mode 100644 shared/src/packages/user/libs/enums/users-api-path.enum.ts delete mode 100644 shared/src/packages/user/libs/types/types.ts delete mode 100644 shared/src/packages/user/libs/types/user-auth-response.type.ts delete mode 100644 shared/src/packages/user/libs/types/user-login-request-dto.type.ts delete mode 100644 shared/src/packages/user/libs/types/user-login-response-dto.type.ts delete mode 100644 shared/src/packages/user/libs/types/user-register-response-dto.type.ts delete mode 100644 shared/src/packages/user/libs/types/user-with-image-relation.type.ts delete mode 100644 shared/src/packages/user/libs/types/user-with-password.type.ts delete mode 100644 shared/tsconfig.json diff --git a/shared/.eslintrc.yml b/packages/shared/.eslintrc.yml similarity index 100% rename from shared/.eslintrc.yml rename to packages/shared/.eslintrc.yml diff --git a/shared/package.json b/packages/shared/package.json similarity index 58% rename from shared/package.json rename to packages/shared/package.json index 32d7b493..56fa2757 100644 --- a/shared/package.json +++ b/packages/shared/package.json @@ -6,10 +6,13 @@ "npm": "9.8.x" }, "type": "module", + "main": "build/index.js", + "types": "build/index.d.ts", "scripts": { - "lint:js": "npx eslint \"src/**/*.ts\"", - "lint": "npm run lint:js", + "postinstall": "npm run build", "lint:type": "npx tsc --noEmit", + "lint:js": "npx eslint . --max-warnings=0 --no-warn-ignored", + "lint": "concurrently \"npm:lint:*\"", "build": "tsc && tsc-alias" }, "dependencies": { diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts new file mode 100644 index 00000000..ef4c02ee --- /dev/null +++ b/packages/shared/src/index.ts @@ -0,0 +1,6 @@ +export { + APIPath, + AppEnvironment, + ExceptionMessage, + ExceptionName +} from './libs/enums/enums.js'; diff --git a/packages/shared/src/libs/enums/api-path.enum.ts b/packages/shared/src/libs/enums/api-path.enum.ts new file mode 100644 index 00000000..6cf6fa65 --- /dev/null +++ b/packages/shared/src/libs/enums/api-path.enum.ts @@ -0,0 +1,5 @@ +const APIPath = { + AUTH: '/auth' +} as const; + +export { APIPath }; diff --git a/shared/src/libs/enums/app-environment.ts b/packages/shared/src/libs/enums/app-environment.ts similarity index 100% rename from shared/src/libs/enums/app-environment.ts rename to packages/shared/src/libs/enums/app-environment.ts diff --git a/shared/src/libs/enums/enums.ts b/packages/shared/src/libs/enums/enums.ts similarity index 79% rename from shared/src/libs/enums/enums.ts rename to packages/shared/src/libs/enums/enums.ts index ec0bd039..7488714d 100644 --- a/shared/src/libs/enums/enums.ts +++ b/packages/shared/src/libs/enums/enums.ts @@ -1,4 +1,4 @@ -export { ApiPath } from './api-path.enum.js'; +export { APIPath } from './api-path.enum.js'; export { AppEnvironment } from './app-environment.js'; export { ExceptionMessage } from './exception-message.enum.js'; export { ExceptionName } from './exception-name.enum.js'; diff --git a/shared/src/libs/enums/exception-message.enum.ts b/packages/shared/src/libs/enums/exception-message.enum.ts similarity index 100% rename from shared/src/libs/enums/exception-message.enum.ts rename to packages/shared/src/libs/enums/exception-message.enum.ts diff --git a/shared/src/libs/enums/exception-name.enum.ts b/packages/shared/src/libs/enums/exception-name.enum.ts similarity index 100% rename from shared/src/libs/enums/exception-name.enum.ts rename to packages/shared/src/libs/enums/exception-name.enum.ts diff --git a/shared/src/libs/exceptions/exceptions.ts b/packages/shared/src/libs/exceptions/exceptions.ts similarity index 100% rename from shared/src/libs/exceptions/exceptions.ts rename to packages/shared/src/libs/exceptions/exceptions.ts diff --git a/shared/src/libs/exceptions/http-error/http-error.exception.ts b/packages/shared/src/libs/exceptions/http-error/http-error.exception.ts similarity index 90% rename from shared/src/libs/exceptions/http-error/http-error.exception.ts rename to packages/shared/src/libs/exceptions/http-error/http-error.exception.ts index 87f260f6..808352a6 100644 --- a/shared/src/libs/exceptions/http-error/http-error.exception.ts +++ b/packages/shared/src/libs/exceptions/http-error/http-error.exception.ts @@ -1,7 +1,7 @@ import { type ValueOf } from '~/libs/types/types.js'; import { ExceptionName } from '../../enums/enums.js'; -import { HttpCode } from '../../packages/http/http.js'; +import { HttpCode } from '../../modules/http/http.js'; const DEFAULT_MESSAGE = 'Network Error'; diff --git a/shared/src/libs/exceptions/invalid-credentials-error/invalid-credentials-error.exception.ts b/packages/shared/src/libs/exceptions/invalid-credentials-error/invalid-credentials-error.exception.ts similarity index 100% rename from shared/src/libs/exceptions/invalid-credentials-error/invalid-credentials-error.exception.ts rename to packages/shared/src/libs/exceptions/invalid-credentials-error/invalid-credentials-error.exception.ts diff --git a/shared/src/libs/helpers/date/date.ts b/packages/shared/src/libs/helpers/date/date.ts similarity index 100% rename from shared/src/libs/helpers/date/date.ts rename to packages/shared/src/libs/helpers/date/date.ts diff --git a/shared/src/libs/helpers/date/dayjs/dayjs.ts b/packages/shared/src/libs/helpers/date/dayjs/dayjs.ts similarity index 100% rename from shared/src/libs/helpers/date/dayjs/dayjs.ts rename to packages/shared/src/libs/helpers/date/dayjs/dayjs.ts diff --git a/shared/src/libs/helpers/date/get-diff/get-diff.helper.ts b/packages/shared/src/libs/helpers/date/get-diff/get-diff.helper.ts similarity index 100% rename from shared/src/libs/helpers/date/get-diff/get-diff.helper.ts rename to packages/shared/src/libs/helpers/date/get-diff/get-diff.helper.ts diff --git a/shared/src/libs/helpers/date/get-from-now-time/get-from-now-time.helper.ts b/packages/shared/src/libs/helpers/date/get-from-now-time/get-from-now-time.helper.ts similarity index 100% rename from shared/src/libs/helpers/date/get-from-now-time/get-from-now-time.helper.ts rename to packages/shared/src/libs/helpers/date/get-from-now-time/get-from-now-time.helper.ts diff --git a/shared/src/libs/helpers/helpers.ts b/packages/shared/src/libs/helpers/helpers.ts similarity index 100% rename from shared/src/libs/helpers/helpers.ts rename to packages/shared/src/libs/helpers/helpers.ts diff --git a/shared/src/libs/packages/config/config.ts b/packages/shared/src/libs/modules/config/config.ts similarity index 100% rename from shared/src/libs/packages/config/config.ts rename to packages/shared/src/libs/modules/config/config.ts diff --git a/shared/src/libs/packages/config/libs/types/configurable.type.ts b/packages/shared/src/libs/modules/config/libs/types/configurable.type.ts similarity index 100% rename from shared/src/libs/packages/config/libs/types/configurable.type.ts rename to packages/shared/src/libs/modules/config/libs/types/configurable.type.ts diff --git a/shared/src/libs/packages/config/libs/types/types.ts b/packages/shared/src/libs/modules/config/libs/types/types.ts similarity index 100% rename from shared/src/libs/packages/config/libs/types/types.ts rename to packages/shared/src/libs/modules/config/libs/types/types.ts diff --git a/shared/src/libs/packages/http/http.ts b/packages/shared/src/libs/modules/http/http.ts similarity index 100% rename from shared/src/libs/packages/http/http.ts rename to packages/shared/src/libs/modules/http/http.ts diff --git a/shared/src/libs/packages/http/libs/enums/enums.ts b/packages/shared/src/libs/modules/http/libs/enums/enums.ts similarity index 100% rename from shared/src/libs/packages/http/libs/enums/enums.ts rename to packages/shared/src/libs/modules/http/libs/enums/enums.ts diff --git a/shared/src/libs/packages/http/libs/enums/http-code.enum.ts b/packages/shared/src/libs/modules/http/libs/enums/http-code.enum.ts similarity index 100% rename from shared/src/libs/packages/http/libs/enums/http-code.enum.ts rename to packages/shared/src/libs/modules/http/libs/enums/http-code.enum.ts diff --git a/shared/src/libs/packages/http/libs/enums/http-header.enum.ts b/packages/shared/src/libs/modules/http/libs/enums/http-header.enum.ts similarity index 100% rename from shared/src/libs/packages/http/libs/enums/http-header.enum.ts rename to packages/shared/src/libs/modules/http/libs/enums/http-header.enum.ts diff --git a/shared/src/libs/packages/http/libs/enums/http-method.enum.ts b/packages/shared/src/libs/modules/http/libs/enums/http-method.enum.ts similarity index 100% rename from shared/src/libs/packages/http/libs/enums/http-method.enum.ts rename to packages/shared/src/libs/modules/http/libs/enums/http-method.enum.ts diff --git a/shared/src/libs/types/generic/generic.ts b/packages/shared/src/libs/types/generic/generic.ts similarity index 100% rename from shared/src/libs/types/generic/generic.ts rename to packages/shared/src/libs/types/generic/generic.ts diff --git a/shared/src/libs/types/generic/value-of.type.ts b/packages/shared/src/libs/types/generic/value-of.type.ts similarity index 100% rename from shared/src/libs/types/generic/value-of.type.ts rename to packages/shared/src/libs/types/generic/value-of.type.ts diff --git a/shared/src/libs/types/types.ts b/packages/shared/src/libs/types/types.ts similarity index 100% rename from shared/src/libs/types/types.ts rename to packages/shared/src/libs/types/types.ts diff --git a/shared/src/libs/types/validation/validation-schema.type.ts b/packages/shared/src/libs/types/validation/validation-schema.type.ts similarity index 100% rename from shared/src/libs/types/validation/validation-schema.type.ts rename to packages/shared/src/libs/types/validation/validation-schema.type.ts diff --git a/shared/src/libs/types/validation/validation.ts b/packages/shared/src/libs/types/validation/validation.ts similarity index 100% rename from shared/src/libs/types/validation/validation.ts rename to packages/shared/src/libs/types/validation/validation.ts diff --git a/packages/shared/src/modules/auth/auth.ts b/packages/shared/src/modules/auth/auth.ts new file mode 100644 index 00000000..96e68824 --- /dev/null +++ b/packages/shared/src/modules/auth/auth.ts @@ -0,0 +1,2 @@ +export { AuthApiPath } from './libs/enums/enums.js'; +export { registration } from './libs/validation-schemas/validation-schemas.js'; diff --git a/packages/shared/src/modules/auth/libs/enums/auth-api-path.enum.ts b/packages/shared/src/modules/auth/libs/enums/auth-api-path.enum.ts new file mode 100644 index 00000000..98dfda2a --- /dev/null +++ b/packages/shared/src/modules/auth/libs/enums/auth-api-path.enum.ts @@ -0,0 +1,5 @@ +const AuthApiPath = { + REGISTER: '/register' +} as const; + +export { AuthApiPath }; diff --git a/shared/src/packages/auth/libs/enums/enums.ts b/packages/shared/src/modules/auth/libs/enums/enums.ts similarity index 100% rename from shared/src/packages/auth/libs/enums/enums.ts rename to packages/shared/src/modules/auth/libs/enums/enums.ts diff --git a/shared/src/packages/auth/libs/validation-schemas/registration.validation-schema.ts b/packages/shared/src/modules/auth/libs/validation-schemas/registration.validation-schema.ts similarity index 100% rename from shared/src/packages/auth/libs/validation-schemas/registration.validation-schema.ts rename to packages/shared/src/modules/auth/libs/validation-schemas/registration.validation-schema.ts diff --git a/shared/src/packages/auth/libs/validation-schemas/validation-schemas.ts b/packages/shared/src/modules/auth/libs/validation-schemas/validation-schemas.ts similarity index 55% rename from shared/src/packages/auth/libs/validation-schemas/validation-schemas.ts rename to packages/shared/src/modules/auth/libs/validation-schemas/validation-schemas.ts index 168b9fcf..dc386381 100644 --- a/shared/src/packages/auth/libs/validation-schemas/validation-schemas.ts +++ b/packages/shared/src/modules/auth/libs/validation-schemas/validation-schemas.ts @@ -1,2 +1 @@ -export { login } from './login.validation-schema.js'; export { registration } from './registration.validation-schema.js'; diff --git a/shared/src/packages/user/libs/enums/enums.ts b/packages/shared/src/modules/user/libs/enums/enums.ts similarity index 78% rename from shared/src/packages/user/libs/enums/enums.ts rename to packages/shared/src/modules/user/libs/enums/enums.ts index 649a6f28..b4c9d4f1 100644 --- a/shared/src/packages/user/libs/enums/enums.ts +++ b/packages/shared/src/modules/user/libs/enums/enums.ts @@ -1,4 +1,3 @@ export { UserPayloadKey } from './user-payload-key.enum.js'; export { UserValidationMessage } from './user-validation-message.enum.js'; export { UserValidationRule } from './user-validation-rule.enum.js'; -export { UsersApiPath } from './users-api-path.enum.js'; diff --git a/shared/src/packages/user/libs/enums/user-payload-key.enum.ts b/packages/shared/src/modules/user/libs/enums/user-payload-key.enum.ts similarity index 100% rename from shared/src/packages/user/libs/enums/user-payload-key.enum.ts rename to packages/shared/src/modules/user/libs/enums/user-payload-key.enum.ts diff --git a/shared/src/packages/user/libs/enums/user-validation-message.enum.ts b/packages/shared/src/modules/user/libs/enums/user-validation-message.enum.ts similarity index 100% rename from shared/src/packages/user/libs/enums/user-validation-message.enum.ts rename to packages/shared/src/modules/user/libs/enums/user-validation-message.enum.ts diff --git a/shared/src/packages/user/libs/enums/user-validation-rule.enum.ts b/packages/shared/src/modules/user/libs/enums/user-validation-rule.enum.ts similarity index 100% rename from shared/src/packages/user/libs/enums/user-validation-rule.enum.ts rename to packages/shared/src/modules/user/libs/enums/user-validation-rule.enum.ts diff --git a/packages/shared/src/modules/user/libs/types/types.ts b/packages/shared/src/modules/user/libs/types/types.ts new file mode 100644 index 00000000..8da0aa85 --- /dev/null +++ b/packages/shared/src/modules/user/libs/types/types.ts @@ -0,0 +1,3 @@ +export { type User } from './user.type.js'; +export { type UserRegisterRequestDto } from './user-register-request-dto.type.js'; +export { type UserRegisterResponseDto } from './user-register-response-dto.type.js'; diff --git a/shared/src/packages/user/libs/types/user-register-request-dto.type.ts b/packages/shared/src/modules/user/libs/types/user-register-request-dto.type.ts similarity index 100% rename from shared/src/packages/user/libs/types/user-register-request-dto.type.ts rename to packages/shared/src/modules/user/libs/types/user-register-request-dto.type.ts diff --git a/packages/shared/src/modules/user/libs/types/user-register-response-dto.type.ts b/packages/shared/src/modules/user/libs/types/user-register-response-dto.type.ts new file mode 100644 index 00000000..1f2a354a --- /dev/null +++ b/packages/shared/src/modules/user/libs/types/user-register-response-dto.type.ts @@ -0,0 +1,5 @@ +import { User } from './user.type.js'; + +type UserRegisterResponseDto = User; + +export { type UserRegisterResponseDto }; diff --git a/shared/src/packages/user/libs/types/user.type.ts b/packages/shared/src/modules/user/libs/types/user.type.ts similarity index 100% rename from shared/src/packages/user/libs/types/user.type.ts rename to packages/shared/src/modules/user/libs/types/user.type.ts diff --git a/shared/src/packages/user/user.ts b/packages/shared/src/modules/user/user.ts similarity index 50% rename from shared/src/packages/user/user.ts rename to packages/shared/src/modules/user/user.ts index ae827d8e..04e671a1 100644 --- a/shared/src/packages/user/user.ts +++ b/packages/shared/src/modules/user/user.ts @@ -1,16 +1,10 @@ export { UserPayloadKey, - UsersApiPath, UserValidationMessage, UserValidationRule } from './libs/enums/enums.js'; export { type User, - type UserAuthResponse, - type UserLoginRequestDto, - type UserLoginResponseDto, type UserRegisterRequestDto, - type UserRegisterResponseDto, - type UserWithImageRelation, - type UserWithPassword + type UserRegisterResponseDto } from './libs/types/types.js'; diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json new file mode 100644 index 00000000..4c02f4c8 --- /dev/null +++ b/packages/shared/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*.ts"], + "exclude": ["node_modules/*"], + "compilerOptions": { + "baseUrl": ".", + "outDir": "build", + "paths": { + "~/*": ["src/*"] + } + } +} diff --git a/shared/src/libs/enums/api-path.enum.ts b/shared/src/libs/enums/api-path.enum.ts deleted file mode 100644 index f1446a5e..00000000 --- a/shared/src/libs/enums/api-path.enum.ts +++ /dev/null @@ -1,10 +0,0 @@ -const ApiPath = { - AUTH: '/auth', - POSTS: '/posts', - COMMENTS: '/comments', - IMAGES: '/images', - USERS: '/users', - PASSWORD: '/password' -} as const; - -export { ApiPath }; diff --git a/shared/src/libs/packages/socket/libs/enums/enums.ts b/shared/src/libs/packages/socket/libs/enums/enums.ts deleted file mode 100644 index 253f39df..00000000 --- a/shared/src/libs/packages/socket/libs/enums/enums.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { NotificationSocketEvent } from './notification-socket-event.enum.js'; -export { SocketEvent } from './socket-event.enum.js'; -export { SocketNamespace } from './socket-namespace.enum.js'; diff --git a/shared/src/libs/packages/socket/libs/enums/notification-socket-event.enum.ts b/shared/src/libs/packages/socket/libs/enums/notification-socket-event.enum.ts deleted file mode 100644 index 97134e87..00000000 --- a/shared/src/libs/packages/socket/libs/enums/notification-socket-event.enum.ts +++ /dev/null @@ -1,6 +0,0 @@ -const NotificationSocketEvent = { - LIKE_POST: 'like-post', - NEW_POST: 'new-post' -} as const; - -export { NotificationSocketEvent }; diff --git a/shared/src/libs/packages/socket/libs/enums/socket-event.enum.ts b/shared/src/libs/packages/socket/libs/enums/socket-event.enum.ts deleted file mode 100644 index 7c7d7140..00000000 --- a/shared/src/libs/packages/socket/libs/enums/socket-event.enum.ts +++ /dev/null @@ -1,7 +0,0 @@ -const SocketEvent = { - CONNECTION: 'connection', - NOTIFICATION_JOIN_ROOM: 'notification-join-room', - NOTIFICATION_LEAVE_ROOM: 'notification-leave-room' -} as const; - -export { SocketEvent }; diff --git a/shared/src/libs/packages/socket/libs/enums/socket-namespace.enum.ts b/shared/src/libs/packages/socket/libs/enums/socket-namespace.enum.ts deleted file mode 100644 index 81c1cf20..00000000 --- a/shared/src/libs/packages/socket/libs/enums/socket-namespace.enum.ts +++ /dev/null @@ -1,5 +0,0 @@ -const SocketNamespace = { - NOTIFICATION: '/notification' -} as const; - -export { SocketNamespace }; diff --git a/shared/src/libs/packages/socket/socket.ts b/shared/src/libs/packages/socket/socket.ts deleted file mode 100644 index 136228bb..00000000 --- a/shared/src/libs/packages/socket/socket.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { - NotificationSocketEvent, - SocketEvent, - SocketNamespace -} from './libs/enums/enums.js'; diff --git a/shared/src/packages/auth/auth.ts b/shared/src/packages/auth/auth.ts deleted file mode 100644 index 3bf44ea8..00000000 --- a/shared/src/packages/auth/auth.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { AuthApiPath } from './libs/enums/enums.js'; -export { - login, - registration -} from './libs/validation-schemas/validation-schemas.js'; diff --git a/shared/src/packages/auth/libs/enums/auth-api-path.enum.ts b/shared/src/packages/auth/libs/enums/auth-api-path.enum.ts deleted file mode 100644 index 8f6dfa98..00000000 --- a/shared/src/packages/auth/libs/enums/auth-api-path.enum.ts +++ /dev/null @@ -1,7 +0,0 @@ -const AuthApiPath = { - LOGIN: '/login', - REGISTER: '/register', - USER: '/user' -} as const; - -export { AuthApiPath }; diff --git a/shared/src/packages/auth/libs/validation-schemas/login.validation-schema.ts b/shared/src/packages/auth/libs/validation-schemas/login.validation-schema.ts deleted file mode 100644 index 77da6c0a..00000000 --- a/shared/src/packages/auth/libs/validation-schemas/login.validation-schema.ts +++ /dev/null @@ -1,32 +0,0 @@ -import Joi from 'joi'; - -import { - UserPayloadKey, - UserValidationMessage, - UserValidationRule -} from '../../../user/user.js'; - -const login = Joi.object({ - [UserPayloadKey.EMAIL]: Joi.string() - .trim() - .email({ tlds: { allow: false } }) - .required() - .messages({ - 'string.email': UserValidationMessage.EMAIL_WRONG, - 'any.required': UserValidationMessage.EMAIL_REQUIRE, - 'string.empty': UserValidationMessage.EMAIL_REQUIRE - }), - [UserPayloadKey.PASSWORD]: Joi.string() - .trim() - .min(UserValidationRule.PASSWORD_MIN_LENGTH) - .max(UserValidationRule.PASSWORD_MAX_LENGTH) - .required() - .messages({ - 'any.required': UserValidationMessage.PASSWORD_REQUIRE, - 'string.empty': UserValidationMessage.PASSWORD_REQUIRE, - 'string.min': UserValidationMessage.PASSWORD_MIN_LENGTH, - 'string.max': UserValidationMessage.PASSWORD_MAX_LENGTH - }) -}); - -export { login }; diff --git a/shared/src/packages/comment/comment.ts b/shared/src/packages/comment/comment.ts deleted file mode 100644 index eac41604..00000000 --- a/shared/src/packages/comment/comment.ts +++ /dev/null @@ -1,7 +0,0 @@ -export { CommentPayloadKey, CommentsApiPath } from './libs/enums/enums.js'; -export { - type Comment, - type CommentWithUserNestedRelations, - type CreateCommentRequestDto, - type GetCommentByIdResponseDto -} from './libs/types/types.js'; diff --git a/shared/src/packages/comment/libs/enums/comment-payload-key.enum.ts b/shared/src/packages/comment/libs/enums/comment-payload-key.enum.ts deleted file mode 100644 index 4b8b0049..00000000 --- a/shared/src/packages/comment/libs/enums/comment-payload-key.enum.ts +++ /dev/null @@ -1,5 +0,0 @@ -const CommentPayloadKey = { - BODY: 'body' -} as const; - -export { CommentPayloadKey }; diff --git a/shared/src/packages/comment/libs/enums/comments-api-path.enum.ts b/shared/src/packages/comment/libs/enums/comments-api-path.enum.ts deleted file mode 100644 index 00e491b2..00000000 --- a/shared/src/packages/comment/libs/enums/comments-api-path.enum.ts +++ /dev/null @@ -1,7 +0,0 @@ -const CommentsApiPath = { - ROOT: '/', - $ID: '/:id', - REACT: '/react' -} as const; - -export { CommentsApiPath }; diff --git a/shared/src/packages/comment/libs/enums/enums.ts b/shared/src/packages/comment/libs/enums/enums.ts deleted file mode 100644 index 846b4892..00000000 --- a/shared/src/packages/comment/libs/enums/enums.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { CommentPayloadKey } from './comment-payload-key.enum.js'; -export { CommentsApiPath } from './comments-api-path.enum.js'; diff --git a/shared/src/packages/comment/libs/types/comment-with-user-nested-relations.type.ts b/shared/src/packages/comment/libs/types/comment-with-user-nested-relations.type.ts deleted file mode 100644 index def9b453..00000000 --- a/shared/src/packages/comment/libs/types/comment-with-user-nested-relations.type.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { type UserWithImageRelation } from '~/packages/user/user.js'; - -import { type Comment } from './comment.type.js'; - -type CommentWithUserNestedRelations = Comment & - Record<'user', UserWithImageRelation>; - -export { type CommentWithUserNestedRelations }; diff --git a/shared/src/packages/comment/libs/types/comment.type.ts b/shared/src/packages/comment/libs/types/comment.type.ts deleted file mode 100644 index 9c5409e3..00000000 --- a/shared/src/packages/comment/libs/types/comment.type.ts +++ /dev/null @@ -1,10 +0,0 @@ -type Comment = { - id: number; - body: string; - postId: number; - userId: number; - createdAt: string; - updatedAt: string; -}; - -export { type Comment }; diff --git a/shared/src/packages/comment/libs/types/create-comment-request-dto.type.ts b/shared/src/packages/comment/libs/types/create-comment-request-dto.type.ts deleted file mode 100644 index 60bc732f..00000000 --- a/shared/src/packages/comment/libs/types/create-comment-request-dto.type.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { type Comment } from './comment.type.js'; - -type CreateCommentRequestDto = Pick; - -export { type CreateCommentRequestDto }; diff --git a/shared/src/packages/comment/libs/types/get-comment-by-id-response-dto.type.ts b/shared/src/packages/comment/libs/types/get-comment-by-id-response-dto.type.ts deleted file mode 100644 index eb5f562b..00000000 --- a/shared/src/packages/comment/libs/types/get-comment-by-id-response-dto.type.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { type CommentWithUserNestedRelations } from './comment-with-user-nested-relations.type.js'; - -type GetCommentByIdResponseDto = CommentWithUserNestedRelations | null; - -export { type GetCommentByIdResponseDto }; diff --git a/shared/src/packages/comment/libs/types/types.ts b/shared/src/packages/comment/libs/types/types.ts deleted file mode 100644 index 91d43d8d..00000000 --- a/shared/src/packages/comment/libs/types/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { type Comment } from './comment.type.js'; -export { type CommentWithUserNestedRelations } from './comment-with-user-nested-relations.type.js'; -export { type CreateCommentRequestDto } from './create-comment-request-dto.type.js'; -export { type GetCommentByIdResponseDto } from './get-comment-by-id-response-dto.type.js'; diff --git a/shared/src/packages/image/image.ts b/shared/src/packages/image/image.ts deleted file mode 100644 index 058a8a20..00000000 --- a/shared/src/packages/image/image.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { ImagePayloadKey, ImagesApiPath } from './libs/enums/enums.js'; -export { type Image, type UploadImageResponseDto } from './libs/types/types.js'; diff --git a/shared/src/packages/image/libs/enums/enums.ts b/shared/src/packages/image/libs/enums/enums.ts deleted file mode 100644 index b5625dbd..00000000 --- a/shared/src/packages/image/libs/enums/enums.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { ImagePayloadKey } from './image-payload-key.enum.js'; -export { ImagesApiPath } from './images-api-path.enum.js'; diff --git a/shared/src/packages/image/libs/enums/image-payload-key.enum.ts b/shared/src/packages/image/libs/enums/image-payload-key.enum.ts deleted file mode 100644 index a41dbbe2..00000000 --- a/shared/src/packages/image/libs/enums/image-payload-key.enum.ts +++ /dev/null @@ -1,5 +0,0 @@ -const ImagePayloadKey = { - IMAGE: 'image' -} as const; - -export { ImagePayloadKey }; diff --git a/shared/src/packages/image/libs/enums/images-api-path.enum.ts b/shared/src/packages/image/libs/enums/images-api-path.enum.ts deleted file mode 100644 index dca25c72..00000000 --- a/shared/src/packages/image/libs/enums/images-api-path.enum.ts +++ /dev/null @@ -1,5 +0,0 @@ -const ImagesApiPath = { - ROOT: '/' -} as const; - -export { ImagesApiPath }; diff --git a/shared/src/packages/image/libs/types/image.type.ts b/shared/src/packages/image/libs/types/image.type.ts deleted file mode 100644 index 99a93223..00000000 --- a/shared/src/packages/image/libs/types/image.type.ts +++ /dev/null @@ -1,8 +0,0 @@ -type Image = { - id: number; - link: string; - createdAt: string; - updatedAt: string; -}; - -export { type Image }; diff --git a/shared/src/packages/image/libs/types/types.ts b/shared/src/packages/image/libs/types/types.ts deleted file mode 100644 index 258565a3..00000000 --- a/shared/src/packages/image/libs/types/types.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { type Image } from './image.type.js'; -export { type UploadImageResponseDto } from './upload-image-response-dto.type.js'; diff --git a/shared/src/packages/image/libs/types/upload-image-response-dto.type.ts b/shared/src/packages/image/libs/types/upload-image-response-dto.type.ts deleted file mode 100644 index 8a8d24ce..00000000 --- a/shared/src/packages/image/libs/types/upload-image-response-dto.type.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { type Image } from './image.type.js'; - -type UploadImageResponseDto = Image; - -export { type UploadImageResponseDto }; diff --git a/shared/src/packages/password/libs/enums/enums.ts b/shared/src/packages/password/libs/enums/enums.ts deleted file mode 100644 index 9c73e1c8..00000000 --- a/shared/src/packages/password/libs/enums/enums.ts +++ /dev/null @@ -1 +0,0 @@ -export { PasswordApiPath } from './password-api-path.enum.js'; diff --git a/shared/src/packages/password/libs/enums/password-api-path.enum.ts b/shared/src/packages/password/libs/enums/password-api-path.enum.ts deleted file mode 100644 index 5e633975..00000000 --- a/shared/src/packages/password/libs/enums/password-api-path.enum.ts +++ /dev/null @@ -1,6 +0,0 @@ -const PasswordApiPath = { - SET: '/set', - RESET: '/reset' -} as const; - -export { PasswordApiPath }; diff --git a/shared/src/packages/password/password.ts b/shared/src/packages/password/password.ts deleted file mode 100644 index e9711362..00000000 --- a/shared/src/packages/password/password.ts +++ /dev/null @@ -1 +0,0 @@ -export { PasswordApiPath } from './libs/enums/enums.js'; diff --git a/shared/src/packages/post/libs/enums/enums.ts b/shared/src/packages/post/libs/enums/enums.ts deleted file mode 100644 index 6df9a37f..00000000 --- a/shared/src/packages/post/libs/enums/enums.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { FilterUserMode } from './filter-user-mode.enum.js'; -export { PostPayloadKey } from './post-payload-key.enum.js'; -export { PostsApiPath } from './posts-api-path.enum.js'; diff --git a/shared/src/packages/post/libs/enums/filter-user-mode.enum.ts b/shared/src/packages/post/libs/enums/filter-user-mode.enum.ts deleted file mode 100644 index 536167ff..00000000 --- a/shared/src/packages/post/libs/enums/filter-user-mode.enum.ts +++ /dev/null @@ -1,8 +0,0 @@ -const FilterUserMode = { - ALL: 'all', - INCLUDE: 'include', - EXCLUDE: 'exclude', - LIKED_BY_OWN: 'likedByOwn' -} as const; - -export { FilterUserMode }; diff --git a/shared/src/packages/post/libs/enums/post-payload-key.enum.ts b/shared/src/packages/post/libs/enums/post-payload-key.enum.ts deleted file mode 100644 index 1d9c244f..00000000 --- a/shared/src/packages/post/libs/enums/post-payload-key.enum.ts +++ /dev/null @@ -1,5 +0,0 @@ -const PostPayloadKey = { - BODY: 'body' -} as const; - -export { PostPayloadKey }; diff --git a/shared/src/packages/post/libs/enums/posts-api-path.enum.ts b/shared/src/packages/post/libs/enums/posts-api-path.enum.ts deleted file mode 100644 index 1561f66e..00000000 --- a/shared/src/packages/post/libs/enums/posts-api-path.enum.ts +++ /dev/null @@ -1,7 +0,0 @@ -const PostsApiPath = { - ROOT: '/', - $ID: '/:id', - REACT: '/react' -} as const; - -export { PostsApiPath }; diff --git a/shared/src/packages/post/libs/types/create-post-reaction-request-dto.type.ts b/shared/src/packages/post/libs/types/create-post-reaction-request-dto.type.ts deleted file mode 100644 index da0f583a..00000000 --- a/shared/src/packages/post/libs/types/create-post-reaction-request-dto.type.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { type PostReaction } from './post-reaction.type.js'; - -type CreatePostReactionRequestDto = Pick; - -export { type CreatePostReactionRequestDto }; diff --git a/shared/src/packages/post/libs/types/create-post-reaction-response-dto.type.ts b/shared/src/packages/post/libs/types/create-post-reaction-response-dto.type.ts deleted file mode 100644 index 42b550b0..00000000 --- a/shared/src/packages/post/libs/types/create-post-reaction-response-dto.type.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { type PostReactionWithPostRelation } from './post-reaction-with-post-relation.type.js'; - -type CreatePostReactionResponseDto = - | Record - | PostReactionWithPostRelation; - -export { type CreatePostReactionResponseDto }; diff --git a/shared/src/packages/post/libs/types/create-post-request-dto.type.ts b/shared/src/packages/post/libs/types/create-post-request-dto.type.ts deleted file mode 100644 index 198d0f00..00000000 --- a/shared/src/packages/post/libs/types/create-post-request-dto.type.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { type Post } from './post.type.js'; - -type CreatePostRequestDto = Pick; - -export { type CreatePostRequestDto }; diff --git a/shared/src/packages/post/libs/types/get-post-by-id-response-dto.type.ts b/shared/src/packages/post/libs/types/get-post-by-id-response-dto.type.ts deleted file mode 100644 index 35e62eca..00000000 --- a/shared/src/packages/post/libs/types/get-post-by-id-response-dto.type.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { type PostWithCommentImageUserNestedRelationsWithCount } from './post-with-comment-image-user-nested-relations-with-count.type.js'; - -type GetPostByIdResponseDto = - PostWithCommentImageUserNestedRelationsWithCount | null; - -export { type GetPostByIdResponseDto }; diff --git a/shared/src/packages/post/libs/types/get-posts-by-filter-request-dto.type.ts b/shared/src/packages/post/libs/types/get-posts-by-filter-request-dto.type.ts deleted file mode 100644 index 6fcd108c..00000000 --- a/shared/src/packages/post/libs/types/get-posts-by-filter-request-dto.type.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { type PostFilter } from './post-filter.type.js'; - -type GetPostsByFilterRequestDto = PostFilter; - -export { type GetPostsByFilterRequestDto }; diff --git a/shared/src/packages/post/libs/types/get-posts-by-filter-response-dto.type.ts b/shared/src/packages/post/libs/types/get-posts-by-filter-response-dto.type.ts deleted file mode 100644 index c52c9732..00000000 --- a/shared/src/packages/post/libs/types/get-posts-by-filter-response-dto.type.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { type PostWithImageUserNestedRelationsWithCount } from './post-with-image-user-nested-relations-with-count.type.js'; - -type GetPostsByFilterResponseDto = PostWithImageUserNestedRelationsWithCount[]; - -export { type GetPostsByFilterResponseDto }; diff --git a/shared/src/packages/post/libs/types/post-filter.type.ts b/shared/src/packages/post/libs/types/post-filter.type.ts deleted file mode 100644 index ec0551eb..00000000 --- a/shared/src/packages/post/libs/types/post-filter.type.ts +++ /dev/null @@ -1,7 +0,0 @@ -type PostFilter = { - from: number; - count: number; - userId?: number; -}; - -export { type PostFilter }; diff --git a/shared/src/packages/post/libs/types/post-reaction-with-post-relation.type.ts b/shared/src/packages/post/libs/types/post-reaction-with-post-relation.type.ts deleted file mode 100644 index e206b9c8..00000000 --- a/shared/src/packages/post/libs/types/post-reaction-with-post-relation.type.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { type Post } from '~/packages/post/post.js'; - -import { type PostReaction } from './post-reaction.type.js'; - -type PostReactionWithPostRelation = PostReaction & Record<'post', Post>; - -export { type PostReactionWithPostRelation }; diff --git a/shared/src/packages/post/libs/types/post-reaction.type.ts b/shared/src/packages/post/libs/types/post-reaction.type.ts deleted file mode 100644 index f77b5416..00000000 --- a/shared/src/packages/post/libs/types/post-reaction.type.ts +++ /dev/null @@ -1,10 +0,0 @@ -type PostReaction = { - id: number; - isLike: boolean; - postId: number; - userId: number; - createdAt: string; - updatedAt: string; -}; - -export { type PostReaction }; diff --git a/shared/src/packages/post/libs/types/post-with-comment-image-user-nested-relations-with-count.type.ts b/shared/src/packages/post/libs/types/post-with-comment-image-user-nested-relations-with-count.type.ts deleted file mode 100644 index 77b975bf..00000000 --- a/shared/src/packages/post/libs/types/post-with-comment-image-user-nested-relations-with-count.type.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { type CommentWithUserNestedRelations } from '~/packages/comment/comment.js'; - -import { type PostWithImageUserNestedRelationsWithCount } from './post-with-image-user-nested-relations-with-count.type.js'; - -type PostWithCommentImageUserNestedRelationsWithCount = - PostWithImageUserNestedRelationsWithCount & - Record<'comments', CommentWithUserNestedRelations[]>; - -export { type PostWithCommentImageUserNestedRelationsWithCount }; diff --git a/shared/src/packages/post/libs/types/post-with-image-user-nested-relations-with-count.type.ts b/shared/src/packages/post/libs/types/post-with-image-user-nested-relations-with-count.type.ts deleted file mode 100644 index d1208bc6..00000000 --- a/shared/src/packages/post/libs/types/post-with-image-user-nested-relations-with-count.type.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { type Image } from '~/packages/image/image.js'; -import { type UserWithImageRelation } from '~/packages/user/user.js'; - -import { type Post } from './post.type.js'; - -type PostWithImageUserNestedRelationsWithCount = Post & - Record<'image', Image> & - Record<'user', UserWithImageRelation> & { - commentCount: number; - likeCount: number; - dislikeCount: number; - }; - -export { type PostWithImageUserNestedRelationsWithCount }; diff --git a/shared/src/packages/post/libs/types/post.type.ts b/shared/src/packages/post/libs/types/post.type.ts deleted file mode 100644 index 18eeaa9f..00000000 --- a/shared/src/packages/post/libs/types/post.type.ts +++ /dev/null @@ -1,10 +0,0 @@ -type Post = { - id: number; - body: string; - imageId: number | null; - userId: number; - createdAt: string; - updatedAt: string; -}; - -export { type Post }; diff --git a/shared/src/packages/post/libs/types/types.ts b/shared/src/packages/post/libs/types/types.ts deleted file mode 100644 index cfc0527c..00000000 --- a/shared/src/packages/post/libs/types/types.ts +++ /dev/null @@ -1,12 +0,0 @@ -export { type CreatePostReactionRequestDto } from './create-post-reaction-request-dto.type.js'; -export { type CreatePostReactionResponseDto } from './create-post-reaction-response-dto.type.js'; -export { type CreatePostRequestDto } from './create-post-request-dto.type.js'; -export { type GetPostByIdResponseDto } from './get-post-by-id-response-dto.type.js'; -export { type GetPostsByFilterRequestDto } from './get-posts-by-filter-request-dto.type.js'; -export { type GetPostsByFilterResponseDto } from './get-posts-by-filter-response-dto.type.js'; -export { type Post } from './post.type.js'; -export { type PostFilter } from './post-filter.type.js'; -export { type PostReaction } from './post-reaction.type.js'; -export { type PostReactionWithPostRelation } from './post-reaction-with-post-relation.type.js'; -export { type PostWithCommentImageUserNestedRelationsWithCount } from './post-with-comment-image-user-nested-relations-with-count.type.js'; -export { type PostWithImageUserNestedRelationsWithCount } from './post-with-image-user-nested-relations-with-count.type.js'; diff --git a/shared/src/packages/post/post.ts b/shared/src/packages/post/post.ts deleted file mode 100644 index d3882ab2..00000000 --- a/shared/src/packages/post/post.ts +++ /dev/null @@ -1,19 +0,0 @@ -export { - FilterUserMode, - PostPayloadKey, - PostsApiPath -} from './libs/enums/enums.js'; -export { - type CreatePostReactionRequestDto, - type CreatePostReactionResponseDto, - type CreatePostRequestDto, - type GetPostByIdResponseDto, - type GetPostsByFilterRequestDto, - type GetPostsByFilterResponseDto, - type Post, - type PostFilter, - type PostReaction, - type PostReactionWithPostRelation, - type PostWithCommentImageUserNestedRelationsWithCount, - type PostWithImageUserNestedRelationsWithCount -} from './libs/types/types.js'; diff --git a/shared/src/packages/user/libs/enums/users-api-path.enum.ts b/shared/src/packages/user/libs/enums/users-api-path.enum.ts deleted file mode 100644 index e79ed57d..00000000 --- a/shared/src/packages/user/libs/enums/users-api-path.enum.ts +++ /dev/null @@ -1,5 +0,0 @@ -const UsersApiPath = { - $ID: '/:id' -} as const; - -export { UsersApiPath }; diff --git a/shared/src/packages/user/libs/types/types.ts b/shared/src/packages/user/libs/types/types.ts deleted file mode 100644 index 5251912a..00000000 --- a/shared/src/packages/user/libs/types/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -export { type User } from './user.type.js'; -export { type UserAuthResponse } from './user-auth-response.type.js'; -export { type UserLoginRequestDto } from './user-login-request-dto.type.js'; -export { type UserLoginResponseDto } from './user-login-response-dto.type.js'; -export { type UserRegisterRequestDto } from './user-register-request-dto.type.js'; -export { type UserRegisterResponseDto } from './user-register-response-dto.type.js'; -export { type UserWithImageRelation } from './user-with-image-relation.type.js'; -export { type UserWithPassword } from './user-with-password.type.js'; diff --git a/shared/src/packages/user/libs/types/user-auth-response.type.ts b/shared/src/packages/user/libs/types/user-auth-response.type.ts deleted file mode 100644 index de80d50d..00000000 --- a/shared/src/packages/user/libs/types/user-auth-response.type.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { type UserWithImageRelation } from './user-with-image-relation.type.js'; - -type UserAuthResponse = UserWithImageRelation; - -export { type UserAuthResponse }; diff --git a/shared/src/packages/user/libs/types/user-login-request-dto.type.ts b/shared/src/packages/user/libs/types/user-login-request-dto.type.ts deleted file mode 100644 index 179552b2..00000000 --- a/shared/src/packages/user/libs/types/user-login-request-dto.type.ts +++ /dev/null @@ -1,6 +0,0 @@ -type UserLoginRequestDto = { - email: string; - password: string; -}; - -export { type UserLoginRequestDto }; diff --git a/shared/src/packages/user/libs/types/user-login-response-dto.type.ts b/shared/src/packages/user/libs/types/user-login-response-dto.type.ts deleted file mode 100644 index 21306a5c..00000000 --- a/shared/src/packages/user/libs/types/user-login-response-dto.type.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { type UserAuthResponse } from './user-auth-response.type.js'; - -type UserLoginResponseDto = { - user: UserAuthResponse; - token: string; -}; - -export { type UserLoginResponseDto }; diff --git a/shared/src/packages/user/libs/types/user-register-response-dto.type.ts b/shared/src/packages/user/libs/types/user-register-response-dto.type.ts deleted file mode 100644 index 4d2f431d..00000000 --- a/shared/src/packages/user/libs/types/user-register-response-dto.type.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { type UserLoginResponseDto } from './user-login-response-dto.type.js'; - -type UserRegisterResponseDto = UserLoginResponseDto; - -export { type UserRegisterResponseDto }; diff --git a/shared/src/packages/user/libs/types/user-with-image-relation.type.ts b/shared/src/packages/user/libs/types/user-with-image-relation.type.ts deleted file mode 100644 index 48d95a13..00000000 --- a/shared/src/packages/user/libs/types/user-with-image-relation.type.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { type Image } from '~/packages/image/image.js'; - -import { type User } from './user.type.js'; - -type UserWithImageRelation = User & { - image: Image | null; -}; - -export { type UserWithImageRelation }; diff --git a/shared/src/packages/user/libs/types/user-with-password.type.ts b/shared/src/packages/user/libs/types/user-with-password.type.ts deleted file mode 100644 index ca74ab0e..00000000 --- a/shared/src/packages/user/libs/types/user-with-password.type.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { type User } from './user.type.js'; - -type UserWithPassword = User & Record<'password', string>; - -export { type UserWithPassword }; diff --git a/shared/tsconfig.json b/shared/tsconfig.json deleted file mode 100644 index b658a345..00000000 --- a/shared/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "../tsconfig.json", - "include": ["src/**/*.ts"], - "exclude": ["node_modules/*"], - "compilerOptions": { - "allowJs": true, - "baseUrl": ".", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "lib": ["ESNext"], - "esModuleInterop": true, - "module": "NodeNext", - "moduleResolution": "NodeNext", - "outDir": "dist", - "paths": { - "~/*": ["src/*"] - }, - "types": ["node"] - } -} From 1046a4793abb2f78a836191b1a1e38b66d907eef Mon Sep 17 00:00:00 2001 From: Volodymyr Minchenko Date: Sat, 8 Jun 2024 21:31:18 +0300 Subject: [PATCH 02/28] thjs-122: * prepare packages/backend workspace --- {server => apps/backend}/.env.example | 11 - {server => apps/backend}/.eslintrc.yml | 0 {server => apps/backend}/jest.config.js | 0 apps/backend/knexfile.ts | 3 + {server => apps/backend}/package.json | 23 +- .../20211208202419_create_tables.ts | 34 ++ .../backend}/src/db/seed-data/users-seed.ts | 18 +- apps/backend/src/db/seeds/fill-database.ts | 15 + apps/backend/src/libs/enums/enums.ts | 7 + .../backend/src/libs/exceptions/exceptions.ts | 1 + .../src/libs/modules/config/config.module.ts | 42 +- .../backend/src/libs/modules/config/config.ts | 10 + .../config/libs/types/config-module.type.ts | 7 + .../libs/types/environment-schema.type.ts | 9 - .../libs/modules}/config/libs/types/types.ts | 2 +- .../modules/controller/controller.module.ts | 68 ++++ .../src/libs/modules/controller/controller.ts | 7 + .../libs/enums/controller-hook.enum.ts | 0 .../modules}/controller/libs/enums/enums.ts | 0 .../controller-api-handler-options.type.ts | 15 + .../controller-api-handler-response.type.ts | 9 + .../libs/types/controller-api-handler.type.ts | 8 + .../libs/types/controller-module.type.ts | 9 + .../types/controller-route-parameters.type.ts | 16 + .../modules/controller/libs/types/types.ts | 5 + .../libs/modules}/database/abstract.model.ts | 0 .../modules}/database/abstract.repository.ts | 0 .../libs/modules/database/database.module.ts | 42 +- .../src/libs/modules/database/database.ts | 12 + .../libs/enums/database-table-name.enum.ts | 5 + .../modules}/database/libs/enums/enums.ts | 0 .../libs/types/database-package.type.ts | 8 +- .../database/libs/types/repository.type.ts | 0 .../libs/modules/database/libs/types/types.ts | 2 + apps/backend/src/libs/modules/http/http.ts | 1 + .../src/libs/modules/http/libs/enums/enums.ts | 5 + .../logger/libs/types/logger-module.type.ts | 13 + .../libs/modules/logger/libs/types/types.ts | 1 + .../src/libs/modules/logger/logger.module.ts | 43 ++ .../backend/src/libs/modules/logger/logger.ts | 6 + .../modules}/path/libs/helpers/helpers.ts | 0 .../helpers/join-path/join-path.helper.ts | 0 .../backend/src/libs/modules}/path/path.ts | 0 .../server-application/libs/enums/enums.ts | 0 .../libs/enums/exit-code.enum.ts | 0 .../get-default-error-info.helper.ts | 16 + .../get-error-info/get-error-info.helper.ts | 14 + .../get-validation-error-info.helper.ts | 26 ++ .../libs/helpers/helpers.ts | 1 + .../libs/types/api-error.type.ts | 6 + .../libs/types/error-info.type.ts | 11 + .../libs/types/server-app-api.type.ts | 7 + ...erver-application-route-parameters.type.ts | 15 +- .../server-application/libs/types/types.ts | 4 + .../server-application/server-app-api.ts | 28 ++ .../modules/server-application/server-app.ts | 161 ++++++++ .../server-application/server-application.ts | 24 +- apps/backend/src/libs/types/types.ts | 1 + apps/backend/src/main.ts | 3 + .../src/packages/auth/auth.controller.ts | 57 +++ .../backend/src/packages/auth/auth.service.ts | 26 ++ .../backend}/src/packages/auth/auth.ts | 22 +- .../src/packages/auth/helpers/crypt/crypt.ts | 1 + .../crypt/encrypt-sync/encrypt-sync.helper.ts | 9 + .../helpers/crypt/libs/constants/constants.ts | 1 + .../crypt/libs/constants/crypt.constant.ts | 3 + .../src/packages/auth/helpers/helpers.ts | 1 + .../src/packages/auth/libs/enums/enums.ts | 1 + .../auth/libs/types/auth-controller.type.ts | 20 + .../auth/libs/types/auth-service.type.ts | 10 + .../src/packages/auth/libs/types/types.ts | 7 + .../validation-schemas/validation-schemas.ts | 1 + .../src/packages/user/libs/enums/enums.ts | 3 +- .../src/packages/user/libs/types/types.ts | 3 + .../user/libs/types/user-repository.type.ts | 11 + .../user/libs/types/user-service.type.ts | 7 + apps/backend/src/packages/user/user.model.ts | 20 + .../src/packages/user/user.repository.ts | 32 ++ .../src/packages/user/user.service.ts | 12 +- .../backend}/src/packages/user/user.ts | 5 +- .../backend/tests/libs/constants/constants.ts | 3 + .../backend/tests/libs/modules}/app/app.ts | 0 .../helpers/build-app/build-app.helper.ts | 14 +- .../libs/modules}/app/libs/helpers/helpers.ts | 0 .../tests/libs/modules}/database/database.ts | 0 .../database/libs/constants/constants.ts | 0 .../database/libs/constants/crud.constant.ts | 0 .../clear-database/clear-database.helper.ts | 8 +- .../get-crud-handlers/get-crud-handlers.ts | 0 .../modules}/database/libs/helpers/helpers.ts | 0 .../libs/types/count-parameters.type.ts | 2 +- .../types/get-crud-handlers-function.type.ts | 0 .../libs/types/insert-parameters.type.ts | 2 +- .../libs/types/remove-parameters.type.ts | 2 +- .../libs/types/select-parameters.type.ts | 2 +- .../modules}/database/libs/types/types.ts | 0 .../libs/types/update-parameters.type.ts | 2 +- .../tests/modules/auth/auth.api.spec.ts | 204 ++++++++++ .../modules}/user/libs/constants/constants.ts | 0 .../test-user-credentials.constant.ts | 2 +- .../modules/user/libs}/helpers/helpers.ts | 0 .../setup-test-users.helper.ts | 6 +- .../backend/tests/modules}/user/user.ts | 2 +- {server => apps/backend}/tsconfig.json | 8 +- packages/shared/package.json | 2 +- packages/shared/src/index.ts | 22 +- packages/shared/src/libs/enums/enums.ts | 1 + .../src/libs/enums/server-error-type.enum.ts | 6 + .../shared/src/libs/exceptions/exceptions.ts | 2 +- .../http-error/http-error.exception.ts | 8 +- .../invalid-credentials-error.exception.ts | 10 - .../validation-error.exception.ts | 5 + packages/shared/src/libs/helpers/date/date.ts | 2 - .../src/libs/helpers/date/dayjs/dayjs.ts | 6 - .../helpers/date/get-diff/get-diff.helper.ts | 7 - .../get-from-now-time.helper.ts | 5 - packages/shared/src/libs/helpers/helpers.ts | 1 - packages/shared/src/libs/modules/http/http.ts | 2 +- .../src/libs/modules/http/libs/enums/enums.ts | 4 +- .../modules/http/libs/enums/http-code.enum.ts | 5 +- .../http/libs/enums/http-method.enum.ts | 4 +- packages/shared/src/libs/types/error/error.ts | 5 + .../types/error/server-error-detail.type.ts | 6 + .../types/error/server-error-response.type.ts | 25 ++ packages/shared/src/libs/types/types.ts | 5 + .../src/modules/user/libs/types/user.type.ts | 1 - server/knexfile.ts | 3 - .../20211208202419_create_tables.ts | 97 ----- .../20211208204457_add_associations.ts | 91 ----- server/src/db/seed-data/comments-seed.ts | 32 -- server/src/db/seed-data/posts-seed.ts | 21 - server/src/db/seeds/fill-database.ts | 109 ----- server/src/index.d.ts | 12 - server/src/libs/enums/enums.ts | 6 - server/src/libs/exceptions/exceptions.ts | 1 - .../middlewares/image/image.middleware.ts | 14 - server/src/libs/middlewares/middlewares.ts | 1 - server/src/libs/packages/config/config.ts | 9 - .../config/libs/types/config-package.type.ts | 7 - .../packages/controller/controller.api.ts | 33 -- .../libs/packages/controller/controller.ts | 3 - .../libs/types/controller-api.type.ts | 7 - .../packages/controller/libs/types/types.ts | 2 - server/src/libs/packages/database/database.ts | 11 - .../libs/enums/database-table-name.enum.ts | 9 - .../packages/database/libs/types/types.ts | 2 - server/src/libs/packages/http/http.service.ts | 49 --- server/src/libs/packages/http/http.ts | 7 - .../libs/packages/http/libs/enums/enums.ts | 5 - .../http/libs/types/http-load-options.type.ts | 13 - .../http/libs/types/http-service.type.ts | 7 - .../libs/packages/http/libs/types/types.ts | 2 - .../libs/constants/api.constants.ts | 10 - .../libs/constants/constants.ts | 1 - .../libs/types/server-app-api.type.ts | 7 - .../server-application/libs/types/types.ts | 1 - .../server-application/server-app-api.ts | 20 - .../packages/server-application/server-app.ts | 147 ------- .../libs/packages/socket/libs/enums/enums.ts | 5 - .../socket/libs/types/socket-service.type.ts | 7 - .../libs/packages/socket/libs/types/types.ts | 1 - .../libs/packages/socket/socket.service.ts | 34 -- server/src/libs/packages/socket/socket.ts | 11 - .../authorization/authorization.plugin.ts | 53 --- server/src/libs/plugins/plugins.ts | 2 - .../socket-injector/socket-injector.plugin.ts | 19 - server/src/libs/types/types.ts | 4 - server/src/main.ts | 3 - server/src/packages/auth/auth.controller.ts | 105 ----- server/src/packages/auth/auth.service.ts | 93 ----- .../crypt-compare/crypt-compare.helper.ts | 7 - .../src/packages/auth/helpers/crypt/crypt.ts | 3 - .../crypt/encrypt-sync/encrypt-sync.helper.ts | 9 - .../helpers/crypt/encrypt/encrypt.helper.ts | 9 - .../helpers/crypt/libs/constants/constants.ts | 1 - .../crypt/libs/constants/user.constants.ts | 3 - server/src/packages/auth/helpers/helpers.ts | 3 - .../get-error-status-code.helper.ts | 19 - server/src/packages/auth/helpers/http/http.ts | 1 - .../token/create-token/create-token.helper.ts | 11 - .../src/packages/auth/helpers/token/token.ts | 2 - .../token/verify-token/verify-token.helper.ts | 10 - server/src/packages/auth/libs/enums/enums.ts | 1 - .../auth/libs/types/auth-controller.type.ts | 24 -- .../auth/libs/types/auth-service.type.ts | 16 - server/src/packages/auth/libs/types/types.ts | 11 - .../validation-schemas/validation-schemas.ts | 4 - .../packages/comment/comment.controller.ts | 66 ---- server/src/packages/comment/comment.model.ts | 46 --- .../packages/comment/comment.repository.ts | 33 -- .../src/packages/comment/comment.service.ts | 35 -- server/src/packages/comment/comment.ts | 26 -- .../src/packages/comment/libs/enums/enums.ts | 4 - .../libs/types/comment-controller.type.ts | 19 - .../libs/types/comment-repository.type.ts | 9 - .../libs/types/comment-service.type.ts | 12 - .../src/packages/comment/libs/types/types.ts | 9 - server/src/packages/image/image.controller.ts | 45 --- server/src/packages/image/image.model.ts | 14 - server/src/packages/image/image.repository.ts | 20 - server/src/packages/image/image.service.ts | 55 --- server/src/packages/image/image.ts | 31 -- server/src/packages/image/libs/enums/enums.ts | 4 - .../image/libs/types/image-controller.type.ts | 9 - .../image/libs/types/image-repository.type.ts | 7 - .../image/libs/types/image-service.type.ts | 9 - server/src/packages/image/libs/types/types.ts | 7 - .../src/packages/password/libs/enums/enums.ts | 1 - server/src/packages/password/password.ts | 1 - server/src/packages/post/libs/enums/enums.ts | 5 - .../libs/helpers/get-comments-count-query.ts | 11 - .../post/libs/helpers/get-reactions-query.ts | 17 - .../libs/helpers/get-where-user-id-query.ts | 14 - .../src/packages/post/libs/helpers/helpers.ts | 3 - .../post/libs/types/post-controller.type.ts | 23 -- .../types/post-reaction-repository.type.ts | 18 - .../post/libs/types/post-repository.type.ts | 22 -- .../post/libs/types/post-service.type.ts | 23 -- server/src/packages/post/libs/types/types.ts | 18 - .../src/packages/post/post-reaction.model.ts | 47 --- .../packages/post/post-reaction.repository.ts | 35 -- server/src/packages/post/post.controller.ts | 116 ------ server/src/packages/post/post.model.ts | 68 ---- server/src/packages/post/post.repository.ts | 71 ---- server/src/packages/post/post.service.ts | 83 ---- server/src/packages/post/post.ts | 41 -- server/src/packages/user/libs/types/types.ts | 8 - .../user/libs/types/user-repository.type.ts | 19 - .../user/libs/types/user-service.type.ts | 8 - server/src/packages/user/user.model.ts | 59 --- server/src/packages/user/user.repository.ts | 65 --- server/tests/api/0-starter/auth.api.spec.ts | 373 ------------------ .../tests/api/0-starter/comment.api.spec.ts | 153 ------- server/tests/api/0-starter/image.api.spec.ts | 114 ------ server/tests/api/0-starter/post.api.spec.ts | 272 ------------- .../tests/api/1-dislike-post/post.api.spec.ts | 319 --------------- .../post-comment.api.spec.ts | 199 ---------- .../api/11-update-profile/user.api.spec.ts | 165 -------- .../12-set-user-status/auth-user.api.spec.ts | 153 ------- .../password.api.spec.ts | 226 ----------- .../tests/api/2-update-post/post.api.spec.ts | 145 ------- .../tests/api/3-delete-post/post.api.spec.ts | 177 --------- .../api/4-update-comment/comment.api.spec.ts | 148 ------- .../api/5-delete-comment/comment.api.spec.ts | 133 ------- .../comment.api.spec.ts | 322 --------------- .../7-show-hide-own-posts/post.api.spec.ts | 133 ------- .../post.api.spec.ts | 132 ------- .../9-show-who-liked-post/post.api.spec.ts | 159 -------- server/tests/data/images/test-image.png | Bin 35204 -> 0 bytes server/tests/libs/packages/http/http.ts | 1 - .../get-bearer-auth-header.helper.ts | 5 - .../packages/http/libs/helpers/helpers.ts | 1 - server/tests/packages/comment/comment.ts | 2 - .../tests/packages/comment/helpers/helpers.ts | 1 - .../setup-test-comments.helper.ts | 38 -- .../comment/libs/constants/constants.ts | 1 - .../libs/constants/test-comments.constant.ts | 11 - server/tests/packages/post/helpers/helpers.ts | 1 - .../setup-test-posts.helper.ts | 32 -- .../packages/post/libs/constants/constants.ts | 1 - .../libs/constants/test-posts.constant.ts | 17 - server/tests/packages/post/post.ts | 2 - 262 files changed, 1184 insertions(+), 6115 deletions(-) rename {server => apps/backend}/.env.example (72%) rename {server => apps/backend}/.eslintrc.yml (100%) rename {server => apps/backend}/jest.config.js (100%) create mode 100644 apps/backend/knexfile.ts rename {server => apps/backend}/package.json (54%) create mode 100644 apps/backend/src/db/migrations/20211208202419_create_tables.ts rename {server => apps/backend}/src/db/seed-data/users-seed.ts (66%) create mode 100644 apps/backend/src/db/seeds/fill-database.ts create mode 100644 apps/backend/src/libs/enums/enums.ts create mode 100644 apps/backend/src/libs/exceptions/exceptions.ts rename server/src/libs/packages/config/config.package.ts => apps/backend/src/libs/modules/config/config.module.ts (78%) create mode 100644 apps/backend/src/libs/modules/config/config.ts create mode 100644 apps/backend/src/libs/modules/config/libs/types/config-module.type.ts rename {server/src/libs/packages => apps/backend/src/libs/modules}/config/libs/types/environment-schema.type.ts (78%) rename {server/src/libs/packages => apps/backend/src/libs/modules}/config/libs/types/types.ts (52%) create mode 100644 apps/backend/src/libs/modules/controller/controller.module.ts create mode 100644 apps/backend/src/libs/modules/controller/controller.ts rename {server/src/libs/packages => apps/backend/src/libs/modules}/controller/libs/enums/controller-hook.enum.ts (100%) rename {server/src/libs/packages => apps/backend/src/libs/modules}/controller/libs/enums/enums.ts (100%) create mode 100644 apps/backend/src/libs/modules/controller/libs/types/controller-api-handler-options.type.ts create mode 100644 apps/backend/src/libs/modules/controller/libs/types/controller-api-handler-response.type.ts create mode 100644 apps/backend/src/libs/modules/controller/libs/types/controller-api-handler.type.ts create mode 100644 apps/backend/src/libs/modules/controller/libs/types/controller-module.type.ts create mode 100644 apps/backend/src/libs/modules/controller/libs/types/controller-route-parameters.type.ts create mode 100644 apps/backend/src/libs/modules/controller/libs/types/types.ts rename {server/src/libs/packages => apps/backend/src/libs/modules}/database/abstract.model.ts (100%) rename {server/src/libs/packages => apps/backend/src/libs/modules}/database/abstract.repository.ts (100%) rename server/src/libs/packages/database/database.package.ts => apps/backend/src/libs/modules/database/database.module.ts (70%) create mode 100644 apps/backend/src/libs/modules/database/database.ts create mode 100644 apps/backend/src/libs/modules/database/libs/enums/database-table-name.enum.ts rename {server/src/libs/packages => apps/backend/src/libs/modules}/database/libs/enums/enums.ts (100%) rename {server/src/libs/packages => apps/backend/src/libs/modules}/database/libs/types/database-package.type.ts (76%) rename {server/src/libs/packages => apps/backend/src/libs/modules}/database/libs/types/repository.type.ts (100%) create mode 100644 apps/backend/src/libs/modules/database/libs/types/types.ts create mode 100644 apps/backend/src/libs/modules/http/http.ts create mode 100644 apps/backend/src/libs/modules/http/libs/enums/enums.ts create mode 100644 apps/backend/src/libs/modules/logger/libs/types/logger-module.type.ts create mode 100644 apps/backend/src/libs/modules/logger/libs/types/types.ts create mode 100644 apps/backend/src/libs/modules/logger/logger.module.ts create mode 100644 apps/backend/src/libs/modules/logger/logger.ts rename {server/src/libs/packages => apps/backend/src/libs/modules}/path/libs/helpers/helpers.ts (100%) rename {server/src/libs/packages => apps/backend/src/libs/modules}/path/libs/helpers/join-path/join-path.helper.ts (100%) rename {server/src/libs/packages => apps/backend/src/libs/modules}/path/path.ts (100%) rename {server/src/libs/packages => apps/backend/src/libs/modules}/server-application/libs/enums/enums.ts (100%) rename {server/src/libs/packages => apps/backend/src/libs/modules}/server-application/libs/enums/exit-code.enum.ts (100%) create mode 100644 apps/backend/src/libs/modules/server-application/libs/helpers/get-error-info/get-default-error-info.helper.ts create mode 100644 apps/backend/src/libs/modules/server-application/libs/helpers/get-error-info/get-error-info.helper.ts create mode 100644 apps/backend/src/libs/modules/server-application/libs/helpers/get-error-info/get-validation-error-info.helper.ts create mode 100644 apps/backend/src/libs/modules/server-application/libs/helpers/helpers.ts create mode 100644 apps/backend/src/libs/modules/server-application/libs/types/api-error.type.ts create mode 100644 apps/backend/src/libs/modules/server-application/libs/types/error-info.type.ts create mode 100644 apps/backend/src/libs/modules/server-application/libs/types/server-app-api.type.ts rename server/src/libs/packages/controller/libs/types/controller-route.type.ts => apps/backend/src/libs/modules/server-application/libs/types/server-application-route-parameters.type.ts (52%) create mode 100644 apps/backend/src/libs/modules/server-application/libs/types/types.ts create mode 100644 apps/backend/src/libs/modules/server-application/server-app-api.ts create mode 100644 apps/backend/src/libs/modules/server-application/server-app.ts rename {server/src/libs/packages => apps/backend/src/libs/modules}/server-application/server-application.ts (54%) create mode 100644 apps/backend/src/libs/types/types.ts create mode 100644 apps/backend/src/main.ts create mode 100644 apps/backend/src/packages/auth/auth.controller.ts create mode 100644 apps/backend/src/packages/auth/auth.service.ts rename {server => apps/backend}/src/packages/auth/auth.ts (53%) create mode 100644 apps/backend/src/packages/auth/helpers/crypt/crypt.ts create mode 100644 apps/backend/src/packages/auth/helpers/crypt/encrypt-sync/encrypt-sync.helper.ts create mode 100644 apps/backend/src/packages/auth/helpers/crypt/libs/constants/constants.ts create mode 100644 apps/backend/src/packages/auth/helpers/crypt/libs/constants/crypt.constant.ts create mode 100644 apps/backend/src/packages/auth/helpers/helpers.ts create mode 100644 apps/backend/src/packages/auth/libs/enums/enums.ts create mode 100644 apps/backend/src/packages/auth/libs/types/auth-controller.type.ts create mode 100644 apps/backend/src/packages/auth/libs/types/auth-service.type.ts create mode 100644 apps/backend/src/packages/auth/libs/types/types.ts create mode 100644 apps/backend/src/packages/auth/libs/validation-schemas/validation-schemas.ts rename {server => apps/backend}/src/packages/user/libs/enums/enums.ts (54%) create mode 100644 apps/backend/src/packages/user/libs/types/types.ts create mode 100644 apps/backend/src/packages/user/libs/types/user-repository.type.ts create mode 100644 apps/backend/src/packages/user/libs/types/user-service.type.ts create mode 100644 apps/backend/src/packages/user/user.model.ts create mode 100644 apps/backend/src/packages/user/user.repository.ts rename {server => apps/backend}/src/packages/user/user.service.ts (61%) rename {server => apps/backend}/src/packages/user/user.ts (87%) create mode 100644 apps/backend/tests/libs/constants/constants.ts rename {server/tests/libs/packages => apps/backend/tests/libs/modules}/app/app.ts (100%) rename {server/tests/libs/packages => apps/backend/tests/libs/modules}/app/libs/helpers/build-app/build-app.helper.ts (75%) rename {server/tests/libs/packages => apps/backend/tests/libs/modules}/app/libs/helpers/helpers.ts (100%) rename {server/tests/libs/packages => apps/backend/tests/libs/modules}/database/database.ts (100%) rename {server/tests/libs/packages => apps/backend/tests/libs/modules}/database/libs/constants/constants.ts (100%) rename {server/tests/libs/packages => apps/backend/tests/libs/modules}/database/libs/constants/crud.constant.ts (100%) rename {server/tests/libs/packages => apps/backend/tests/libs/modules}/database/libs/helpers/clear-database/clear-database.helper.ts (67%) rename {server/tests/libs/packages => apps/backend/tests/libs/modules}/database/libs/helpers/get-crud-handlers/get-crud-handlers.ts (100%) rename {server/tests/libs/packages => apps/backend/tests/libs/modules}/database/libs/helpers/helpers.ts (100%) rename {server/tests/libs/packages => apps/backend/tests/libs/modules}/database/libs/types/count-parameters.type.ts (81%) rename {server/tests/libs/packages => apps/backend/tests/libs/modules}/database/libs/types/get-crud-handlers-function.type.ts (100%) rename {server/tests/libs/packages => apps/backend/tests/libs/modules}/database/libs/types/insert-parameters.type.ts (75%) rename {server/tests/libs/packages => apps/backend/tests/libs/modules}/database/libs/types/remove-parameters.type.ts (73%) rename {server/tests/libs/packages => apps/backend/tests/libs/modules}/database/libs/types/select-parameters.type.ts (87%) rename {server/tests/libs/packages => apps/backend/tests/libs/modules}/database/libs/types/types.ts (100%) rename {server/tests/libs/packages => apps/backend/tests/libs/modules}/database/libs/types/update-parameters.type.ts (76%) create mode 100644 apps/backend/tests/modules/auth/auth.api.spec.ts rename {server/tests/packages => apps/backend/tests/modules}/user/libs/constants/constants.ts (100%) rename {server/tests/packages => apps/backend/tests/modules}/user/libs/constants/test-user-credentials.constant.ts (85%) rename {server/tests/packages/user => apps/backend/tests/modules/user/libs}/helpers/helpers.ts (100%) rename {server/tests/packages/user => apps/backend/tests/modules/user/libs}/helpers/setup-test-users/setup-test-users.helper.ts (68%) rename {server/tests/packages => apps/backend/tests/modules}/user/user.ts (54%) rename {server => apps/backend}/tsconfig.json (53%) create mode 100644 packages/shared/src/libs/enums/server-error-type.enum.ts delete mode 100644 packages/shared/src/libs/exceptions/invalid-credentials-error/invalid-credentials-error.exception.ts create mode 100644 packages/shared/src/libs/exceptions/validation-error/validation-error.exception.ts delete mode 100644 packages/shared/src/libs/helpers/date/date.ts delete mode 100644 packages/shared/src/libs/helpers/date/dayjs/dayjs.ts delete mode 100644 packages/shared/src/libs/helpers/date/get-diff/get-diff.helper.ts delete mode 100644 packages/shared/src/libs/helpers/date/get-from-now-time/get-from-now-time.helper.ts delete mode 100644 packages/shared/src/libs/helpers/helpers.ts create mode 100644 packages/shared/src/libs/types/error/error.ts create mode 100644 packages/shared/src/libs/types/error/server-error-detail.type.ts create mode 100644 packages/shared/src/libs/types/error/server-error-response.type.ts delete mode 100644 server/knexfile.ts delete mode 100644 server/src/db/migrations/20211208202419_create_tables.ts delete mode 100644 server/src/db/migrations/20211208204457_add_associations.ts delete mode 100644 server/src/db/seed-data/comments-seed.ts delete mode 100644 server/src/db/seed-data/posts-seed.ts delete mode 100644 server/src/db/seeds/fill-database.ts delete mode 100644 server/src/index.d.ts delete mode 100644 server/src/libs/enums/enums.ts delete mode 100644 server/src/libs/exceptions/exceptions.ts delete mode 100644 server/src/libs/middlewares/image/image.middleware.ts delete mode 100644 server/src/libs/middlewares/middlewares.ts delete mode 100644 server/src/libs/packages/config/config.ts delete mode 100644 server/src/libs/packages/config/libs/types/config-package.type.ts delete mode 100644 server/src/libs/packages/controller/controller.api.ts delete mode 100644 server/src/libs/packages/controller/controller.ts delete mode 100644 server/src/libs/packages/controller/libs/types/controller-api.type.ts delete mode 100644 server/src/libs/packages/controller/libs/types/types.ts delete mode 100644 server/src/libs/packages/database/database.ts delete mode 100644 server/src/libs/packages/database/libs/enums/database-table-name.enum.ts delete mode 100644 server/src/libs/packages/database/libs/types/types.ts delete mode 100644 server/src/libs/packages/http/http.service.ts delete mode 100644 server/src/libs/packages/http/http.ts delete mode 100644 server/src/libs/packages/http/libs/enums/enums.ts delete mode 100644 server/src/libs/packages/http/libs/types/http-load-options.type.ts delete mode 100644 server/src/libs/packages/http/libs/types/http-service.type.ts delete mode 100644 server/src/libs/packages/http/libs/types/types.ts delete mode 100644 server/src/libs/packages/server-application/libs/constants/api.constants.ts delete mode 100644 server/src/libs/packages/server-application/libs/constants/constants.ts delete mode 100644 server/src/libs/packages/server-application/libs/types/server-app-api.type.ts delete mode 100644 server/src/libs/packages/server-application/libs/types/types.ts delete mode 100644 server/src/libs/packages/server-application/server-app-api.ts delete mode 100644 server/src/libs/packages/server-application/server-app.ts delete mode 100644 server/src/libs/packages/socket/libs/enums/enums.ts delete mode 100644 server/src/libs/packages/socket/libs/types/socket-service.type.ts delete mode 100644 server/src/libs/packages/socket/libs/types/types.ts delete mode 100644 server/src/libs/packages/socket/socket.service.ts delete mode 100644 server/src/libs/packages/socket/socket.ts delete mode 100644 server/src/libs/plugins/authorization/authorization.plugin.ts delete mode 100644 server/src/libs/plugins/plugins.ts delete mode 100644 server/src/libs/plugins/socket-injector/socket-injector.plugin.ts delete mode 100644 server/src/libs/types/types.ts delete mode 100644 server/src/main.ts delete mode 100644 server/src/packages/auth/auth.controller.ts delete mode 100644 server/src/packages/auth/auth.service.ts delete mode 100644 server/src/packages/auth/helpers/crypt/crypt-compare/crypt-compare.helper.ts delete mode 100644 server/src/packages/auth/helpers/crypt/crypt.ts delete mode 100644 server/src/packages/auth/helpers/crypt/encrypt-sync/encrypt-sync.helper.ts delete mode 100644 server/src/packages/auth/helpers/crypt/encrypt/encrypt.helper.ts delete mode 100644 server/src/packages/auth/helpers/crypt/libs/constants/constants.ts delete mode 100644 server/src/packages/auth/helpers/crypt/libs/constants/user.constants.ts delete mode 100644 server/src/packages/auth/helpers/helpers.ts delete mode 100644 server/src/packages/auth/helpers/http/get-error-status-code/get-error-status-code.helper.ts delete mode 100644 server/src/packages/auth/helpers/http/http.ts delete mode 100644 server/src/packages/auth/helpers/token/create-token/create-token.helper.ts delete mode 100644 server/src/packages/auth/helpers/token/token.ts delete mode 100644 server/src/packages/auth/helpers/token/verify-token/verify-token.helper.ts delete mode 100644 server/src/packages/auth/libs/enums/enums.ts delete mode 100644 server/src/packages/auth/libs/types/auth-controller.type.ts delete mode 100644 server/src/packages/auth/libs/types/auth-service.type.ts delete mode 100644 server/src/packages/auth/libs/types/types.ts delete mode 100644 server/src/packages/auth/libs/validation-schemas/validation-schemas.ts delete mode 100644 server/src/packages/comment/comment.controller.ts delete mode 100644 server/src/packages/comment/comment.model.ts delete mode 100644 server/src/packages/comment/comment.repository.ts delete mode 100644 server/src/packages/comment/comment.service.ts delete mode 100644 server/src/packages/comment/comment.ts delete mode 100644 server/src/packages/comment/libs/enums/enums.ts delete mode 100644 server/src/packages/comment/libs/types/comment-controller.type.ts delete mode 100644 server/src/packages/comment/libs/types/comment-repository.type.ts delete mode 100644 server/src/packages/comment/libs/types/comment-service.type.ts delete mode 100644 server/src/packages/comment/libs/types/types.ts delete mode 100644 server/src/packages/image/image.controller.ts delete mode 100644 server/src/packages/image/image.model.ts delete mode 100644 server/src/packages/image/image.repository.ts delete mode 100644 server/src/packages/image/image.service.ts delete mode 100644 server/src/packages/image/image.ts delete mode 100644 server/src/packages/image/libs/enums/enums.ts delete mode 100644 server/src/packages/image/libs/types/image-controller.type.ts delete mode 100644 server/src/packages/image/libs/types/image-repository.type.ts delete mode 100644 server/src/packages/image/libs/types/image-service.type.ts delete mode 100644 server/src/packages/image/libs/types/types.ts delete mode 100644 server/src/packages/password/libs/enums/enums.ts delete mode 100644 server/src/packages/password/password.ts delete mode 100644 server/src/packages/post/libs/enums/enums.ts delete mode 100644 server/src/packages/post/libs/helpers/get-comments-count-query.ts delete mode 100644 server/src/packages/post/libs/helpers/get-reactions-query.ts delete mode 100644 server/src/packages/post/libs/helpers/get-where-user-id-query.ts delete mode 100644 server/src/packages/post/libs/helpers/helpers.ts delete mode 100644 server/src/packages/post/libs/types/post-controller.type.ts delete mode 100644 server/src/packages/post/libs/types/post-reaction-repository.type.ts delete mode 100644 server/src/packages/post/libs/types/post-repository.type.ts delete mode 100644 server/src/packages/post/libs/types/post-service.type.ts delete mode 100644 server/src/packages/post/libs/types/types.ts delete mode 100644 server/src/packages/post/post-reaction.model.ts delete mode 100644 server/src/packages/post/post-reaction.repository.ts delete mode 100644 server/src/packages/post/post.controller.ts delete mode 100644 server/src/packages/post/post.model.ts delete mode 100644 server/src/packages/post/post.repository.ts delete mode 100644 server/src/packages/post/post.service.ts delete mode 100644 server/src/packages/post/post.ts delete mode 100644 server/src/packages/user/libs/types/types.ts delete mode 100644 server/src/packages/user/libs/types/user-repository.type.ts delete mode 100644 server/src/packages/user/libs/types/user-service.type.ts delete mode 100644 server/src/packages/user/user.model.ts delete mode 100644 server/src/packages/user/user.repository.ts delete mode 100644 server/tests/api/0-starter/auth.api.spec.ts delete mode 100644 server/tests/api/0-starter/comment.api.spec.ts delete mode 100644 server/tests/api/0-starter/image.api.spec.ts delete mode 100644 server/tests/api/0-starter/post.api.spec.ts delete mode 100644 server/tests/api/1-dislike-post/post.api.spec.ts delete mode 100644 server/tests/api/10-show-who-liked-comment/post-comment.api.spec.ts delete mode 100644 server/tests/api/11-update-profile/user.api.spec.ts delete mode 100644 server/tests/api/12-set-user-status/auth-user.api.spec.ts delete mode 100644 server/tests/api/13-reset-set-password/password.api.spec.ts delete mode 100644 server/tests/api/2-update-post/post.api.spec.ts delete mode 100644 server/tests/api/3-delete-post/post.api.spec.ts delete mode 100644 server/tests/api/4-update-comment/comment.api.spec.ts delete mode 100644 server/tests/api/5-delete-comment/comment.api.spec.ts delete mode 100644 server/tests/api/6-like-dislike-comment/comment.api.spec.ts delete mode 100644 server/tests/api/7-show-hide-own-posts/post.api.spec.ts delete mode 100644 server/tests/api/8-show-liked-by-own-posts/post.api.spec.ts delete mode 100644 server/tests/api/9-show-who-liked-post/post.api.spec.ts delete mode 100644 server/tests/data/images/test-image.png delete mode 100644 server/tests/libs/packages/http/http.ts delete mode 100644 server/tests/libs/packages/http/libs/helpers/get-bearer-auth-header/get-bearer-auth-header.helper.ts delete mode 100644 server/tests/libs/packages/http/libs/helpers/helpers.ts delete mode 100644 server/tests/packages/comment/comment.ts delete mode 100644 server/tests/packages/comment/helpers/helpers.ts delete mode 100644 server/tests/packages/comment/helpers/setup-test-comments/setup-test-comments.helper.ts delete mode 100644 server/tests/packages/comment/libs/constants/constants.ts delete mode 100644 server/tests/packages/comment/libs/constants/test-comments.constant.ts delete mode 100644 server/tests/packages/post/helpers/helpers.ts delete mode 100644 server/tests/packages/post/helpers/setup-test-posts/setup-test-posts.helper.ts delete mode 100644 server/tests/packages/post/libs/constants/constants.ts delete mode 100644 server/tests/packages/post/libs/constants/test-posts.constant.ts delete mode 100644 server/tests/packages/post/post.ts diff --git a/server/.env.example b/apps/backend/.env.example similarity index 72% rename from server/.env.example rename to apps/backend/.env.example index 2c7e5f0b..4d1220fd 100644 --- a/server/.env.example +++ b/apps/backend/.env.example @@ -25,14 +25,3 @@ DB_CLIENT=pg DB_POOL_MIN=1 DB_POOL_MAX=10 -# -# AUTHENTICATION -# -# SECRET_KEY has to be changed to own random secret key -SECRET_KEY=secretkeysecretkeysecretkey - -# Image Storage -# -# GYAZO_ACCESS_TOKEN - has to be changed to a real key from Gyazo -GYAZO_UPLOAD_API_URL=https://upload.gyazo.com/api/upload -GYAZO_ACCESS_TOKEN=gyazoaccesstoken diff --git a/server/.eslintrc.yml b/apps/backend/.eslintrc.yml similarity index 100% rename from server/.eslintrc.yml rename to apps/backend/.eslintrc.yml diff --git a/server/jest.config.js b/apps/backend/jest.config.js similarity index 100% rename from server/jest.config.js rename to apps/backend/jest.config.js diff --git a/apps/backend/knexfile.ts b/apps/backend/knexfile.ts new file mode 100644 index 00000000..9f307a1a --- /dev/null +++ b/apps/backend/knexfile.ts @@ -0,0 +1,3 @@ +import { database } from '~/libs/modules/database/database.js'; + +export default database.environmentsConfig; diff --git a/server/package.json b/apps/backend/package.json similarity index 54% rename from server/package.json rename to apps/backend/package.json index 14d1ed55..570ff2e4 100644 --- a/server/package.json +++ b/apps/backend/package.json @@ -1,5 +1,5 @@ { - "name": "server", + "name": "backend", "private": true, "engines": { "node": "18.18.x", @@ -20,25 +20,13 @@ "lint": "npm run lint:js", "build": "tsc && tsc-alias", "pretest": "cross-env NODE_ENV=test npm run migrate:dev", - "test": "cross-env NODE_ENV=test node --experimental-vm-modules --expose-gc --no-compilation-cache ../node_modules/jest/bin/jest.js --config jest.config.js --runInBand --forceExit --detectOpenHandles", - "test:starter": "npm run test -- --verbose --rootDir=tests/api/0-starter/", - "test:dislike-post": "npm run test -- --verbose --rootDir=tests/api/1-dislike-post/", - "test:update-post": "npm run test -- --verbose --rootDir=tests/api/2-update-post/", - "test:delete-post": "npm run test -- --verbose --rootDir=tests/api/3-delete-post/", - "test:update-comment": "npm run test -- --verbose --rootDir=tests/api/4-update-comment/", - "test:delete-comment": "npm run test -- --verbose --rootDir=tests/api/5-delete-comment/", - "test:like-dislike-comment": "npm run test -- --verbose --rootDir=tests/api/6-like-dislike-comment/", - "test:show-hide-own-posts": "npm run test -- --verbose --rootDir=tests/api/7-show-hide-own-posts/", - "test:show-liked-by-own-posts": "npm run test -- --verbose --rootDir=tests/api/8-show-liked-by-own-posts/", - "test:show-who-liked-post": "npm run test -- --verbose --rootDir=tests/api/9-show-who-liked-post/", - "test:show-who-liked-comment": "npm run test -- --verbose --rootDir=tests/api/10-show-who-liked-comment/", - "test:update-profile": "npm run test -- --verbose --rootDir=tests/api/11-update-profile/", - "test:set-user-status": "npm run test -- --verbose --rootDir=tests/api/12-set-user-status/", - "test:reset-set-password": "npm run test -- --verbose --rootDir=tests/api/13-reset-set-password/" + "test": "cross-env NODE_ENV=test node --experimental-vm-modules --expose-gc --no-compilation-cache ../../node_modules/jest/bin/jest.js --config jest.config.js --runInBand --forceExit --detectOpenHandles", + "test:auth": "npm run test -- --verbose --rootDir=tests/modules/auth/" }, "dependencies": { "@fastify/cors": "8.4.2", "@fastify/static": "6.12.0", + "@thread-js/shared": "file:../../packages/shared", "axios": "1.6.2", "bcrypt": "5.1.1", "convict": "6.2.4", @@ -50,7 +38,7 @@ "jsonwebtoken": "9.0.2", "knex": "3.1.0", "objection": "3.1.3", - "pg": "8.11.3", + "pg": "8.7.3", "pg-hstore": "2.3.4", "qs": "6.11.2", "socket.io": "4.7.2" @@ -71,6 +59,7 @@ "npm": "10.2.5", "pino-pretty": "10.3.0", "ts-jest": "29.1.1", + "ts-node": "10.9.2", "ts-paths-esm-loader": "1.4.3" } } diff --git a/apps/backend/src/db/migrations/20211208202419_create_tables.ts b/apps/backend/src/db/migrations/20211208202419_create_tables.ts new file mode 100644 index 00000000..3864877c --- /dev/null +++ b/apps/backend/src/db/migrations/20211208202419_create_tables.ts @@ -0,0 +1,34 @@ +import { type Knex } from 'knex'; + +const TableName = { + USERS: 'users' +} as const; + +const ColumnName = { + CREATED_AT: 'created_at', + EMAIL: 'email', + ID: 'id', + PASSWORD: 'password', + UPDATED_AT: 'updated_at', + USERNAME: 'username' +} as const; + +export async function up(knex: Knex): Promise { + await knex.schema.createTable(TableName.USERS, table => { + table.increments(ColumnName.ID).primary(); + table.string(ColumnName.EMAIL).notNullable().unique(); + table.string(ColumnName.USERNAME).notNullable().unique(); + table.string(ColumnName.PASSWORD).notNullable(); + table + .dateTime(ColumnName.CREATED_AT) + .notNullable() + .defaultTo(knex.fn.now()); + table + .dateTime(ColumnName.UPDATED_AT) + .notNullable() + .defaultTo(knex.fn.now()); + }); +} +export async function down(knex: Knex): Promise { + await knex.schema.dropTableIfExists(TableName.USERS); +} diff --git a/server/src/db/seed-data/users-seed.ts b/apps/backend/src/db/seed-data/users-seed.ts similarity index 66% rename from server/src/db/seed-data/users-seed.ts rename to apps/backend/src/db/seed-data/users-seed.ts index 9f6e3c87..c08ed505 100644 --- a/server/src/db/seed-data/users-seed.ts +++ b/apps/backend/src/db/seed-data/users-seed.ts @@ -30,20 +30,4 @@ const usersSeed = [ } ]; -// Do not add more images than the number of users. -const userImagesSeed = [ - { - link: 'https://i.imgur.com/RS2wGch.png' - }, - { - link: 'https://i.imgur.com/7V9tqy6.png' - }, - { - link: 'https://i.imgur.com/PhlZpUd.png' - }, - { - link: 'https://i.imgur.com/3KHckHc.png' - } -]; - -export { userImagesSeed, usersSeed }; +export { usersSeed }; diff --git a/apps/backend/src/db/seeds/fill-database.ts b/apps/backend/src/db/seeds/fill-database.ts new file mode 100644 index 00000000..21162432 --- /dev/null +++ b/apps/backend/src/db/seeds/fill-database.ts @@ -0,0 +1,15 @@ +import { type Knex } from 'knex'; + +import { usersSeed } from '../seed-data/users-seed.js'; + +const TableName = { + USERS: 'users' +} as const; + +export async function seed(knex: Knex): Promise { + await knex.transaction(async trx => { + await trx(TableName.USERS).del(); + + await trx(TableName.USERS).insert(usersSeed).returning('*'); + }); +} diff --git a/apps/backend/src/libs/enums/enums.ts b/apps/backend/src/libs/enums/enums.ts new file mode 100644 index 00000000..898a1d9c --- /dev/null +++ b/apps/backend/src/libs/enums/enums.ts @@ -0,0 +1,7 @@ +export { + APIPath, + AppEnvironment, + ExceptionMessage, + ExceptionName, + ServerErrorType +} from '@thread-js/shared'; diff --git a/apps/backend/src/libs/exceptions/exceptions.ts b/apps/backend/src/libs/exceptions/exceptions.ts new file mode 100644 index 00000000..b4badd3b --- /dev/null +++ b/apps/backend/src/libs/exceptions/exceptions.ts @@ -0,0 +1 @@ +export { ValidationError } from '@thread-js/shared'; diff --git a/server/src/libs/packages/config/config.package.ts b/apps/backend/src/libs/modules/config/config.module.ts similarity index 78% rename from server/src/libs/packages/config/config.package.ts rename to apps/backend/src/libs/modules/config/config.module.ts index c43e0f68..d4e3ed0a 100644 --- a/server/src/libs/packages/config/config.package.ts +++ b/apps/backend/src/libs/modules/config/config.module.ts @@ -4,18 +4,28 @@ import { config } from 'dotenv'; import { AppEnvironment } from '~/libs/enums/enums.js'; import { - type ConfigPackage, + type ConfigModule, type EnvironmentSchema } from './libs/types/types.js'; +import { LoggerModule } from '../logger/logger.js'; -class Config implements ConfigPackage { +type Constructor = { logger: LoggerModule }; + +class Config implements ConfigModule { + #logger: LoggerModule; #ENV: EnvironmentSchema; - public constructor() { + public constructor({ logger }: Constructor) { config(); + this.#logger = logger; this.#envSchema.load({}); - this.#envSchema.validate({ allowed: 'strict' }); + this.#envSchema.validate({ + allowed: 'strict', + output: message => { + this.#logger.info(message); + } + }); this.#ENV = this.#envSchema.getProperties(); } @@ -46,15 +56,6 @@ class Config implements ConfigPackage { default: null } }, - JWT: { - SECRET: { - doc: 'Secret key for token generation', - format: String, - env: 'SECRET_KEY', - default: null - }, - EXPIRES_IN: '24h' - }, DB: { DATABASE: { doc: 'Database name', @@ -115,21 +116,6 @@ class Config implements ConfigPackage { format: Boolean, default: false } - }, - GYAZO: { - ACCESS_KEY: { - doc: 'Gyazo access key', - format: String, - env: 'GYAZO_ACCESS_TOKEN', - default: null - }, - UPLOAD_API_URL: { - doc: 'Gyazo upload api url', - format: String, - env: 'GYAZO_UPLOAD_API_URL', - default: null - }, - FILE_SIZE: 10_000_000 } }); } diff --git a/apps/backend/src/libs/modules/config/config.ts b/apps/backend/src/libs/modules/config/config.ts new file mode 100644 index 00000000..9e6d4c23 --- /dev/null +++ b/apps/backend/src/libs/modules/config/config.ts @@ -0,0 +1,10 @@ +import { logger } from '../logger/logger.js'; +import { Config } from './config.module.js'; + +const config = new Config({ logger }); + +export { config }; +export { + type ConfigModule, + type EnvironmentSchema +} from './libs/types/types.js'; diff --git a/apps/backend/src/libs/modules/config/libs/types/config-module.type.ts b/apps/backend/src/libs/modules/config/libs/types/config-module.type.ts new file mode 100644 index 00000000..f3ed76be --- /dev/null +++ b/apps/backend/src/libs/modules/config/libs/types/config-module.type.ts @@ -0,0 +1,7 @@ +import { type Configurable } from '@thread-js/shared'; + +import { type EnvironmentSchema } from './types.js'; + +type ConfigModule = Configurable; + +export { type ConfigModule }; diff --git a/server/src/libs/packages/config/libs/types/environment-schema.type.ts b/apps/backend/src/libs/modules/config/libs/types/environment-schema.type.ts similarity index 78% rename from server/src/libs/packages/config/libs/types/environment-schema.type.ts rename to apps/backend/src/libs/modules/config/libs/types/environment-schema.type.ts index ed1e3088..37545a40 100644 --- a/server/src/libs/packages/config/libs/types/environment-schema.type.ts +++ b/apps/backend/src/libs/modules/config/libs/types/environment-schema.type.ts @@ -20,15 +20,6 @@ type EnvironmentSchema = { CLIENT: string; DEBUG: boolean; }; - JWT: { - SECRET: string; - EXPIRES_IN: string; - }; - GYAZO: { - ACCESS_KEY: string; - UPLOAD_API_URL: string; - FILE_SIZE: number; - }; }; export { type EnvironmentSchema }; diff --git a/server/src/libs/packages/config/libs/types/types.ts b/apps/backend/src/libs/modules/config/libs/types/types.ts similarity index 52% rename from server/src/libs/packages/config/libs/types/types.ts rename to apps/backend/src/libs/modules/config/libs/types/types.ts index dc8534ca..5a4a2e89 100644 --- a/server/src/libs/packages/config/libs/types/types.ts +++ b/apps/backend/src/libs/modules/config/libs/types/types.ts @@ -1,2 +1,2 @@ -export { type ConfigPackage } from './config-package.type.js'; +export { type ConfigModule } from './config-module.type.js'; export { type EnvironmentSchema } from './environment-schema.type.js'; diff --git a/apps/backend/src/libs/modules/controller/controller.module.ts b/apps/backend/src/libs/modules/controller/controller.module.ts new file mode 100644 index 00000000..56e069af --- /dev/null +++ b/apps/backend/src/libs/modules/controller/controller.module.ts @@ -0,0 +1,68 @@ +import { joinPath } from '~/libs/modules/path/path.js'; +import { + ControllerAPIHandler, + ControllerAPIHandlerOptions, + ControllerModule, + ControllerRouteParameters +} from './libs/types/types.js'; +import { LoggerModule } from '../logger/logger.js'; +import { ServerApplicationRouteParameters } from '../server-application/server-application.js'; + +type Constructor = { + apiPath: string; + logger: LoggerModule; +}; + +class Controller implements ControllerModule { + #apiPath: string; + + #routes: ServerApplicationRouteParameters[] = []; + + #logger: LoggerModule; + + public constructor({ logger, apiPath }: Constructor) { + this.#logger = logger; + this.#apiPath = apiPath; + } + + public get routes(): ServerApplicationRouteParameters[] { + return this.#routes; + } + + private async mapHandler( + handler: ControllerAPIHandler, + request: Parameters[0], + reply: Parameters[1] + ): Promise { + this.#logger.info(`${request.method.toUpperCase()} on ${request.url}`); + + const handlerOptions = this.mapRequest(request); + const { payload, status } = await handler(handlerOptions); + + return await reply.status(status).send(payload); + } + + private mapRequest( + request: Parameters[0] + ): ControllerAPIHandlerOptions { + const { body, params, query } = request; + + return { + body, + params, + query + }; + } + + public addRoute(options: ControllerRouteParameters): void { + const { handler, url } = options; + + this.#routes.push({ + ...options, + handler: (request, reply) => this.mapHandler(handler, request, reply), + url: joinPath([this.#apiPath, url]) + }); + } +} + +export { Controller }; diff --git a/apps/backend/src/libs/modules/controller/controller.ts b/apps/backend/src/libs/modules/controller/controller.ts new file mode 100644 index 00000000..9756c348 --- /dev/null +++ b/apps/backend/src/libs/modules/controller/controller.ts @@ -0,0 +1,7 @@ +export { Controller } from './controller.module.js'; +export { ControllerHook } from './libs/enums/enums.js'; +export { + type ControllerAPIHandler, + type ControllerAPIHandlerOptions, + type ControllerAPIHandlerResponse +} from './libs/types/types.js'; diff --git a/server/src/libs/packages/controller/libs/enums/controller-hook.enum.ts b/apps/backend/src/libs/modules/controller/libs/enums/controller-hook.enum.ts similarity index 100% rename from server/src/libs/packages/controller/libs/enums/controller-hook.enum.ts rename to apps/backend/src/libs/modules/controller/libs/enums/controller-hook.enum.ts diff --git a/server/src/libs/packages/controller/libs/enums/enums.ts b/apps/backend/src/libs/modules/controller/libs/enums/enums.ts similarity index 100% rename from server/src/libs/packages/controller/libs/enums/enums.ts rename to apps/backend/src/libs/modules/controller/libs/enums/enums.ts diff --git a/apps/backend/src/libs/modules/controller/libs/types/controller-api-handler-options.type.ts b/apps/backend/src/libs/modules/controller/libs/types/controller-api-handler-options.type.ts new file mode 100644 index 00000000..8e9f8aa7 --- /dev/null +++ b/apps/backend/src/libs/modules/controller/libs/types/controller-api-handler-options.type.ts @@ -0,0 +1,15 @@ +type DefaultApiHandlerOptions = { + body?: unknown; + query?: unknown; + params?: unknown; +}; + +type ControllerAPIHandlerOptions< + T extends DefaultApiHandlerOptions = DefaultApiHandlerOptions +> = { + body: T['body']; + query: T['query']; + params: T['params']; +}; + +export { type ControllerAPIHandlerOptions }; diff --git a/apps/backend/src/libs/modules/controller/libs/types/controller-api-handler-response.type.ts b/apps/backend/src/libs/modules/controller/libs/types/controller-api-handler-response.type.ts new file mode 100644 index 00000000..62177c5a --- /dev/null +++ b/apps/backend/src/libs/modules/controller/libs/types/controller-api-handler-response.type.ts @@ -0,0 +1,9 @@ +import { HTTPCode } from '~/libs/modules/http/http.js'; +import { type ValueOf } from '~/libs/types/types.js'; + +type ControllerAPIHandlerResponse = { + status: ValueOf; + payload: T; +}; + +export { type ControllerAPIHandlerResponse }; diff --git a/apps/backend/src/libs/modules/controller/libs/types/controller-api-handler.type.ts b/apps/backend/src/libs/modules/controller/libs/types/controller-api-handler.type.ts new file mode 100644 index 00000000..ba681608 --- /dev/null +++ b/apps/backend/src/libs/modules/controller/libs/types/controller-api-handler.type.ts @@ -0,0 +1,8 @@ +import { type ControllerAPIHandlerOptions } from './controller-api-handler-options.type.js'; +import { type ControllerAPIHandlerResponse } from './controller-api-handler-response.type.js'; + +type ControllerAPIHandler = ( + options: ControllerAPIHandlerOptions +) => ControllerAPIHandlerResponse | Promise; + +export { type ControllerAPIHandler }; diff --git a/apps/backend/src/libs/modules/controller/libs/types/controller-module.type.ts b/apps/backend/src/libs/modules/controller/libs/types/controller-module.type.ts new file mode 100644 index 00000000..c7d7639e --- /dev/null +++ b/apps/backend/src/libs/modules/controller/libs/types/controller-module.type.ts @@ -0,0 +1,9 @@ +import { ServerApplicationRouteParameters } from '~/libs/modules/server-application/libs/types/types.js'; +import { ControllerRouteParameters } from './controller-route-parameters.type.js'; + +type ControllerModule = { + routes: ServerApplicationRouteParameters[]; + addRoute(options: ControllerRouteParameters): void; +}; + +export { type ControllerModule }; diff --git a/apps/backend/src/libs/modules/controller/libs/types/controller-route-parameters.type.ts b/apps/backend/src/libs/modules/controller/libs/types/controller-route-parameters.type.ts new file mode 100644 index 00000000..26710694 --- /dev/null +++ b/apps/backend/src/libs/modules/controller/libs/types/controller-route-parameters.type.ts @@ -0,0 +1,16 @@ +import { HTTPMethod } from '~/libs/modules/http/http.js'; +import { type ValidationSchema, type ValueOf } from '~/libs/types/types.js'; +import { ControllerAPIHandler } from './controller-api-handler.type.js'; + +type ControllerRouteParameters = { + url: string; + method: ValueOf; + handler: ControllerAPIHandler; + schema?: { + body?: ValidationSchema; + params?: ValidationSchema; + query?: ValidationSchema; + }; +}; + +export { type ControllerRouteParameters }; diff --git a/apps/backend/src/libs/modules/controller/libs/types/types.ts b/apps/backend/src/libs/modules/controller/libs/types/types.ts new file mode 100644 index 00000000..3349dc91 --- /dev/null +++ b/apps/backend/src/libs/modules/controller/libs/types/types.ts @@ -0,0 +1,5 @@ +export { type ControllerModule } from './controller-module.type.js'; +export { type ControllerRouteParameters } from './controller-route-parameters.type.js'; +export { type ControllerAPIHandler } from './controller-api-handler.type.js'; +export { type ControllerAPIHandlerOptions } from './controller-api-handler-options.type.js'; +export { type ControllerAPIHandlerResponse } from './controller-api-handler-response.type.js'; diff --git a/server/src/libs/packages/database/abstract.model.ts b/apps/backend/src/libs/modules/database/abstract.model.ts similarity index 100% rename from server/src/libs/packages/database/abstract.model.ts rename to apps/backend/src/libs/modules/database/abstract.model.ts diff --git a/server/src/libs/packages/database/abstract.repository.ts b/apps/backend/src/libs/modules/database/abstract.repository.ts similarity index 100% rename from server/src/libs/packages/database/abstract.repository.ts rename to apps/backend/src/libs/modules/database/abstract.repository.ts diff --git a/server/src/libs/packages/database/database.package.ts b/apps/backend/src/libs/modules/database/database.module.ts similarity index 70% rename from server/src/libs/packages/database/database.package.ts rename to apps/backend/src/libs/modules/database/database.module.ts index 044c599e..8a4352b9 100644 --- a/server/src/libs/packages/database/database.package.ts +++ b/apps/backend/src/libs/modules/database/database.module.ts @@ -1,39 +1,39 @@ -import * as LibraryKnex from 'knex'; +import LibraryKnex from 'knex'; import { knexSnakeCaseMappers, Model } from 'objection'; import { AppEnvironment } from '~/libs/enums/enums.js'; import { type ValueOf } from '~/libs/types/types.js'; -import { type ConfigPackage } from '../config/config.js'; -import { type DatabasePackage } from './libs/types/types.js'; - -/** - * @description Type 'typeof import("PATH_TO_PROJECT/node_modules/knex/types/index")' has no call signatures. Issue: https://github.com/knex/knex/issues/5358 - */ -const { knex: Knex } = LibraryKnex.default; +import { type ConfigModule } from '../config/config.js'; +import { type DatabaseModule } from './libs/types/types.js'; +import { LoggerModule } from '../logger/logger.js'; type Constructor = { - config: ConfigPackage; + config: ConfigModule; + logger: LoggerModule; }; -class Database implements DatabasePackage { - #config: ConfigPackage; +class Database implements DatabaseModule { + #config: ConfigModule; + + #logger: LoggerModule; #knex!: LibraryKnex.Knex; - public constructor({ config }: Constructor) { + public constructor({ config, logger }: Constructor) { this.#config = config; + this.#logger = logger; } - public get knex(): LibraryKnex.Knex { - return this.#knex; - } + public async connect(): Promise { + this.#logger.info('Establish DB connection...'); - public connect(): void { - const knex = Knex(this.environmentConfig); - Model.knex(knex); + this.#knex = LibraryKnex.default(this.environmentConfig); - this.#knex = knex; + await this.#knex.raw('SELECT VERSION()'); + this.#logger.info('DB connection established successfully!'); + + Model.knex(this.#knex); } public get environmentsConfig(): Record< @@ -56,6 +56,10 @@ class Database implements DatabasePackage { }; } + public get knex(): LibraryKnex.Knex { + return this.#knex; + } + public get initialConfig(): LibraryKnex.Knex.Config { const { DATABASE: database, diff --git a/apps/backend/src/libs/modules/database/database.ts b/apps/backend/src/libs/modules/database/database.ts new file mode 100644 index 00000000..89b065a1 --- /dev/null +++ b/apps/backend/src/libs/modules/database/database.ts @@ -0,0 +1,12 @@ +import { config } from '~/libs/modules/config/config.js'; + +import { Database } from './database.module.js'; +import { logger } from '../logger/logger.js'; + +const database = new Database({ config, logger }); + +export { database }; +export { Abstract as AbstractModel } from './abstract.model.js'; +export { Abstract as AbstractRepository } from './abstract.repository.js'; +export { DatabaseTableName } from './libs/enums/enums.js'; +export { type DatabaseModule, type Repository } from './libs/types/types.js'; diff --git a/apps/backend/src/libs/modules/database/libs/enums/database-table-name.enum.ts b/apps/backend/src/libs/modules/database/libs/enums/database-table-name.enum.ts new file mode 100644 index 00000000..f7561fd7 --- /dev/null +++ b/apps/backend/src/libs/modules/database/libs/enums/database-table-name.enum.ts @@ -0,0 +1,5 @@ +const DatabaseTableName = { + USERS: 'users' +} as const; + +export { DatabaseTableName }; diff --git a/server/src/libs/packages/database/libs/enums/enums.ts b/apps/backend/src/libs/modules/database/libs/enums/enums.ts similarity index 100% rename from server/src/libs/packages/database/libs/enums/enums.ts rename to apps/backend/src/libs/modules/database/libs/enums/enums.ts diff --git a/server/src/libs/packages/database/libs/types/database-package.type.ts b/apps/backend/src/libs/modules/database/libs/types/database-package.type.ts similarity index 76% rename from server/src/libs/packages/database/libs/types/database-package.type.ts rename to apps/backend/src/libs/modules/database/libs/types/database-package.type.ts index 288c07d6..8aa42736 100644 --- a/server/src/libs/packages/database/libs/types/database-package.type.ts +++ b/apps/backend/src/libs/modules/database/libs/types/database-package.type.ts @@ -3,11 +3,11 @@ import { type Knex } from 'knex'; import { type AppEnvironment } from '~/libs/enums/enums.js'; import { type ValueOf } from '~/libs/types/types.js'; -type DatabasePackage = { +type DatabaseModule = { + knex: Knex; environmentsConfig: Record, Knex.Config>; initialConfig: Knex.Config; - knex: Knex; - connect(): void; + connect(): Promise; }; -export { type DatabasePackage }; +export { type DatabaseModule }; diff --git a/server/src/libs/packages/database/libs/types/repository.type.ts b/apps/backend/src/libs/modules/database/libs/types/repository.type.ts similarity index 100% rename from server/src/libs/packages/database/libs/types/repository.type.ts rename to apps/backend/src/libs/modules/database/libs/types/repository.type.ts diff --git a/apps/backend/src/libs/modules/database/libs/types/types.ts b/apps/backend/src/libs/modules/database/libs/types/types.ts new file mode 100644 index 00000000..783061bc --- /dev/null +++ b/apps/backend/src/libs/modules/database/libs/types/types.ts @@ -0,0 +1,2 @@ +export { type DatabaseModule } from './database-package.type.js'; +export { type Repository } from './repository.type.js'; diff --git a/apps/backend/src/libs/modules/http/http.ts b/apps/backend/src/libs/modules/http/http.ts new file mode 100644 index 00000000..4b4ec0a1 --- /dev/null +++ b/apps/backend/src/libs/modules/http/http.ts @@ -0,0 +1 @@ +export { HTTPCode, HttpHeader, HTTPMethod } from './libs/enums/enums.js'; diff --git a/apps/backend/src/libs/modules/http/libs/enums/enums.ts b/apps/backend/src/libs/modules/http/libs/enums/enums.ts new file mode 100644 index 00000000..ffca92db --- /dev/null +++ b/apps/backend/src/libs/modules/http/libs/enums/enums.ts @@ -0,0 +1,5 @@ +export { + HTTPCode, + HttpHeader, + HTTPMethod +} from '@thread-js/shared'; diff --git a/apps/backend/src/libs/modules/logger/libs/types/logger-module.type.ts b/apps/backend/src/libs/modules/logger/libs/types/logger-module.type.ts new file mode 100644 index 00000000..c51c753c --- /dev/null +++ b/apps/backend/src/libs/modules/logger/libs/types/logger-module.type.ts @@ -0,0 +1,13 @@ +type LogFunction = ( + message: string, + parameters?: Record +) => void; + +type LoggerModule = { + debug: LogFunction; + error: LogFunction; + info: LogFunction; + warn: LogFunction; +}; + +export { type LoggerModule }; diff --git a/apps/backend/src/libs/modules/logger/libs/types/types.ts b/apps/backend/src/libs/modules/logger/libs/types/types.ts new file mode 100644 index 00000000..de2e77a4 --- /dev/null +++ b/apps/backend/src/libs/modules/logger/libs/types/types.ts @@ -0,0 +1 @@ +export { type LoggerModule } from './logger-module.type.js'; diff --git a/apps/backend/src/libs/modules/logger/logger.module.ts b/apps/backend/src/libs/modules/logger/logger.module.ts new file mode 100644 index 00000000..7dbce0c5 --- /dev/null +++ b/apps/backend/src/libs/modules/logger/logger.module.ts @@ -0,0 +1,43 @@ +import { type Logger as LibraryLogger, pino } from 'pino'; +import pretty from 'pino-pretty'; +import { LoggerModule } from './libs/types/types.js'; + +class Logger implements LoggerModule { + private logger: LibraryLogger; + + public constructor() { + this.logger = pino(pretty.default()); + + this.logger.info('Logger is created…'); + } + + public debug( + message: string, + parameters: Record = {} + ): ReturnType { + this.logger.debug(parameters, message); + } + + public error( + message: string, + parameters: Record = {} + ): ReturnType { + this.logger.error(parameters, message); + } + + public info( + message: string, + parameters: Record = {} + ): ReturnType { + this.logger.info(parameters, message); + } + + public warn( + message: string, + parameters: Record = {} + ): ReturnType { + this.logger.warn(parameters, message); + } +} + +export { Logger }; diff --git a/apps/backend/src/libs/modules/logger/logger.ts b/apps/backend/src/libs/modules/logger/logger.ts new file mode 100644 index 00000000..d20463d2 --- /dev/null +++ b/apps/backend/src/libs/modules/logger/logger.ts @@ -0,0 +1,6 @@ +import { Logger } from './logger.module.js'; + +const logger = new Logger(); + +export { logger }; +export { type LoggerModule } from './libs/types/types.js'; diff --git a/server/src/libs/packages/path/libs/helpers/helpers.ts b/apps/backend/src/libs/modules/path/libs/helpers/helpers.ts similarity index 100% rename from server/src/libs/packages/path/libs/helpers/helpers.ts rename to apps/backend/src/libs/modules/path/libs/helpers/helpers.ts diff --git a/server/src/libs/packages/path/libs/helpers/join-path/join-path.helper.ts b/apps/backend/src/libs/modules/path/libs/helpers/join-path/join-path.helper.ts similarity index 100% rename from server/src/libs/packages/path/libs/helpers/join-path/join-path.helper.ts rename to apps/backend/src/libs/modules/path/libs/helpers/join-path/join-path.helper.ts diff --git a/server/src/libs/packages/path/path.ts b/apps/backend/src/libs/modules/path/path.ts similarity index 100% rename from server/src/libs/packages/path/path.ts rename to apps/backend/src/libs/modules/path/path.ts diff --git a/server/src/libs/packages/server-application/libs/enums/enums.ts b/apps/backend/src/libs/modules/server-application/libs/enums/enums.ts similarity index 100% rename from server/src/libs/packages/server-application/libs/enums/enums.ts rename to apps/backend/src/libs/modules/server-application/libs/enums/enums.ts diff --git a/server/src/libs/packages/server-application/libs/enums/exit-code.enum.ts b/apps/backend/src/libs/modules/server-application/libs/enums/exit-code.enum.ts similarity index 100% rename from server/src/libs/packages/server-application/libs/enums/exit-code.enum.ts rename to apps/backend/src/libs/modules/server-application/libs/enums/exit-code.enum.ts diff --git a/apps/backend/src/libs/modules/server-application/libs/helpers/get-error-info/get-default-error-info.helper.ts b/apps/backend/src/libs/modules/server-application/libs/helpers/get-error-info/get-default-error-info.helper.ts new file mode 100644 index 00000000..bc8b368a --- /dev/null +++ b/apps/backend/src/libs/modules/server-application/libs/helpers/get-error-info/get-default-error-info.helper.ts @@ -0,0 +1,16 @@ +import { HTTPCode } from '~/libs/modules/http/http.js'; +import { APIError, ErrorInfo } from '../../types/types.js'; +import { ServerErrorType } from '~/libs/enums/enums.js'; + +const getDefaultErrorInfo = (error: APIError): ErrorInfo => { + return { + internalMessage: error.message, + status: HTTPCode.INTERNAL_SERVER_ERROR, + response: { + message: error.message, + errorType: ServerErrorType.COMMON + } + }; +}; + +export { getDefaultErrorInfo }; diff --git a/apps/backend/src/libs/modules/server-application/libs/helpers/get-error-info/get-error-info.helper.ts b/apps/backend/src/libs/modules/server-application/libs/helpers/get-error-info/get-error-info.helper.ts new file mode 100644 index 00000000..758627ad --- /dev/null +++ b/apps/backend/src/libs/modules/server-application/libs/helpers/get-error-info/get-error-info.helper.ts @@ -0,0 +1,14 @@ +import { APIError, ErrorInfo } from '../../types/types.js'; +import { getDefaultErrorInfo } from './get-default-error-info.helper.js'; + +import { getValidationErrorInfo } from './get-validation-error-info.helper.js'; + +const getErrorInfo = (error: APIError): ErrorInfo => { + if ('isJoi' in error) { + return getValidationErrorInfo(error); + } + + return getDefaultErrorInfo(error); +}; + +export { getErrorInfo }; diff --git a/apps/backend/src/libs/modules/server-application/libs/helpers/get-error-info/get-validation-error-info.helper.ts b/apps/backend/src/libs/modules/server-application/libs/helpers/get-error-info/get-validation-error-info.helper.ts new file mode 100644 index 00000000..37d1a471 --- /dev/null +++ b/apps/backend/src/libs/modules/server-application/libs/helpers/get-error-info/get-validation-error-info.helper.ts @@ -0,0 +1,26 @@ +import { ServerErrorType } from '~/libs/enums/enums.js'; +import { type ValidationError } from '~/libs/exceptions/exceptions.js'; + +import { type ErrorInfo } from '../../types/types.js'; +import { HTTPCode } from '~/libs/modules/http/http.js'; + +const getValidationErrorInfo = (error: ValidationError): ErrorInfo => { + const { message, details } = error; + + return { + internalMessage: `[Validation Error]: ${message}`, + status: HTTPCode.UNPROCESSED_ENTITY, + response: { + message, + errorType: ServerErrorType.VALIDATION, + details: details.map(detail => { + return { + path: detail.path, + message: detail.message + }; + }) + } + }; +}; + +export { getValidationErrorInfo }; diff --git a/apps/backend/src/libs/modules/server-application/libs/helpers/helpers.ts b/apps/backend/src/libs/modules/server-application/libs/helpers/helpers.ts new file mode 100644 index 00000000..3e865383 --- /dev/null +++ b/apps/backend/src/libs/modules/server-application/libs/helpers/helpers.ts @@ -0,0 +1 @@ +export { getErrorInfo } from './get-error-info/get-error-info.helper.js'; diff --git a/apps/backend/src/libs/modules/server-application/libs/types/api-error.type.ts b/apps/backend/src/libs/modules/server-application/libs/types/api-error.type.ts new file mode 100644 index 00000000..3f25496b --- /dev/null +++ b/apps/backend/src/libs/modules/server-application/libs/types/api-error.type.ts @@ -0,0 +1,6 @@ +import { type FastifyError } from 'fastify'; +import { ValidationError } from '~/libs/exceptions/exceptions.js'; + +type APIError = FastifyError | ValidationError; + +export { type APIError }; diff --git a/apps/backend/src/libs/modules/server-application/libs/types/error-info.type.ts b/apps/backend/src/libs/modules/server-application/libs/types/error-info.type.ts new file mode 100644 index 00000000..c392bea6 --- /dev/null +++ b/apps/backend/src/libs/modules/server-application/libs/types/error-info.type.ts @@ -0,0 +1,11 @@ +import { ServerErrorResponse } from '@thread-js/shared'; +import { HTTPCode } from '~/libs/modules/http/http.js'; +import { ValueOf } from '~/libs/types/types.js'; + +type ErrorInfo = { + internalMessage: string; + status: ValueOf; + response: ServerErrorResponse; +}; + +export { type ErrorInfo }; diff --git a/apps/backend/src/libs/modules/server-application/libs/types/server-app-api.type.ts b/apps/backend/src/libs/modules/server-application/libs/types/server-app-api.type.ts new file mode 100644 index 00000000..60641ca6 --- /dev/null +++ b/apps/backend/src/libs/modules/server-application/libs/types/server-app-api.type.ts @@ -0,0 +1,7 @@ +import { type Controller } from '~/libs/modules/controller/controller.js'; + +type ServerApi = { + routes: Controller['routes']; +}; + +export { type ServerApi }; diff --git a/server/src/libs/packages/controller/libs/types/controller-route.type.ts b/apps/backend/src/libs/modules/server-application/libs/types/server-application-route-parameters.type.ts similarity index 52% rename from server/src/libs/packages/controller/libs/types/controller-route.type.ts rename to apps/backend/src/libs/modules/server-application/libs/types/server-application-route-parameters.type.ts index 90d877bd..d76cd16d 100644 --- a/server/src/libs/packages/controller/libs/types/controller-route.type.ts +++ b/apps/backend/src/libs/modules/server-application/libs/types/server-application-route-parameters.type.ts @@ -4,23 +4,20 @@ import { type preHandlerHookHandler, type RouteGenericInterface } from 'fastify'; +import { HTTPMethod } from '~/libs/modules/http/http.js'; +import { ValueOf, type ValidationSchema } from '~/libs/types/types.js'; -import { type HttpMethod } from '~/libs/packages/http/http.js'; -import { type ValidationSchema, type ValueOf } from '~/libs/types/types.js'; - -type ControllerRoute = { +type ServerApplicationRouteParameters = { url: string; - method: ValueOf; + method: ValueOf; preHandler?: preHandlerHookHandler; handler: ( _request: FastifyRequest, _reply: FastifyReply ) => Promise; - schema?: { + validation?: { body?: ValidationSchema; - params?: ValidationSchema; - query?: ValidationSchema; }; }; -export { type ControllerRoute }; +export { type ServerApplicationRouteParameters }; diff --git a/apps/backend/src/libs/modules/server-application/libs/types/types.ts b/apps/backend/src/libs/modules/server-application/libs/types/types.ts new file mode 100644 index 00000000..b995622a --- /dev/null +++ b/apps/backend/src/libs/modules/server-application/libs/types/types.ts @@ -0,0 +1,4 @@ +export { type ServerApi } from './server-app-api.type.js'; +export { type ServerApplicationRouteParameters } from './server-application-route-parameters.type.js'; +export { type APIError } from './api-error.type.js'; +export { type ErrorInfo } from './error-info.type.js'; diff --git a/apps/backend/src/libs/modules/server-application/server-app-api.ts b/apps/backend/src/libs/modules/server-application/server-app-api.ts new file mode 100644 index 00000000..91b7885d --- /dev/null +++ b/apps/backend/src/libs/modules/server-application/server-app-api.ts @@ -0,0 +1,28 @@ +import { type Controller } from '../controller/controller.js'; +import { joinPath } from '../path/path.js'; +import { type ServerApi } from './libs/types/types.js'; + +type Constructor = { + routes: Controller['routes']; + version: string; +}; + +class ServerAppApi implements ServerApi { + #routes: Controller['routes']; + + #version: string; + + public constructor({ version, routes }: Constructor) { + this.#version = version; + this.#routes = routes.map(handler => ({ + ...handler, + url: joinPath([`/${this.#version}`, handler.url]) + })); + } + + public get routes(): Controller['routes'] { + return this.#routes; + } +} + +export { ServerAppApi }; diff --git a/apps/backend/src/libs/modules/server-application/server-app.ts b/apps/backend/src/libs/modules/server-application/server-app.ts new file mode 100644 index 00000000..9b5acb82 --- /dev/null +++ b/apps/backend/src/libs/modules/server-application/server-app.ts @@ -0,0 +1,161 @@ +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import fastifyStatic from '@fastify/static'; +import fastify, { + FastifyError, + type FastifyInstance, + type FastifyServerOptions +} from 'fastify'; + +import { type ConfigModule } from '~/libs/modules/config/config.js'; +import { joinPath } from '~/libs/modules/path/path.js'; + +import { type ValidationSchema } from '~/libs/types/types.js'; + +import { type DatabaseModule } from '../database/database.js'; +import { type ServerApi } from './libs/types/types.js'; +import { LoggerModule } from '../logger/logger.js'; +import { ValidationError } from '~/libs/exceptions/exceptions.js'; +import { getErrorInfo } from './libs/helpers/helpers.js'; +import { ServerErrorType } from '~/libs/enums/enums.js'; + +type Constructor = { + config: ConfigModule; + logger: LoggerModule; + apis: ServerApi[]; + options: FastifyServerOptions; + database: DatabaseModule; +}; + +class ServerApp { + #app: FastifyInstance; + + #config: ConfigModule; + + #logger: LoggerModule; + + #apis: ServerApi[]; + + #database: DatabaseModule; + + public constructor({ config, logger, options, apis, database }: Constructor) { + this.#config = config; + this.#logger = logger; + + this.#app = this.#initApp(options); + + this.#apis = apis; + this.#database = database; + } + + public get app(): FastifyInstance { + return this.#app; + } + + public get database(): DatabaseModule { + return this.#database; + } + + #initApp = (options: FastifyServerOptions): FastifyInstance => { + const app = fastify(options); + + return app; + }; + + public initialize = async (): Promise => { + this.#initValidationCompiler(); + await this.#registerServe(); + this.#registerRoutes(); + this.#initErrorHandler(); + + await this.#database.connect(); + + return this; + }; + + #registerServe = async (): Promise => { + const staticPath = join( + dirname(fileURLToPath(import.meta.url)), + '../../../../public' + ); + + await this.#app.register(fastifyStatic, { + root: staticPath, + prefix: '/' + }); + + this.#app.setNotFoundHandler(async (_request, response) => { + await response.sendFile('index.html', staticPath); + }); + }; + + #registerRoutes = (): void => { + const routers = this.#apis.flatMap(it => it.routes); + + for (const it of routers) { + const { url: path, ...parameters } = it; + + this.app.route({ + url: joinPath([this.#config.ENV.APP.API_PATH, path]), + ...parameters + }); + } + }; + + #initValidationCompiler = (): void => { + this.app.setValidatorCompiler(({ schema }) => { + return >(data: T): R => { + return schema.validate(data, { + abortEarly: false + }) as R; + }; + }); + }; + + #initErrorHandler(): void { + this.app.setErrorHandler( + (error: FastifyError | ValidationError, _request, reply) => { + const { internalMessage, status, response } = getErrorInfo(error); + + this.#logger.error(internalMessage); + + if (response.errorType === ServerErrorType.VALIDATION) { + response.details.forEach(detail => { + this.#logger.error( + `[${detail.path.toString()}] — ${detail.message}` + ); + }); + } + + return reply.status(status).send(response); + } + ); + } + + public start = async (): Promise | never => { + try { + await this.#app.listen({ + port: this.#config.ENV.APP.PORT, + host: this.#config.ENV.APP.HOST + }); + console.log(this.#app.printRoutes()); + this.#logger.info( + `Application is listening on PORT - ${this.#config.ENV.APP.PORT.toString()}, on ENVIRONMENT - ${ + this.#config.ENV.APP.ENVIRONMENT as string + }.` + ); + } catch (error) { + if (error instanceof Error) { + this.#logger.error(error.message, { + cause: error.cause, + stack: error.stack + }); + } + + throw error; + } + }; +} + +export { ServerApp }; diff --git a/server/src/libs/packages/server-application/server-application.ts b/apps/backend/src/libs/modules/server-application/server-application.ts similarity index 54% rename from server/src/libs/packages/server-application/server-application.ts rename to apps/backend/src/libs/modules/server-application/server-application.ts index 751ec6a2..59aa0305 100644 --- a/server/src/libs/packages/server-application/server-application.ts +++ b/apps/backend/src/libs/modules/server-application/server-application.ts @@ -1,26 +1,21 @@ import { parse, type ParsedQs } from 'qs'; -import { config } from '~/libs/packages/config/config.js'; -import { database } from '~/libs/packages/database/database.js'; +import { config } from '~/libs/modules/config/config.js'; +import { database } from '~/libs/modules/database/database.js'; import { authController } from '~/packages/auth/auth.js'; -import { commentController } from '~/packages/comment/comment.js'; -import { imageController } from '~/packages/image/image.js'; -import { postController } from '~/packages/post/post.js'; import { ServerApp } from './server-app.js'; import { ServerAppApi } from './server-app-api.js'; +import { logger } from '../logger/logger.js'; -const serverAppApi = new ServerAppApi({ - controllers: [ - authController, - commentController, - imageController, - postController - ] +const serverAppApiV1 = new ServerAppApi({ + routes: [...authController.routes], + version: 'v1' }); const serverApp = new ServerApp({ config, + logger, options: { ignoreTrailingSlash: true, logger: { @@ -33,9 +28,10 @@ const serverApp = new ServerApp({ } }, database, - api: serverAppApi + apis: [serverAppApiV1] }); -export { serverApp, serverAppApi }; +export { serverApp, serverAppApiV1 }; export { ExitCode } from './libs/enums/enums.js'; export { ServerApp } from './server-app.js'; +export { type ServerApplicationRouteParameters } from './libs/types/types.js'; diff --git a/apps/backend/src/libs/types/types.ts b/apps/backend/src/libs/types/types.ts new file mode 100644 index 00000000..92334189 --- /dev/null +++ b/apps/backend/src/libs/types/types.ts @@ -0,0 +1 @@ +export { type ValidationSchema, type ValueOf } from '@thread-js/shared'; diff --git a/apps/backend/src/main.ts b/apps/backend/src/main.ts new file mode 100644 index 00000000..2d0d5d6a --- /dev/null +++ b/apps/backend/src/main.ts @@ -0,0 +1,3 @@ +import { serverApp } from './libs/modules/server-application/server-application.js'; + +await serverApp.initialize().then(app => app.start()); diff --git a/apps/backend/src/packages/auth/auth.controller.ts b/apps/backend/src/packages/auth/auth.controller.ts new file mode 100644 index 00000000..765ebfe3 --- /dev/null +++ b/apps/backend/src/packages/auth/auth.controller.ts @@ -0,0 +1,57 @@ +import { type APIPath } from '~/libs/enums/enums.js'; +import { + Controller, + ControllerAPIHandler, + ControllerAPIHandlerOptions, + ControllerAPIHandlerResponse, + ControllerHook +} from '~/libs/modules/controller/controller.js'; +import { HTTPCode, HTTPMethod } from '~/libs/modules/http/http.js'; +import { type ValueOf } from '~/libs/types/types.js'; + +import { AuthApiPath } from './libs/enums/enums.js'; +import { + UserRegisterResponseDto, + type AuthController, + type AuthService, + type UserRegisterRequestDto +} from './libs/types/types.js'; +import { registrationValidationSchema } from './libs/validation-schemas/validation-schemas.js'; +import { LoggerModule } from '~/libs/modules/logger/logger.js'; + +type Constructor = { + apiPath: ValueOf; + authService: AuthService; + logger: LoggerModule; +}; + +class Auth extends Controller implements AuthController { + #authService: AuthService; + + public constructor({ apiPath, authService, logger }: Constructor) { + super({ apiPath, logger }); + this.#authService = authService; + + this.addRoute({ + method: HTTPMethod.POST, + url: AuthApiPath.REGISTER, + schema: { + body: registrationValidationSchema + }, + handler: this.register as ControllerAPIHandler + }); + } + + public register = async ( + options: ControllerAPIHandlerOptions<{ + body: UserRegisterRequestDto; + }> + ): Promise> => { + return { + payload: await this.#authService.register(options.body), + status: HTTPCode.CREATED + }; + }; +} + +export { Auth }; diff --git a/apps/backend/src/packages/auth/auth.service.ts b/apps/backend/src/packages/auth/auth.service.ts new file mode 100644 index 00000000..8ed48ee9 --- /dev/null +++ b/apps/backend/src/packages/auth/auth.service.ts @@ -0,0 +1,26 @@ +import { type UserRepository } from '../user/user.js'; +import { + type UserRegisterResponseDto, + type AuthService, + type UserRegisterRequestDto +} from './libs/types/types.js'; + +type Constructor = { + userRepository: UserRepository; +}; + +class Auth implements AuthService { + #userRepository: UserRepository; + + public constructor({ userRepository }: Constructor) { + this.#userRepository = userRepository; + } + + public register = async ( + userRequestDto: UserRegisterRequestDto + ): Promise => { + return this.#userRepository.create(userRequestDto); + }; +} + +export { Auth }; diff --git a/server/src/packages/auth/auth.ts b/apps/backend/src/packages/auth/auth.ts similarity index 53% rename from server/src/packages/auth/auth.ts rename to apps/backend/src/packages/auth/auth.ts index edeed822..068c519d 100644 --- a/server/src/packages/auth/auth.ts +++ b/apps/backend/src/packages/auth/auth.ts @@ -1,30 +1,24 @@ -import { ApiPath } from '~/libs/enums/enums.js'; -import { userRepository, userService } from '~/packages/user/user.js'; +import { APIPath } from '~/libs/enums/enums.js'; +import { userRepository } from '~/packages/user/user.js'; import { Auth as AuthController } from './auth.controller.js'; import { Auth as AuthService } from './auth.service.js'; +import { logger } from '~/libs/modules/logger/logger.js'; const authService = new AuthService({ userRepository }); const authController = new AuthController({ - apiPath: ApiPath.AUTH, + apiPath: APIPath.AUTH, authService, - userService + logger }); export { authController, authService }; -export { - createToken, - cryptCompare, - encrypt, - encryptSync, - getErrorStatusCode, - verifyToken -} from './helpers/helpers.js'; +export { encryptSync } from './helpers/helpers.js'; export { AuthApiPath } from './libs/enums/enums.js'; export { type AuthService, - type UserLoginResponseDto, - type UserRegisterRequestDto + type UserRegisterRequestDto, + type UserRegisterResponseDto } from './libs/types/types.js'; diff --git a/apps/backend/src/packages/auth/helpers/crypt/crypt.ts b/apps/backend/src/packages/auth/helpers/crypt/crypt.ts new file mode 100644 index 00000000..2c0e28e9 --- /dev/null +++ b/apps/backend/src/packages/auth/helpers/crypt/crypt.ts @@ -0,0 +1 @@ +export { encryptSync } from './encrypt-sync/encrypt-sync.helper.js'; diff --git a/apps/backend/src/packages/auth/helpers/crypt/encrypt-sync/encrypt-sync.helper.ts b/apps/backend/src/packages/auth/helpers/crypt/encrypt-sync/encrypt-sync.helper.ts new file mode 100644 index 00000000..531aca51 --- /dev/null +++ b/apps/backend/src/packages/auth/helpers/crypt/encrypt-sync/encrypt-sync.helper.ts @@ -0,0 +1,9 @@ +import { hashSync } from 'bcrypt'; + +import { PASSWORD_SALT_ROUNDS } from '../libs/constants/constants.js'; + +const encryptSync = (data: string): string => { + return hashSync(data, PASSWORD_SALT_ROUNDS); +}; + +export { encryptSync }; diff --git a/apps/backend/src/packages/auth/helpers/crypt/libs/constants/constants.ts b/apps/backend/src/packages/auth/helpers/crypt/libs/constants/constants.ts new file mode 100644 index 00000000..5f6fa985 --- /dev/null +++ b/apps/backend/src/packages/auth/helpers/crypt/libs/constants/constants.ts @@ -0,0 +1 @@ +export { PASSWORD_SALT_ROUNDS } from './crypt.constant.js'; diff --git a/apps/backend/src/packages/auth/helpers/crypt/libs/constants/crypt.constant.ts b/apps/backend/src/packages/auth/helpers/crypt/libs/constants/crypt.constant.ts new file mode 100644 index 00000000..777a9a46 --- /dev/null +++ b/apps/backend/src/packages/auth/helpers/crypt/libs/constants/crypt.constant.ts @@ -0,0 +1,3 @@ +const PASSWORD_SALT_ROUNDS = 10; + +export { PASSWORD_SALT_ROUNDS }; diff --git a/apps/backend/src/packages/auth/helpers/helpers.ts b/apps/backend/src/packages/auth/helpers/helpers.ts new file mode 100644 index 00000000..b8fe6946 --- /dev/null +++ b/apps/backend/src/packages/auth/helpers/helpers.ts @@ -0,0 +1 @@ +export { encryptSync } from './crypt/crypt.js'; diff --git a/apps/backend/src/packages/auth/libs/enums/enums.ts b/apps/backend/src/packages/auth/libs/enums/enums.ts new file mode 100644 index 00000000..11cc65fd --- /dev/null +++ b/apps/backend/src/packages/auth/libs/enums/enums.ts @@ -0,0 +1 @@ +export { AuthApiPath } from '@thread-js/shared'; diff --git a/apps/backend/src/packages/auth/libs/types/auth-controller.type.ts b/apps/backend/src/packages/auth/libs/types/auth-controller.type.ts new file mode 100644 index 00000000..1f52b1c5 --- /dev/null +++ b/apps/backend/src/packages/auth/libs/types/auth-controller.type.ts @@ -0,0 +1,20 @@ +import { type FastifyReply, type FastifyRequest } from 'fastify'; + +import { + type UserRegisterResponseDto, + type UserRegisterRequestDto +} from './types.js'; +import { + ControllerAPIHandlerOptions, + ControllerAPIHandlerResponse +} from '~/libs/modules/controller/controller.js'; + +type AuthController = { + register: ( + options: ControllerAPIHandlerOptions<{ + body: UserRegisterRequestDto; + }> + ) => Promise>; +}; + +export { type AuthController }; diff --git a/apps/backend/src/packages/auth/libs/types/auth-service.type.ts b/apps/backend/src/packages/auth/libs/types/auth-service.type.ts new file mode 100644 index 00000000..c1ecb95f --- /dev/null +++ b/apps/backend/src/packages/auth/libs/types/auth-service.type.ts @@ -0,0 +1,10 @@ +import { + type UserRegisterRequestDto, + type UserRegisterResponseDto +} from './types.js'; + +type AuthService = { + register(_user: UserRegisterRequestDto): Promise; +}; + +export { type AuthService }; diff --git a/apps/backend/src/packages/auth/libs/types/types.ts b/apps/backend/src/packages/auth/libs/types/types.ts new file mode 100644 index 00000000..a8a171e9 --- /dev/null +++ b/apps/backend/src/packages/auth/libs/types/types.ts @@ -0,0 +1,7 @@ +export { type AuthController } from './auth-controller.type.js'; +export { type AuthService } from './auth-service.type.js'; +export { + type User, + type UserRegisterRequestDto, + type UserRegisterResponseDto +} from '@thread-js/shared'; diff --git a/apps/backend/src/packages/auth/libs/validation-schemas/validation-schemas.ts b/apps/backend/src/packages/auth/libs/validation-schemas/validation-schemas.ts new file mode 100644 index 00000000..d11ee0e5 --- /dev/null +++ b/apps/backend/src/packages/auth/libs/validation-schemas/validation-schemas.ts @@ -0,0 +1 @@ +export { registration as registrationValidationSchema } from '@thread-js/shared'; diff --git a/server/src/packages/user/libs/enums/enums.ts b/apps/backend/src/packages/user/libs/enums/enums.ts similarity index 54% rename from server/src/packages/user/libs/enums/enums.ts rename to apps/backend/src/packages/user/libs/enums/enums.ts index 3f199e70..12b02912 100644 --- a/server/src/packages/user/libs/enums/enums.ts +++ b/apps/backend/src/packages/user/libs/enums/enums.ts @@ -1,6 +1,5 @@ export { UserPayloadKey, - UsersApiPath, UserValidationMessage, UserValidationRule -} from 'shared/dist/packages/user/user.js'; +} from '@thread-js/shared'; diff --git a/apps/backend/src/packages/user/libs/types/types.ts b/apps/backend/src/packages/user/libs/types/types.ts new file mode 100644 index 00000000..c315a7f3 --- /dev/null +++ b/apps/backend/src/packages/user/libs/types/types.ts @@ -0,0 +1,3 @@ +export { type UserRepository } from './user-repository.type.js'; +export { type UserService } from './user-service.type.js'; +export { type User } from '@thread-js/shared'; diff --git a/apps/backend/src/packages/user/libs/types/user-repository.type.ts b/apps/backend/src/packages/user/libs/types/user-repository.type.ts new file mode 100644 index 00000000..8c252346 --- /dev/null +++ b/apps/backend/src/packages/user/libs/types/user-repository.type.ts @@ -0,0 +1,11 @@ +import { type Repository } from '~/libs/modules/database/database.js'; + +import { type User } from './types.js'; + +type UserRepository = Pick, 'create'> & { + getByEmail(_email: string): Promise; + + getByUsername(_username: string): Promise; +}; + +export { type UserRepository }; diff --git a/apps/backend/src/packages/user/libs/types/user-service.type.ts b/apps/backend/src/packages/user/libs/types/user-service.type.ts new file mode 100644 index 00000000..8e4d22ab --- /dev/null +++ b/apps/backend/src/packages/user/libs/types/user-service.type.ts @@ -0,0 +1,7 @@ +import { type User } from './types.js'; + +type UserService = { + getById(_id: number): Promise; +}; + +export { type UserService }; diff --git a/apps/backend/src/packages/user/user.model.ts b/apps/backend/src/packages/user/user.model.ts new file mode 100644 index 00000000..9985a402 --- /dev/null +++ b/apps/backend/src/packages/user/user.model.ts @@ -0,0 +1,20 @@ +import { + AbstractModel, + DatabaseTableName +} from '~/libs/modules/database/database.js'; + +class User extends AbstractModel { + public email!: string; + + public username!: string; + + public password!: string; + + public imageId!: number | null; + + public static get tableName(): typeof DatabaseTableName.USERS { + return DatabaseTableName.USERS; + } +} + +export { User }; diff --git a/apps/backend/src/packages/user/user.repository.ts b/apps/backend/src/packages/user/user.repository.ts new file mode 100644 index 00000000..f4230e4d --- /dev/null +++ b/apps/backend/src/packages/user/user.repository.ts @@ -0,0 +1,32 @@ +import { AbstractRepository } from '~/libs/modules/database/database.js'; + +import { type User as TUser, type UserRepository } from './libs/types/types.js'; +import { type User as UserModel } from './user.model.js'; + +type Constructor = Record<'userModel', typeof UserModel>; + +class User + extends AbstractRepository + implements UserRepository +{ + public constructor({ userModel }: Constructor) { + super(userModel); + } + + public async getByEmail(email: string): Promise { + const user = await this.model + .query() + .modify('withoutPassword') + .findOne({ email }); + + return user ?? null; + } + + public async getByUsername(username: string): Promise { + const user = await this.model.query().select().findOne({ username }); + + return user ?? null; + } +} + +export { User }; diff --git a/server/src/packages/user/user.service.ts b/apps/backend/src/packages/user/user.service.ts similarity index 61% rename from server/src/packages/user/user.service.ts rename to apps/backend/src/packages/user/user.service.ts index e4a74d4a..edbf45fc 100644 --- a/server/src/packages/user/user.service.ts +++ b/apps/backend/src/packages/user/user.service.ts @@ -1,8 +1,4 @@ -import { - type User as TUser, - type UserService, - type UserWithImageRelation -} from './libs/types/types.js'; +import { type User as TUser, type UserService } from './libs/types/types.js'; import { type User as UserRepository } from './user.repository.js'; type Constructor = Record<'userRepository', UserRepository>; @@ -17,12 +13,6 @@ class User implements UserService { public getById(id: number): Promise { return this.#userRepository.getById(id); } - - public async getByIdWithImage( - id: number - ): Promise { - return await this.#userRepository.getByIdWithImage(id); - } } export { User }; diff --git a/server/src/packages/user/user.ts b/apps/backend/src/packages/user/user.ts similarity index 87% rename from server/src/packages/user/user.ts rename to apps/backend/src/packages/user/user.ts index 7552fc85..7757ca51 100644 --- a/server/src/packages/user/user.ts +++ b/apps/backend/src/packages/user/user.ts @@ -12,15 +12,12 @@ const userService = new UserService({ export { userRepository, userService }; export { UserPayloadKey, - UsersApiPath, UserValidationMessage, UserValidationRule } from './libs/enums/enums.js'; export { type User, - type UserAuthResponse, type UserRepository, - type UserService, - type UserWithPassword + type UserService } from './libs/types/types.js'; export { User as UserModel } from './user.model.js'; diff --git a/apps/backend/tests/libs/constants/constants.ts b/apps/backend/tests/libs/constants/constants.ts new file mode 100644 index 00000000..4d28106b --- /dev/null +++ b/apps/backend/tests/libs/constants/constants.ts @@ -0,0 +1,3 @@ +const API_V1_VERSION_PREFIX = '/v1'; + +export { API_V1_VERSION_PREFIX }; diff --git a/server/tests/libs/packages/app/app.ts b/apps/backend/tests/libs/modules/app/app.ts similarity index 100% rename from server/tests/libs/packages/app/app.ts rename to apps/backend/tests/libs/modules/app/app.ts diff --git a/server/tests/libs/packages/app/libs/helpers/build-app/build-app.helper.ts b/apps/backend/tests/libs/modules/app/libs/helpers/build-app/build-app.helper.ts similarity index 75% rename from server/tests/libs/packages/app/libs/helpers/build-app/build-app.helper.ts rename to apps/backend/tests/libs/modules/app/libs/helpers/build-app/build-app.helper.ts index 6e3e96c3..fe00b740 100644 --- a/server/tests/libs/packages/app/libs/helpers/build-app/build-app.helper.ts +++ b/apps/backend/tests/libs/modules/app/libs/helpers/build-app/build-app.helper.ts @@ -3,12 +3,13 @@ import { type FastifyInstance } from 'fastify'; import { type Knex } from 'knex'; import pg from 'pg'; -import { config } from '~/libs/packages/config/config.js'; -import { database } from '~/libs/packages/database/database.js'; +import { config } from '~/libs/modules/config/config.js'; +import { database } from '~/libs/modules/database/database.js'; +import { logger } from '~/libs/modules/logger/logger.js'; import { ServerApp, - serverAppApi -} from '~/libs/packages/server-application/server-application.js'; + serverAppApiV1 +} from '~/libs/modules/server-application/server-application.js'; import { clearDatabase } from '../../../../database/database.js'; @@ -20,10 +21,11 @@ type BuildApp = () => { const buildApp: BuildApp = () => { const serverApp = new ServerApp({ config, + logger, options: { - logger: false + logger: true }, - api: serverAppApi, + apis: [serverAppApiV1], database }); diff --git a/server/tests/libs/packages/app/libs/helpers/helpers.ts b/apps/backend/tests/libs/modules/app/libs/helpers/helpers.ts similarity index 100% rename from server/tests/libs/packages/app/libs/helpers/helpers.ts rename to apps/backend/tests/libs/modules/app/libs/helpers/helpers.ts diff --git a/server/tests/libs/packages/database/database.ts b/apps/backend/tests/libs/modules/database/database.ts similarity index 100% rename from server/tests/libs/packages/database/database.ts rename to apps/backend/tests/libs/modules/database/database.ts diff --git a/server/tests/libs/packages/database/libs/constants/constants.ts b/apps/backend/tests/libs/modules/database/libs/constants/constants.ts similarity index 100% rename from server/tests/libs/packages/database/libs/constants/constants.ts rename to apps/backend/tests/libs/modules/database/libs/constants/constants.ts diff --git a/server/tests/libs/packages/database/libs/constants/crud.constant.ts b/apps/backend/tests/libs/modules/database/libs/constants/crud.constant.ts similarity index 100% rename from server/tests/libs/packages/database/libs/constants/crud.constant.ts rename to apps/backend/tests/libs/modules/database/libs/constants/crud.constant.ts diff --git a/server/tests/libs/packages/database/libs/helpers/clear-database/clear-database.helper.ts b/apps/backend/tests/libs/modules/database/libs/helpers/clear-database/clear-database.helper.ts similarity index 67% rename from server/tests/libs/packages/database/libs/helpers/clear-database/clear-database.helper.ts rename to apps/backend/tests/libs/modules/database/libs/helpers/clear-database/clear-database.helper.ts index ae46269e..f5c7fecf 100644 --- a/server/tests/libs/packages/database/libs/helpers/clear-database/clear-database.helper.ts +++ b/apps/backend/tests/libs/modules/database/libs/helpers/clear-database/clear-database.helper.ts @@ -1,4 +1,4 @@ -import { DatabaseTableName } from '~/libs/packages/database/database.js'; +import { DatabaseTableName } from '~/libs/modules/database/database.js'; import { type GetCrudHandlersFunction } from '../../types/types.js'; import { getCrudHandlers } from '../get-crud-handlers/get-crud-handlers.js'; @@ -8,11 +8,7 @@ const clearDatabase = async ( ): Promise => { const { remove } = getCrudHandlers(getKnex); - const tables = [ - DatabaseTableName.COMMENTS, - DatabaseTableName.POSTS, - DatabaseTableName.USERS - ]; + const tables = [DatabaseTableName.USERS]; for (const table of tables) { await remove({ table }); diff --git a/server/tests/libs/packages/database/libs/helpers/get-crud-handlers/get-crud-handlers.ts b/apps/backend/tests/libs/modules/database/libs/helpers/get-crud-handlers/get-crud-handlers.ts similarity index 100% rename from server/tests/libs/packages/database/libs/helpers/get-crud-handlers/get-crud-handlers.ts rename to apps/backend/tests/libs/modules/database/libs/helpers/get-crud-handlers/get-crud-handlers.ts diff --git a/server/tests/libs/packages/database/libs/helpers/helpers.ts b/apps/backend/tests/libs/modules/database/libs/helpers/helpers.ts similarity index 100% rename from server/tests/libs/packages/database/libs/helpers/helpers.ts rename to apps/backend/tests/libs/modules/database/libs/helpers/helpers.ts diff --git a/server/tests/libs/packages/database/libs/types/count-parameters.type.ts b/apps/backend/tests/libs/modules/database/libs/types/count-parameters.type.ts similarity index 81% rename from server/tests/libs/packages/database/libs/types/count-parameters.type.ts rename to apps/backend/tests/libs/modules/database/libs/types/count-parameters.type.ts index 4e3e3d69..60f5be25 100644 --- a/server/tests/libs/packages/database/libs/types/count-parameters.type.ts +++ b/apps/backend/tests/libs/modules/database/libs/types/count-parameters.type.ts @@ -1,4 +1,4 @@ -import { type DatabaseTableName } from '~/libs/packages/database/database.js'; +import { type DatabaseTableName } from '~/libs/modules/database/database.js'; import { type ValueOf } from '~/libs/types/types.js'; type CountParameters< diff --git a/server/tests/libs/packages/database/libs/types/get-crud-handlers-function.type.ts b/apps/backend/tests/libs/modules/database/libs/types/get-crud-handlers-function.type.ts similarity index 100% rename from server/tests/libs/packages/database/libs/types/get-crud-handlers-function.type.ts rename to apps/backend/tests/libs/modules/database/libs/types/get-crud-handlers-function.type.ts diff --git a/server/tests/libs/packages/database/libs/types/insert-parameters.type.ts b/apps/backend/tests/libs/modules/database/libs/types/insert-parameters.type.ts similarity index 75% rename from server/tests/libs/packages/database/libs/types/insert-parameters.type.ts rename to apps/backend/tests/libs/modules/database/libs/types/insert-parameters.type.ts index 661befd1..e85087bb 100644 --- a/server/tests/libs/packages/database/libs/types/insert-parameters.type.ts +++ b/apps/backend/tests/libs/modules/database/libs/types/insert-parameters.type.ts @@ -1,4 +1,4 @@ -import { type DatabaseTableName } from '~/libs/packages/database/database.js'; +import { type DatabaseTableName } from '~/libs/modules/database/database.js'; import { type ValueOf } from '~/libs/types/types.js'; type InsertParameters> = { diff --git a/server/tests/libs/packages/database/libs/types/remove-parameters.type.ts b/apps/backend/tests/libs/modules/database/libs/types/remove-parameters.type.ts similarity index 73% rename from server/tests/libs/packages/database/libs/types/remove-parameters.type.ts rename to apps/backend/tests/libs/modules/database/libs/types/remove-parameters.type.ts index b74f45d7..7c2ea044 100644 --- a/server/tests/libs/packages/database/libs/types/remove-parameters.type.ts +++ b/apps/backend/tests/libs/modules/database/libs/types/remove-parameters.type.ts @@ -1,4 +1,4 @@ -import { type DatabaseTableName } from '~/libs/packages/database/database.js'; +import { type DatabaseTableName } from '~/libs/modules/database/database.js'; import { type ValueOf } from '~/libs/types/types.js'; type RemoveParameters> = { diff --git a/server/tests/libs/packages/database/libs/types/select-parameters.type.ts b/apps/backend/tests/libs/modules/database/libs/types/select-parameters.type.ts similarity index 87% rename from server/tests/libs/packages/database/libs/types/select-parameters.type.ts rename to apps/backend/tests/libs/modules/database/libs/types/select-parameters.type.ts index f83c3560..0131c183 100644 --- a/server/tests/libs/packages/database/libs/types/select-parameters.type.ts +++ b/apps/backend/tests/libs/modules/database/libs/types/select-parameters.type.ts @@ -1,4 +1,4 @@ -import { type DatabaseTableName } from '~/libs/packages/database/database.js'; +import { type DatabaseTableName } from '~/libs/modules/database/database.js'; import { type ValueOf } from '~/libs/types/types.js'; type SelectParameters< diff --git a/server/tests/libs/packages/database/libs/types/types.ts b/apps/backend/tests/libs/modules/database/libs/types/types.ts similarity index 100% rename from server/tests/libs/packages/database/libs/types/types.ts rename to apps/backend/tests/libs/modules/database/libs/types/types.ts diff --git a/server/tests/libs/packages/database/libs/types/update-parameters.type.ts b/apps/backend/tests/libs/modules/database/libs/types/update-parameters.type.ts similarity index 76% rename from server/tests/libs/packages/database/libs/types/update-parameters.type.ts rename to apps/backend/tests/libs/modules/database/libs/types/update-parameters.type.ts index 783aa6d9..598e6311 100644 --- a/server/tests/libs/packages/database/libs/types/update-parameters.type.ts +++ b/apps/backend/tests/libs/modules/database/libs/types/update-parameters.type.ts @@ -1,4 +1,4 @@ -import { type DatabaseTableName } from '~/libs/packages/database/database.js'; +import { type DatabaseTableName } from '~/libs/modules/database/database.js'; import { type ValueOf } from '~/libs/types/types.js'; type UpdateParameters> = { diff --git a/apps/backend/tests/modules/auth/auth.api.spec.ts b/apps/backend/tests/modules/auth/auth.api.spec.ts new file mode 100644 index 00000000..5536b51b --- /dev/null +++ b/apps/backend/tests/modules/auth/auth.api.spec.ts @@ -0,0 +1,204 @@ +import { faker } from '@faker-js/faker'; +import { describe, expect, it } from '@jest/globals'; + +import { APIPath } from '~/libs/enums/enums.js'; +import { config } from '~/libs/modules/config/config.js'; +import { DatabaseTableName } from '~/libs/modules/database/database.js'; +import { HTTPCode, HTTPMethod } from '~/libs/modules/http/http.js'; +import { joinPath } from '~/libs/modules/path/path.js'; +import { + AuthApiPath, + type UserRegisterRequestDto, + type UserRegisterResponseDto +} from '~/packages/auth/auth.js'; +import { + UserPayloadKey, + UserValidationMessage, + UserValidationRule +} from '~/packages/user/user.js'; + +import { buildApp } from '../../libs/modules/app/app.js'; +import { + getCrudHandlers, + KNEX_SELECT_ONE_RECORD +} from '../../libs/modules/database/database.js'; +import { TEST_USERS_CREDENTIALS } from '../user/user.js'; +import { API_V1_VERSION_PREFIX } from '../../libs/constants/constants.js'; + +const authApiPath = joinPath([config.ENV.APP.API_PATH, APIPath.AUTH]); + +const registerEndpoint = joinPath([ + config.ENV.APP.API_PATH, + API_V1_VERSION_PREFIX, + APIPath.AUTH, + AuthApiPath.REGISTER +]); + +describe(`${authApiPath} routes`, () => { + const { getApp, getKnex } = buildApp(); + const { select } = getCrudHandlers(getKnex); + + describe(`${registerEndpoint} (${HTTPMethod.POST}) endpoint`, () => { + const app = getApp(); + + it(`should return ${HTTPCode.UNPROCESSED_ENTITY} of empty ${UserPayloadKey.USERNAME} validation error`, async () => { + const response = await app.inject().post(registerEndpoint).body({}); + console.log('response', response); + expect(response.statusCode).toBe(HTTPCode.UNPROCESSED_ENTITY); + expect(response.json>().message).toBe( + `${UserValidationMessage.USERNAME_REQUIRE}. ${UserValidationMessage.EMAIL_REQUIRE}. ${UserValidationMessage.PASSWORD_REQUIRE}` + ); + }); + + it(`should return ${HTTPCode.UNPROCESSED_ENTITY} of too short ${UserPayloadKey.USERNAME} validation error`, async () => { + const [validTestUser] = TEST_USERS_CREDENTIALS; + + const response = await app + .inject() + .post(registerEndpoint) + .body({ + ...validTestUser, + [UserPayloadKey.USERNAME]: faker.string.alpha( + UserValidationRule.USERNAME_MIN_LENGTH - 1 + ) + }); + + expect(response.statusCode).toBe(HTTPCode.UNPROCESSED_ENTITY); + expect(response.json>().message).toBe( + UserValidationMessage.USERNAME_MIN_LENGTH + ); + }); + + it(`should return ${HTTPCode.UNPROCESSED_ENTITY} of too long ${UserPayloadKey.USERNAME} validation error`, async () => { + const [validTestUser] = TEST_USERS_CREDENTIALS; + + const response = await app + .inject() + .post(registerEndpoint) + .body({ + ...validTestUser, + [UserPayloadKey.USERNAME]: faker.string.alpha( + UserValidationRule.USERNAME_MAX_LENGTH + 2 + ) + }); + + expect(response.statusCode).toBe(HTTPCode.UNPROCESSED_ENTITY); + expect(response.json>().message).toBe( + UserValidationMessage.USERNAME_MAX_LENGTH + ); + }); + + it(`should return ${HTTPCode.UNPROCESSED_ENTITY} of empty ${UserPayloadKey.EMAIL} validation error`, async () => { + const [validTestUser] = TEST_USERS_CREDENTIALS; + const { [UserPayloadKey.EMAIL]: _email, ...user } = + validTestUser as UserRegisterRequestDto; + + const response = await app.inject().post(registerEndpoint).body(user); + + expect(response.statusCode).toBe(HTTPCode.UNPROCESSED_ENTITY); + expect(response.json>().message).toBe( + UserValidationMessage.EMAIL_REQUIRE + ); + }); + + it(`should return ${HTTPCode.UNPROCESSED_ENTITY} of wrong ${UserPayloadKey.EMAIL} validation error`, async () => { + const [validTestUser] = TEST_USERS_CREDENTIALS; + + const response = await app + .inject() + .post(registerEndpoint) + .body({ + ...validTestUser, + [UserPayloadKey.EMAIL]: faker.person.firstName() + }); + + expect(response.statusCode).toBe(HTTPCode.UNPROCESSED_ENTITY); + expect(response.json>().message).toBe( + UserValidationMessage.EMAIL_WRONG + ); + }); + + it(`should return ${HTTPCode.UNPROCESSED_ENTITY} of empty ${UserPayloadKey.PASSWORD} validation error`, async () => { + const [validTestUser] = TEST_USERS_CREDENTIALS; + const { [UserPayloadKey.PASSWORD]: _password, ...user } = + validTestUser as UserRegisterRequestDto; + + const response = await app.inject().post(registerEndpoint).body(user); + + expect(response.statusCode).toBe(HTTPCode.UNPROCESSED_ENTITY); + expect(response.json>().message).toBe( + UserValidationMessage.PASSWORD_REQUIRE + ); + }); + + it(`should return ${HTTPCode.UNPROCESSED_ENTITY} of too short ${UserPayloadKey.PASSWORD} validation error`, async () => { + const [validTestUser] = TEST_USERS_CREDENTIALS; + + const response = await app + .inject() + .post(registerEndpoint) + .body({ + ...validTestUser, + [UserPayloadKey.PASSWORD]: faker.internet.password({ + length: UserValidationRule.PASSWORD_MIN_LENGTH - 2 + }) + }); + + expect(response.statusCode).toBe(HTTPCode.UNPROCESSED_ENTITY); + expect(response.json>().message).toBe( + UserValidationMessage.PASSWORD_MIN_LENGTH + ); + }); + + it(`should return ${HTTPCode.UNPROCESSED_ENTITY} of too long ${UserPayloadKey.PASSWORD} validation error`, async () => { + const [validTestUser] = TEST_USERS_CREDENTIALS; + + const response = await app + .inject() + .post(registerEndpoint) + .body({ + ...validTestUser, + [UserPayloadKey.PASSWORD]: faker.internet.password({ + length: UserValidationRule.PASSWORD_MAX_LENGTH + 2 + }) + }); + + expect(response.statusCode).toBe(HTTPCode.UNPROCESSED_ENTITY); + expect(response.json>().message).toBe( + UserValidationMessage.PASSWORD_MAX_LENGTH + ); + }); + + it(`should return ${HTTPCode.CREATED} and create a new user`, async () => { + const [validTestUser] = TEST_USERS_CREDENTIALS as [ + UserRegisterRequestDto + ]; + + const response = await app + .inject() + .post(registerEndpoint) + .body(validTestUser); + + expect(response.statusCode).toBe(HTTPCode.CREATED); + expect(response.json()).toEqual( + expect.objectContaining({ + [UserPayloadKey.USERNAME]: validTestUser[UserPayloadKey.USERNAME], + [UserPayloadKey.EMAIL]: validTestUser[UserPayloadKey.EMAIL] + }) + ); + + const savedDatabaseUser = await select({ + table: DatabaseTableName.USERS, + condition: { id: response.json().id }, + limit: KNEX_SELECT_ONE_RECORD + }); + + expect(savedDatabaseUser).toEqual( + expect.objectContaining({ + [UserPayloadKey.USERNAME]: validTestUser[UserPayloadKey.USERNAME], + [UserPayloadKey.EMAIL]: validTestUser[UserPayloadKey.EMAIL] + }) + ); + }); + }); +}); diff --git a/server/tests/packages/user/libs/constants/constants.ts b/apps/backend/tests/modules/user/libs/constants/constants.ts similarity index 100% rename from server/tests/packages/user/libs/constants/constants.ts rename to apps/backend/tests/modules/user/libs/constants/constants.ts diff --git a/server/tests/packages/user/libs/constants/test-user-credentials.constant.ts b/apps/backend/tests/modules/user/libs/constants/test-user-credentials.constant.ts similarity index 85% rename from server/tests/packages/user/libs/constants/test-user-credentials.constant.ts rename to apps/backend/tests/modules/user/libs/constants/test-user-credentials.constant.ts index 80811fb5..717a9f1a 100644 --- a/server/tests/packages/user/libs/constants/test-user-credentials.constant.ts +++ b/apps/backend/tests/modules/user/libs/constants/test-user-credentials.constant.ts @@ -1,5 +1,5 @@ import { faker } from '@faker-js/faker'; -import { type UserRegisterRequestDto } from 'shared/dist/packages/user/user.js'; +import { UserRegisterRequestDto } from '~/packages/auth/auth.js'; import { UserPayloadKey } from '~/packages/user/user.js'; diff --git a/server/tests/packages/user/helpers/helpers.ts b/apps/backend/tests/modules/user/libs/helpers/helpers.ts similarity index 100% rename from server/tests/packages/user/helpers/helpers.ts rename to apps/backend/tests/modules/user/libs/helpers/helpers.ts diff --git a/server/tests/packages/user/helpers/setup-test-users/setup-test-users.helper.ts b/apps/backend/tests/modules/user/libs/helpers/setup-test-users/setup-test-users.helper.ts similarity index 68% rename from server/tests/packages/user/helpers/setup-test-users/setup-test-users.helper.ts rename to apps/backend/tests/modules/user/libs/helpers/setup-test-users/setup-test-users.helper.ts index 7e50f7fe..cdfa0571 100644 --- a/server/tests/packages/user/helpers/setup-test-users/setup-test-users.helper.ts +++ b/apps/backend/tests/modules/user/libs/helpers/setup-test-users/setup-test-users.helper.ts @@ -1,8 +1,8 @@ -import { DatabaseTableName } from '~/libs/packages/database/database.js'; +import { DatabaseTableName } from '~/libs/modules/database/database.js'; import { encryptSync } from '~/packages/auth/auth.js'; -import { type GetCrudHandlersFunction } from '../../../../libs/packages/database/libs/types/types.js'; -import { TEST_USERS_CREDENTIALS } from '../../libs/constants/constants.js'; +import { type GetCrudHandlersFunction } from '../../../../../libs/modules/database/libs/types/types.js'; +import { TEST_USERS_CREDENTIALS } from '../../constants/constants.js'; const hash = (password: string): string => encryptSync(password); diff --git a/server/tests/packages/user/user.ts b/apps/backend/tests/modules/user/user.ts similarity index 54% rename from server/tests/packages/user/user.ts rename to apps/backend/tests/modules/user/user.ts index 9c1d7982..4f584e3b 100644 --- a/server/tests/packages/user/user.ts +++ b/apps/backend/tests/modules/user/user.ts @@ -1,2 +1,2 @@ -export { setupTestUsers } from './helpers/helpers.js'; +export { setupTestUsers } from './libs/helpers/helpers.js'; export { TEST_USERS_CREDENTIALS } from './libs/constants/constants.js'; diff --git a/server/tsconfig.json b/apps/backend/tsconfig.json similarity index 53% rename from server/tsconfig.json rename to apps/backend/tsconfig.json index 932d479c..591c5496 100644 --- a/server/tsconfig.json +++ b/apps/backend/tsconfig.json @@ -1,11 +1,9 @@ { - "extends": "../tsconfig.json", + "extends": "../../tsconfig.json", "include": ["src/**/*.ts", "tests/**/*.ts", "knexfile.ts"], - "files": ["src/index.d.ts"], - "exclude": ["node_modules"], + "exclude": ["node_modules/*"], + "lib": ["ESNext"], "compilerOptions": { - "module": "NodeNext", - "moduleResolution": "NodeNext", "baseUrl": ".", "paths": { "~/*": ["./src/*"] diff --git a/packages/shared/package.json b/packages/shared/package.json index 56fa2757..0f251997 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,5 +1,5 @@ { - "name": "shared", + "name": "@thread-js/shared", "private": true, "engines": { "node": "18.18.x", diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index ef4c02ee..69573ca9 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -2,5 +2,25 @@ export { APIPath, AppEnvironment, ExceptionMessage, - ExceptionName + ExceptionName, + ServerErrorType } from './libs/enums/enums.js'; +export { HttpError, ValidationError } from './libs/exceptions/exceptions.js'; +export { type Configurable } from './libs/modules/config/config.js'; +export { HTTPCode, HttpHeader, HTTPMethod } from './libs/modules/http/http.js'; +export { + type ValueOf, + type ValidationSchema, + type ServerCommonErrorResponse, + type ServerErrorResponse, + type ServerValidationErrorResponse +} from './libs/types/types.js'; +export { AuthApiPath, registration } from './modules/auth/auth.js'; +export { + UserPayloadKey, + UserValidationMessage, + UserValidationRule, + type User, + type UserRegisterRequestDto, + type UserRegisterResponseDto +} from './modules/user/user.js'; diff --git a/packages/shared/src/libs/enums/enums.ts b/packages/shared/src/libs/enums/enums.ts index 7488714d..0dede2b0 100644 --- a/packages/shared/src/libs/enums/enums.ts +++ b/packages/shared/src/libs/enums/enums.ts @@ -2,3 +2,4 @@ export { APIPath } from './api-path.enum.js'; export { AppEnvironment } from './app-environment.js'; export { ExceptionMessage } from './exception-message.enum.js'; export { ExceptionName } from './exception-name.enum.js'; +export { ServerErrorType } from './server-error-type.enum.js'; diff --git a/packages/shared/src/libs/enums/server-error-type.enum.ts b/packages/shared/src/libs/enums/server-error-type.enum.ts new file mode 100644 index 00000000..0700118c --- /dev/null +++ b/packages/shared/src/libs/enums/server-error-type.enum.ts @@ -0,0 +1,6 @@ +const ServerErrorType = { + COMMON: 'COMMON', + VALIDATION: 'VALIDATION' +} as const; + +export { ServerErrorType }; diff --git a/packages/shared/src/libs/exceptions/exceptions.ts b/packages/shared/src/libs/exceptions/exceptions.ts index 284bad0c..7d28e3ac 100644 --- a/packages/shared/src/libs/exceptions/exceptions.ts +++ b/packages/shared/src/libs/exceptions/exceptions.ts @@ -1,2 +1,2 @@ export { HttpError } from './http-error/http-error.exception.js'; -export { InvalidCredentialsError } from './invalid-credentials-error/invalid-credentials-error.exception.js'; +export { ValidationError } from './validation-error/validation-error.exception.js'; diff --git a/packages/shared/src/libs/exceptions/http-error/http-error.exception.ts b/packages/shared/src/libs/exceptions/http-error/http-error.exception.ts index 808352a6..7a3c588c 100644 --- a/packages/shared/src/libs/exceptions/http-error/http-error.exception.ts +++ b/packages/shared/src/libs/exceptions/http-error/http-error.exception.ts @@ -1,20 +1,20 @@ import { type ValueOf } from '~/libs/types/types.js'; import { ExceptionName } from '../../enums/enums.js'; -import { HttpCode } from '../../modules/http/http.js'; +import { HTTPCode } from '../../modules/http/http.js'; const DEFAULT_MESSAGE = 'Network Error'; type Constructor = { - status: ValueOf; + status: ValueOf; message: string; }; class HttpError extends Error { - public status: ValueOf; + public status: ValueOf; public constructor({ - status = HttpCode.INTERNAL_SERVER_ERROR, + status = HTTPCode.INTERNAL_SERVER_ERROR, message = DEFAULT_MESSAGE }: Partial = {}) { super(message); diff --git a/packages/shared/src/libs/exceptions/invalid-credentials-error/invalid-credentials-error.exception.ts b/packages/shared/src/libs/exceptions/invalid-credentials-error/invalid-credentials-error.exception.ts deleted file mode 100644 index abe4b6a2..00000000 --- a/packages/shared/src/libs/exceptions/invalid-credentials-error/invalid-credentials-error.exception.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ExceptionMessage, ExceptionName } from '../../enums/enums.js'; - -class InvalidCredentialsError extends Error { - public constructor(message: string = ExceptionMessage.INCORRECT_EMAIL) { - super(message); - this.name = ExceptionName.INVALID_CREDENTIALS; - } -} - -export { InvalidCredentialsError }; diff --git a/packages/shared/src/libs/exceptions/validation-error/validation-error.exception.ts b/packages/shared/src/libs/exceptions/validation-error/validation-error.exception.ts new file mode 100644 index 00000000..87685892 --- /dev/null +++ b/packages/shared/src/libs/exceptions/validation-error/validation-error.exception.ts @@ -0,0 +1,5 @@ +import joi from 'joi'; + +class ValidationError extends joi.ValidationError {} + +export { ValidationError }; diff --git a/packages/shared/src/libs/helpers/date/date.ts b/packages/shared/src/libs/helpers/date/date.ts deleted file mode 100644 index d8f9c5c6..00000000 --- a/packages/shared/src/libs/helpers/date/date.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { getDiff } from './get-diff/get-diff.helper.js'; -export { getFromNowTime } from './get-from-now-time/get-from-now-time.helper.js'; diff --git a/packages/shared/src/libs/helpers/date/dayjs/dayjs.ts b/packages/shared/src/libs/helpers/date/dayjs/dayjs.ts deleted file mode 100644 index 86f72f91..00000000 --- a/packages/shared/src/libs/helpers/date/dayjs/dayjs.ts +++ /dev/null @@ -1,6 +0,0 @@ -import dayjs from 'dayjs'; -import relativeTime from 'dayjs/plugin/relativeTime.js'; - -dayjs.extend(relativeTime); - -export { default as dayjs } from 'dayjs'; diff --git a/packages/shared/src/libs/helpers/date/get-diff/get-diff.helper.ts b/packages/shared/src/libs/helpers/date/get-diff/get-diff.helper.ts deleted file mode 100644 index cfa7efbd..00000000 --- a/packages/shared/src/libs/helpers/date/get-diff/get-diff.helper.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { dayjs } from '../dayjs/dayjs.js'; - -const getDiff = (a: Date | string, b: Date | string): number => { - return dayjs(a).diff(b); -}; - -export { getDiff }; diff --git a/packages/shared/src/libs/helpers/date/get-from-now-time/get-from-now-time.helper.ts b/packages/shared/src/libs/helpers/date/get-from-now-time/get-from-now-time.helper.ts deleted file mode 100644 index 18cc167d..00000000 --- a/packages/shared/src/libs/helpers/date/get-from-now-time/get-from-now-time.helper.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { dayjs } from '../dayjs/dayjs.js'; - -const getFromNowTime = (date: Date | string): string => dayjs(date).fromNow(); - -export { getFromNowTime }; diff --git a/packages/shared/src/libs/helpers/helpers.ts b/packages/shared/src/libs/helpers/helpers.ts deleted file mode 100644 index 14e76164..00000000 --- a/packages/shared/src/libs/helpers/helpers.ts +++ /dev/null @@ -1 +0,0 @@ -export { getDiff, getFromNowTime } from './date/date.js'; diff --git a/packages/shared/src/libs/modules/http/http.ts b/packages/shared/src/libs/modules/http/http.ts index 5e56e9b2..4b4ec0a1 100644 --- a/packages/shared/src/libs/modules/http/http.ts +++ b/packages/shared/src/libs/modules/http/http.ts @@ -1 +1 @@ -export { HttpCode, HttpHeader, HttpMethod } from './libs/enums/enums.js'; +export { HTTPCode, HttpHeader, HTTPMethod } from './libs/enums/enums.js'; diff --git a/packages/shared/src/libs/modules/http/libs/enums/enums.ts b/packages/shared/src/libs/modules/http/libs/enums/enums.ts index cf99b938..de4be24d 100644 --- a/packages/shared/src/libs/modules/http/libs/enums/enums.ts +++ b/packages/shared/src/libs/modules/http/libs/enums/enums.ts @@ -1,3 +1,3 @@ -export { HttpCode } from './http-code.enum.js'; +export { HTTPCode } from './http-code.enum.js'; export { HttpHeader } from './http-header.enum.js'; -export { HttpMethod } from './http-method.enum.js'; +export { HTTPMethod } from './http-method.enum.js'; diff --git a/packages/shared/src/libs/modules/http/libs/enums/http-code.enum.ts b/packages/shared/src/libs/modules/http/libs/enums/http-code.enum.ts index 40fc7528..b225b324 100644 --- a/packages/shared/src/libs/modules/http/libs/enums/http-code.enum.ts +++ b/packages/shared/src/libs/modules/http/libs/enums/http-code.enum.ts @@ -1,11 +1,12 @@ -const HttpCode = { +const HTTPCode = { OK: 200, CREATED: 201, BAD_REQUEST: 400, UNAUTHORIZED: 401, FORBIDDEN: 403, NOT_FOUND: 404, + UNPROCESSED_ENTITY: 422, INTERNAL_SERVER_ERROR: 500 } as const; -export { HttpCode }; +export { HTTPCode }; diff --git a/packages/shared/src/libs/modules/http/libs/enums/http-method.enum.ts b/packages/shared/src/libs/modules/http/libs/enums/http-method.enum.ts index bac2761b..ecf26373 100644 --- a/packages/shared/src/libs/modules/http/libs/enums/http-method.enum.ts +++ b/packages/shared/src/libs/modules/http/libs/enums/http-method.enum.ts @@ -1,8 +1,8 @@ -const HttpMethod = { +const HTTPMethod = { GET: 'GET', POST: 'POST', PUT: 'PUT', DELETE: 'DELETE' } as const; -export { HttpMethod }; +export { HTTPMethod }; diff --git a/packages/shared/src/libs/types/error/error.ts b/packages/shared/src/libs/types/error/error.ts new file mode 100644 index 00000000..53e1b32f --- /dev/null +++ b/packages/shared/src/libs/types/error/error.ts @@ -0,0 +1,5 @@ +export { + type ServerCommonErrorResponse, + type ServerErrorResponse, + type ServerValidationErrorResponse +} from './server-error-response.type.js'; diff --git a/packages/shared/src/libs/types/error/server-error-detail.type.ts b/packages/shared/src/libs/types/error/server-error-detail.type.ts new file mode 100644 index 00000000..423dfc2a --- /dev/null +++ b/packages/shared/src/libs/types/error/server-error-detail.type.ts @@ -0,0 +1,6 @@ +type ServerErrorDetail = { + path: (number | string)[]; + message: string; +}; + +export { type ServerErrorDetail }; diff --git a/packages/shared/src/libs/types/error/server-error-response.type.ts b/packages/shared/src/libs/types/error/server-error-response.type.ts new file mode 100644 index 00000000..d9a66b5b --- /dev/null +++ b/packages/shared/src/libs/types/error/server-error-response.type.ts @@ -0,0 +1,25 @@ +import { type ServerErrorType } from '~/libs/enums/enums.js'; + +import { type ServerErrorDetail } from './server-error-detail.type.js'; + +type ServerValidationErrorResponse = { + errorType: typeof ServerErrorType.VALIDATION; + message: string; + details: ServerErrorDetail[]; +}; + +type ServerCommonErrorResponse = { + errorType: typeof ServerErrorType.COMMON; + message: string; +}; + + +type ServerErrorResponse = + | ServerValidationErrorResponse + | ServerCommonErrorResponse; + +export { + type ServerCommonErrorResponse, + type ServerErrorResponse, + type ServerValidationErrorResponse, +}; diff --git a/packages/shared/src/libs/types/types.ts b/packages/shared/src/libs/types/types.ts index 7ab57e99..94eace42 100644 --- a/packages/shared/src/libs/types/types.ts +++ b/packages/shared/src/libs/types/types.ts @@ -1,2 +1,7 @@ export { type ValueOf } from './generic/generic.js'; export { type ValidationSchema } from './validation/validation.js'; +export { + type ServerCommonErrorResponse, + type ServerErrorResponse, + type ServerValidationErrorResponse +} from './error/error.js'; diff --git a/packages/shared/src/modules/user/libs/types/user.type.ts b/packages/shared/src/modules/user/libs/types/user.type.ts index 29a0c41a..6d85dc32 100644 --- a/packages/shared/src/modules/user/libs/types/user.type.ts +++ b/packages/shared/src/modules/user/libs/types/user.type.ts @@ -2,7 +2,6 @@ type User = { id: number; email: string; username: string; - imageId: number | null; createdAt: string; updatedAt: string; }; diff --git a/server/knexfile.ts b/server/knexfile.ts deleted file mode 100644 index 3e8752cc..00000000 --- a/server/knexfile.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { database } from '~/libs/packages/database/database.js'; - -export default database.environmentsConfig; diff --git a/server/src/db/migrations/20211208202419_create_tables.ts b/server/src/db/migrations/20211208202419_create_tables.ts deleted file mode 100644 index 0f7646cd..00000000 --- a/server/src/db/migrations/20211208202419_create_tables.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { type Knex } from 'knex'; - -const TableName = { - USERS: 'users', - POSTS: 'posts', - COMMENTS: 'comments', - POST_REACTIONS: 'post_reactions', - IMAGES: 'images' -} as const; - -const ColumnName = { - BODY: 'body', - CREATED_AT: 'created_at', - EMAIL: 'email', - ID: 'id', - IS_LIKE: 'is_like', - LINK: 'link', - PASSWORD: 'password', - UPDATED_AT: 'updated_at', - USERNAME: 'username' -} as const; - -export async function up(knex: Knex): Promise { - await knex.schema.createTable(TableName.USERS, table => { - table.increments(ColumnName.ID).primary(); - table.string(ColumnName.EMAIL).notNullable().unique(); - table.string(ColumnName.USERNAME).notNullable().unique(); - table.string(ColumnName.PASSWORD).notNullable(); - table - .dateTime(ColumnName.CREATED_AT) - .notNullable() - .defaultTo(knex.fn.now()); - table - .dateTime(ColumnName.UPDATED_AT) - .notNullable() - .defaultTo(knex.fn.now()); - }); - - await knex.schema.createTable(TableName.POSTS, table => { - table.increments(ColumnName.ID).primary(); - table.text(ColumnName.BODY).notNullable(); - table - .dateTime(ColumnName.CREATED_AT) - .notNullable() - .defaultTo(knex.fn.now()); - table - .dateTime(ColumnName.UPDATED_AT) - .notNullable() - .defaultTo(knex.fn.now()); - }); - - await knex.schema.createTable(TableName.COMMENTS, table => { - table.increments(ColumnName.ID).primary(); - table.text(ColumnName.BODY).notNullable(); - table - .dateTime(ColumnName.CREATED_AT) - .notNullable() - .defaultTo(knex.fn.now()); - table - .dateTime(ColumnName.UPDATED_AT) - .notNullable() - .defaultTo(knex.fn.now()); - }); - - await knex.schema.createTable(TableName.POST_REACTIONS, table => { - table.increments(ColumnName.ID).primary(); - table.boolean(ColumnName.IS_LIKE).notNullable().defaultTo(true); - table - .dateTime(ColumnName.CREATED_AT) - .notNullable() - .defaultTo(knex.fn.now()); - table - .dateTime(ColumnName.UPDATED_AT) - .notNullable() - .defaultTo(knex.fn.now()); - }); - - await knex.schema.createTable(TableName.IMAGES, table => { - table.increments(ColumnName.ID).primary(); - table.string(ColumnName.LINK).notNullable(); - table - .dateTime(ColumnName.CREATED_AT) - .notNullable() - .defaultTo(knex.fn.now()); - table - .dateTime(ColumnName.UPDATED_AT) - .notNullable() - .defaultTo(knex.fn.now()); - }); -} -export async function down(knex: Knex): Promise { - await knex.schema.dropTableIfExists(TableName.USERS); - await knex.schema.dropTableIfExists(TableName.POSTS); - await knex.schema.dropTableIfExists(TableName.COMMENTS); - await knex.schema.dropTableIfExists(TableName.POST_REACTIONS); - await knex.schema.dropTableIfExists(TableName.IMAGES); -} diff --git a/server/src/db/migrations/20211208204457_add_associations.ts b/server/src/db/migrations/20211208204457_add_associations.ts deleted file mode 100644 index 4ae7e7c1..00000000 --- a/server/src/db/migrations/20211208204457_add_associations.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { type Knex } from 'knex'; - -const TableName = { - USERS: 'users', - POSTS: 'posts', - COMMENTS: 'comments', - POST_REACTIONS: 'post_reactions', - IMAGES: 'images' -}; - -const ColumnName = { - ID: 'id', - IMAGE_ID: 'image_id', - POST_ID: 'post_id', - USER_ID: 'user_id' -}; - -const RelationRule = { - CASCADE: 'CASCADE', - SET_NULL: 'SET NULL' -}; - -export async function up(knex: Knex): Promise { - await knex.schema.alterTable(TableName.USERS, table => { - table - .integer(ColumnName.IMAGE_ID) - .references(ColumnName.ID) - .inTable(TableName.IMAGES) - .onUpdate(RelationRule.CASCADE) - .onDelete(RelationRule.SET_NULL); - }); - await knex.schema.alterTable(TableName.POSTS, table => { - table - .integer(ColumnName.IMAGE_ID) - .references(ColumnName.ID) - .inTable(TableName.IMAGES) - .onUpdate(RelationRule.CASCADE) - .onDelete(RelationRule.SET_NULL); - table - .integer(ColumnName.USER_ID) - .references(ColumnName.ID) - .inTable(TableName.USERS) - .onUpdate(RelationRule.CASCADE) - .onDelete(RelationRule.SET_NULL); - }); - await knex.schema.alterTable(TableName.POST_REACTIONS, table => { - table - .integer(ColumnName.USER_ID) - .references(ColumnName.ID) - .inTable(TableName.USERS) - .onUpdate(RelationRule.CASCADE) - .onDelete(RelationRule.SET_NULL); - table - .integer(ColumnName.POST_ID) - .references(ColumnName.ID) - .inTable(TableName.POSTS) - .onUpdate(RelationRule.CASCADE) - .onDelete(RelationRule.SET_NULL); - }); - await knex.schema.alterTable(TableName.COMMENTS, table => { - table - .integer(ColumnName.USER_ID) - .references(ColumnName.ID) - .inTable(TableName.USERS) - .onUpdate(RelationRule.CASCADE) - .onDelete(RelationRule.SET_NULL); - table - .integer(ColumnName.POST_ID) - .references(ColumnName.ID) - .inTable(TableName.POSTS) - .onUpdate(RelationRule.CASCADE) - .onDelete(RelationRule.SET_NULL); - }); -} -export async function down(knex: Knex): Promise { - await knex.schema.alterTable(TableName.USERS, table => { - table.dropColumn(ColumnName.IMAGE_ID); - }); - await knex.schema.alterTable(TableName.POSTS, table => { - table.dropColumn(ColumnName.IMAGE_ID); - table.dropColumn(ColumnName.USER_ID); - }); - await knex.schema.alterTable(TableName.POST_REACTIONS, table => { - table.dropColumn(ColumnName.USER_ID); - table.dropColumn(ColumnName.POST_ID); - }); - await knex.schema.alterTable(TableName.COMMENTS, table => { - table.dropColumn(ColumnName.USER_ID); - table.dropColumn(ColumnName.POST_ID); - }); -} diff --git a/server/src/db/seed-data/comments-seed.ts b/server/src/db/seed-data/comments-seed.ts deleted file mode 100644 index b7f81a3c..00000000 --- a/server/src/db/seed-data/comments-seed.ts +++ /dev/null @@ -1,32 +0,0 @@ -const commentsSeed = [ - 'laudantium enim quasi est quidem magnam voluptate ipsam eos\ntempora quo necessitatibus\ndolor quam autem quasi\nreiciendis et nam sapiente accusantium', - 'est natus enim nihil est dolore omnis voluptatem numquam\net omnis occaecati quod ullam at\nvoluptatem error expedita pariatur\nnihil sint nostrum voluptatem reiciendis et', - 'quia molestiae reprehenderit quasi aspernatur\naut expedita occaecati aliquam eveniet laudantium\nomnis quibusdam delectus saepe quia accusamus maiores nam est\ncum et ducimus et vero voluptates excepturi deleniti ratione', - 'non et atque\noccaecati deserunt quas accusantium unde odit nobis qui voluptatem\nquia voluptas consequuntur itaque dolor\net qui rerum deleniti ut occaecati', - 'harum non quasi et ratione\ntempore iure ex voluptates in ratione\nharum architecto fugit inventore cupiditate\nvoluptates magni quo et', - 'doloribus at sed quis culpa deserunt consectetur qui praesentium\naccusamus fugiat dicta\nvoluptatem rerum ut voluptate autem\nvoluptatem repellendus aspernatur dolorem in', - 'maiores sed dolores similique labore et inventore et\nquasi temporibus esse sunt id et\neos voluptatem aliquam\naliquid ratione corporis molestiae mollitia quia et magnam dolor', - 'ut voluptatem corrupti velit\nad voluptatem maiores\net nisi velit vero accusamus maiores\nvoluptates quia aliquid ullam eaque', - 'sapiente assumenda molestiae atque\nadipisci laborum distinctio aperiam et ab ut omnis\net occaecati aspernatur odit sit rem expedita\nquas enim ipsam minus', - 'voluptate iusto quis nobis reprehenderit ipsum amet nulla\nquia quas dolores velit et non\naut quia necessitatibus\nnostrum quaerat nulla et accusamus nisi facilis', - 'ut dolorum nostrum id quia aut est\nfuga est inventore vel eligendi explicabo quis consectetur\naut occaecati repellat id natus quo est\nut blanditiis quia ut vel ut maiores ea', - 'expedita maiores dignissimos facilis\nipsum est rem est fugit velit sequi\neum odio dolores dolor totam\noccaecati ratione eius rem velit', - 'fuga eos qui dolor rerum\ninventore corporis exercitationem\ncorporis cupiditate et deserunt recusandae est sed quis culpa\neum maiores corporis et', - 'vel quae voluptas qui exercitationem\nvoluptatibus unde sed\nminima et qui ipsam aspernatur\nexpedita magnam laudantium et et quaerat ut qui dolorum', - 'nihil ut voluptates blanditiis autem odio dicta rerum\nquisquam saepe et est\nsunt quasi nemo laudantium deserunt\nmolestias tempora quo quia', - 'iste ut laborum aliquid velit facere itaque\nquo ut soluta dicta voluptate\nerror tempore aut et\nsequi reiciendis dignissimos expedita consequuntur libero sed fugiat facilis', - 'consequatur necessitatibus totam sed sit dolorum\nrecusandae quae odio excepturi voluptatum harum voluptas\nquisquam sit ad eveniet delectus\ndoloribus odio qui non labore', - 'veritatis voluptates necessitatibus maiores corrupti\nneque et exercitationem amet sit et\nullam velit sit magnam laborum\nmagni ut molestias', - 'doloribus est illo sed minima aperiam\nut dignissimos accusantium tempore atque et aut molestiae\nmagni ut accusamus voluptatem quos ut voluptates\nquisquam porro sed architecto ut', - 'qui harum consequatur fugiat\net eligendi perferendis at molestiae commodi ducimus\ndoloremque asperiores numquam qui\nut sit dignissimos reprehenderit tempore', - 'deleniti aut sed molestias explicabo\ncommodi odio ratione nesciunt\nvoluptate doloremque est\nnam autem error delectus', - 'qui ipsa animi nostrum praesentium voluptatibus odit\nqui non impedit cum qui nostrum aliquid fuga explicabo\nvoluptatem fugit earum voluptas exercitationem temporibus dignissimos distinctio\nesse inventore reprehenderit quidem ut incidunt nihil necessitatibus rerum', - 'voluptates provident repellendus iusto perspiciatis ex fugiat ut\nut dolor nam aliquid et expedita voluptate\nsunt vitae illo rerum in quos\nvel eligendi enim quae fugiat est', - 'repudiandae repellat quia\nsequi est dolore explicabo nihil et\net sit et\net praesentium iste atque asperiores tenetur', - 'sunt aut quae laboriosam sit ut impedit\nadipisci harum laborum totam deleniti voluptas odit rem ea\nnon iure distinctio ut velit doloribus\net non ex', - 'incidunt sapiente eaque dolor eos\nad est molestias\nquas sit et nihil exercitationem at cumque ullam\nnihil magnam et', - 'nisi vel quas ut laborum ratione\nrerum magni eum\nunde et voluptatem saepe\nvoluptas corporis modi amet ipsam eos saepe porro', - 'voluptatem repellendus quo alias at laudantium\nmollitia quidem esse\ntemporibus consequuntur vitae rerum illum\nid corporis sit id' -].map(body => ({ body })); - -export { commentsSeed }; diff --git a/server/src/db/seed-data/posts-seed.ts b/server/src/db/seed-data/posts-seed.ts deleted file mode 100644 index 2e26845c..00000000 --- a/server/src/db/seed-data/posts-seed.ts +++ /dev/null @@ -1,21 +0,0 @@ -const postsSeed = [ - 'quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto', - 'est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla', - 'et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut', - 'ullam et saepe reiciendis voluptatem adipisci\nsit amet autem assumenda provident rerum culpa\nquis hic commodi nesciunt rem tenetur doloremque ipsam iure\nquis sunt voluptatem rerum illo velit', - 'repudiandae veniam quaerat sunt sed\nalias aut fugiat sit autem sed est\nvoluptatem omnis possimus esse voluptatibus quis\nest aut tenetur dolor neque', - 'ut aspernatur corporis harum nihil quis provident sequi\nmollitia nobis aliquid molestiae\nperspiciatis et ea nemo ab reprehenderit accusantium quas\nvoluptate dolores velit et doloremque molestiae', - 'dolore placeat quibusdam ea quo vitae\nmagni quis enim qui quis quo nemo aut saepe\nquidem repellat excepturi ut quia\nsunt ut sequi eos ea sed quas', - 'dignissimos aperiam dolorem qui eum\nfacilis quibusdam animi sint suscipit qui sint possimus cum\nquaerat magni maiores excepturi\nipsam ut commodi dolor voluptatum modi aut vitae', - 'consectetur animi nesciunt iure dolore\nenim quia ad\nveniam autem ut quam aut nobis\net est aut quod aut provident voluptas autem voluptas', - 'quo et expedita modi cum officia vel magni\ndoloribus qui repudiandae\nvero nisi sit\nquos veniam quod sed accusamus veritatis error' -].map(body => ({ body })); - -// Do not add more images than the number of posts. -const postImagesSeed = [ - { - link: 'https://i.imgur.com/HwBQh72.jpg' - } -]; - -export { postImagesSeed, postsSeed }; diff --git a/server/src/db/seeds/fill-database.ts b/server/src/db/seeds/fill-database.ts deleted file mode 100644 index 4ce1c6e7..00000000 --- a/server/src/db/seeds/fill-database.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { type Knex } from 'knex'; - -import { commentsSeed } from '../seed-data/comments-seed.js'; -import { postImagesSeed, postsSeed } from '../seed-data/posts-seed.js'; -import { userImagesSeed, usersSeed } from '../seed-data/users-seed.js'; - -const TableName = { - USERS: 'users', - POSTS: 'posts', - COMMENTS: 'comments', - POST_REACTIONS: 'post_reactions', - IMAGES: 'images' -} as const; - -const ColumnName = { - IMAGE_ID: 'image_id', - IS_LIKE: 'is_like', - POST_ID: 'post_id', - USER_ID: 'user_id' -} as const; - -type SaveImageDto = { - link: string; -}; - -type Image = SaveImageDto & { - id: number; -}; - -type SaveUserDto = { - email: string; - username: string; - password: string; -}; - -type User = SaveUserDto & { - id: number; -}; - -type SavePostDto = { - body: string; - userId: number; -}; - -type Post = SavePostDto & { - id: number; -}; - -const getRandomIndex = (length: number): number => { - return Math.floor(Math.random() * length); -}; - -const mapLinks = (images: SaveImageDto[]): string[] => { - return images.map(image => image.link); -}; - -export async function seed(knex: Knex): Promise { - await knex.transaction(async trx => { - await trx(TableName.USERS).del(); - await trx(TableName.POSTS).del(); - await trx(TableName.COMMENTS).del(); - await trx(TableName.POST_REACTIONS).del(); - await trx(TableName.IMAGES).del(); - - await trx(TableName.IMAGES).insert([...userImagesSeed, ...postImagesSeed]); - - const userImages = await trx(TableName.IMAGES) - .select('id') - .whereIn('link', mapLinks(userImagesSeed)); - const postImages = await trx(TableName.IMAGES) - .select('id') - .whereIn('link', mapLinks(postImagesSeed)); - - const usersMappedSeed = usersSeed.map((user, index) => ({ - ...user, - [ColumnName.IMAGE_ID]: userImages[index] - ? (userImages[index] as Pick).id - : null - })); - const users = await trx(TableName.USERS) - .insert(usersMappedSeed) - .returning('*'); - - const postsMappedSeed = postsSeed.map((post, index) => ({ - ...post, - [ColumnName.USER_ID]: (users[getRandomIndex(users.length)] as User).id, - [ColumnName.IMAGE_ID]: postImages[index] - ? (postImages[index] as Pick).id - : null - })); - const posts = await trx(TableName.POSTS) - .insert(postsMappedSeed) - .returning('*'); - - const commentsMappedSeed = commentsSeed.map(comment => ({ - ...comment, - [ColumnName.USER_ID]: (users[getRandomIndex(users.length)] as User).id, - [ColumnName.POST_ID]: (posts[getRandomIndex(posts.length)] as Post).id - })); - await trx(TableName.COMMENTS).insert(commentsMappedSeed); - - const postReactionsMappedSeed = users.map(user => ({ - [ColumnName.IS_LIKE]: true, - [ColumnName.USER_ID]: user.id, - [ColumnName.POST_ID]: (posts[getRandomIndex(posts.length)] as Post).id - })); - await trx(TableName.POST_REACTIONS).insert(postReactionsMappedSeed); - }); -} diff --git a/server/src/index.d.ts b/server/src/index.d.ts deleted file mode 100644 index ce2933a8..00000000 --- a/server/src/index.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { type File } from 'fastify-multer/lib/interfaces.js'; -import { type Server as SocketServer } from 'socket.io'; - -import { type User } from '~/packages/user/user.js'; - -declare module 'fastify' { - interface FastifyRequest { - user?: User; - file?: File; - io: SocketServer; - } -} diff --git a/server/src/libs/enums/enums.ts b/server/src/libs/enums/enums.ts deleted file mode 100644 index afb855b3..00000000 --- a/server/src/libs/enums/enums.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { - ApiPath, - AppEnvironment, - ExceptionMessage, - ExceptionName -} from 'shared/dist/libs/enums/enums.js'; diff --git a/server/src/libs/exceptions/exceptions.ts b/server/src/libs/exceptions/exceptions.ts deleted file mode 100644 index d2ded1c6..00000000 --- a/server/src/libs/exceptions/exceptions.ts +++ /dev/null @@ -1 +0,0 @@ -export { InvalidCredentialsError } from 'shared/dist/libs/exceptions/exceptions.js'; diff --git a/server/src/libs/middlewares/image/image.middleware.ts b/server/src/libs/middlewares/image/image.middleware.ts deleted file mode 100644 index 877b8990..00000000 --- a/server/src/libs/middlewares/image/image.middleware.ts +++ /dev/null @@ -1,14 +0,0 @@ -import multer from 'fastify-multer'; - -import { config } from '~/libs/packages/config/config.js'; - -const storage = multer.memoryStorage(); - -const upload = multer({ - storage, - limits: { - fileSize: config.ENV.GYAZO.FILE_SIZE - } -}); - -export { upload }; diff --git a/server/src/libs/middlewares/middlewares.ts b/server/src/libs/middlewares/middlewares.ts deleted file mode 100644 index 105082c1..00000000 --- a/server/src/libs/middlewares/middlewares.ts +++ /dev/null @@ -1 +0,0 @@ -export { upload } from './image/image.middleware.js'; diff --git a/server/src/libs/packages/config/config.ts b/server/src/libs/packages/config/config.ts deleted file mode 100644 index fade993e..00000000 --- a/server/src/libs/packages/config/config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Config } from './config.package.js'; - -const config = new Config(); - -export { config }; -export { - type ConfigPackage, - type EnvironmentSchema -} from './libs/types/types.js'; diff --git a/server/src/libs/packages/config/libs/types/config-package.type.ts b/server/src/libs/packages/config/libs/types/config-package.type.ts deleted file mode 100644 index 60f9cd57..00000000 --- a/server/src/libs/packages/config/libs/types/config-package.type.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { type Configurable } from 'shared/dist/libs/packages/config/config.js'; - -import { type EnvironmentSchema } from './types.js'; - -type ConfigPackage = Configurable; - -export { type ConfigPackage }; diff --git a/server/src/libs/packages/controller/controller.api.ts b/server/src/libs/packages/controller/controller.api.ts deleted file mode 100644 index 3cb6095b..00000000 --- a/server/src/libs/packages/controller/controller.api.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { joinPath } from '~/libs/packages/path/path.js'; - -import { - type ControllerApi, - type ControllerRoute -} from './libs/types/types.js'; - -type Constructor = { - apiPath: string; -}; - -class Controller implements ControllerApi { - #apiPath: string; - - #routes: ControllerRoute[] = []; - - public get routes(): ControllerRoute[] { - return this.#routes; - } - - public constructor({ apiPath }: Constructor) { - this.#apiPath = apiPath; - } - - public addRoute = ({ url, ...options }: ControllerRoute): void => { - this.#routes.push({ - url: joinPath([this.#apiPath, url]), - ...options - }); - }; -} - -export { Controller }; diff --git a/server/src/libs/packages/controller/controller.ts b/server/src/libs/packages/controller/controller.ts deleted file mode 100644 index 5f3653a3..00000000 --- a/server/src/libs/packages/controller/controller.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { Controller } from './controller.api.js'; -export { ControllerHook } from './libs/enums/enums.js'; -export { type ControllerApi } from './libs/types/types.js'; diff --git a/server/src/libs/packages/controller/libs/types/controller-api.type.ts b/server/src/libs/packages/controller/libs/types/controller-api.type.ts deleted file mode 100644 index b26bb526..00000000 --- a/server/src/libs/packages/controller/libs/types/controller-api.type.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { type ControllerRoute } from './controller-route.type.js'; - -type ControllerApi = { - addRoute(_route: ControllerRoute): void; -}; - -export { type ControllerApi }; diff --git a/server/src/libs/packages/controller/libs/types/types.ts b/server/src/libs/packages/controller/libs/types/types.ts deleted file mode 100644 index 53efe130..00000000 --- a/server/src/libs/packages/controller/libs/types/types.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { type ControllerApi } from './controller-api.type.js'; -export { type ControllerRoute } from './controller-route.type.js'; diff --git a/server/src/libs/packages/database/database.ts b/server/src/libs/packages/database/database.ts deleted file mode 100644 index 776749d2..00000000 --- a/server/src/libs/packages/database/database.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { config } from '~/libs/packages/config/config.js'; - -import { Database } from './database.package.js'; - -const database = new Database({ config }); - -export { database }; -export { Abstract as AbstractModel } from './abstract.model.js'; -export { Abstract as AbstractRepository } from './abstract.repository.js'; -export { DatabaseTableName } from './libs/enums/enums.js'; -export { type DatabasePackage, type Repository } from './libs/types/types.js'; diff --git a/server/src/libs/packages/database/libs/enums/database-table-name.enum.ts b/server/src/libs/packages/database/libs/enums/database-table-name.enum.ts deleted file mode 100644 index f5ab6b78..00000000 --- a/server/src/libs/packages/database/libs/enums/database-table-name.enum.ts +++ /dev/null @@ -1,9 +0,0 @@ -const DatabaseTableName = { - COMMENTS: 'comments', - IMAGES: 'images', - POST_REACTIONS: 'postReactions', - POSTS: 'posts', - USERS: 'users' -} as const; - -export { DatabaseTableName }; diff --git a/server/src/libs/packages/database/libs/types/types.ts b/server/src/libs/packages/database/libs/types/types.ts deleted file mode 100644 index b4fbf452..00000000 --- a/server/src/libs/packages/database/libs/types/types.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { type DatabasePackage } from './database-package.type.js'; -export { type Repository } from './repository.type.js'; diff --git a/server/src/libs/packages/http/http.service.ts b/server/src/libs/packages/http/http.service.ts deleted file mode 100644 index dcf7d1eb..00000000 --- a/server/src/libs/packages/http/http.service.ts +++ /dev/null @@ -1,49 +0,0 @@ -import axios, { - type AxiosError, - type AxiosInstance, - type AxiosResponse -} from 'axios'; - -import { HttpMethod } from '~/libs/packages/http/http.js'; - -import { type HttpLoadOptions, type HttpService } from './libs/types/types.js'; - -class Http implements HttpService { - #instance: AxiosInstance; - - public constructor() { - this.#instance = axios.create({ - timeout: 5000 - }); - } - - public load( - url: string, - options?: HttpLoadOptions - ): Promise | never { - const { data, headers, method = HttpMethod.GET } = options ?? {}; - - return this.#instance - .request({ - url, - method, - headers: headers as NonNullable, - data - }) - .then(this.#getData) - .catch(this.#catchError); - } - - #getData = (response: T): AxiosResponse['data'] => { - return (response as AxiosResponse).data; - }; - - #catchError = (error: AxiosError): never => { - const { response } = error; - const { data } = response as AxiosResponse; - - throw new Error((data as Error).toString()); - }; -} - -export { Http }; diff --git a/server/src/libs/packages/http/http.ts b/server/src/libs/packages/http/http.ts deleted file mode 100644 index 67f4738a..00000000 --- a/server/src/libs/packages/http/http.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Http as HttpService } from './http.service.js'; - -const httpService = new HttpService(); - -export { httpService }; -export { HttpCode, HttpHeader, HttpMethod } from './libs/enums/enums.js'; -export { type HttpService } from './libs/types/types.js'; diff --git a/server/src/libs/packages/http/libs/enums/enums.ts b/server/src/libs/packages/http/libs/enums/enums.ts deleted file mode 100644 index b2aa4d17..00000000 --- a/server/src/libs/packages/http/libs/enums/enums.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { - HttpCode, - HttpHeader, - HttpMethod -} from 'shared/dist/libs/packages/http/http.js'; diff --git a/server/src/libs/packages/http/libs/types/http-load-options.type.ts b/server/src/libs/packages/http/libs/types/http-load-options.type.ts deleted file mode 100644 index 0bddefa7..00000000 --- a/server/src/libs/packages/http/libs/types/http-load-options.type.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { type RawAxiosRequestHeaders } from 'axios'; - -import { type ValueOf } from '~/libs/types/types.js'; - -import { type HttpMethod } from '../enums/enums.js'; - -type HttpLoadOptions = { - method: ValueOf; - data: T; - headers: RawAxiosRequestHeaders; -}; - -export { type HttpLoadOptions }; diff --git a/server/src/libs/packages/http/libs/types/http-service.type.ts b/server/src/libs/packages/http/libs/types/http-service.type.ts deleted file mode 100644 index 0ed16079..00000000 --- a/server/src/libs/packages/http/libs/types/http-service.type.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { type HttpLoadOptions } from './http-load-options.type.js'; - -type HttpService = { - load(_url: string, _options?: HttpLoadOptions): Promise; -}; - -export { type HttpService }; diff --git a/server/src/libs/packages/http/libs/types/types.ts b/server/src/libs/packages/http/libs/types/types.ts deleted file mode 100644 index e3eef0d8..00000000 --- a/server/src/libs/packages/http/libs/types/types.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { type HttpLoadOptions } from './http-load-options.type.js'; -export { type HttpService } from './http-service.type.js'; diff --git a/server/src/libs/packages/server-application/libs/constants/api.constants.ts b/server/src/libs/packages/server-application/libs/constants/api.constants.ts deleted file mode 100644 index 57871571..00000000 --- a/server/src/libs/packages/server-application/libs/constants/api.constants.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ApiPath } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { AuthApiPath } from '~/packages/auth/auth.js'; - -const WHITE_ROUTES = [ - `${config.ENV.APP.API_PATH}${ApiPath.AUTH}${AuthApiPath.LOGIN}`, - `${config.ENV.APP.API_PATH}${ApiPath.AUTH}${AuthApiPath.REGISTER}` -]; - -export { WHITE_ROUTES }; diff --git a/server/src/libs/packages/server-application/libs/constants/constants.ts b/server/src/libs/packages/server-application/libs/constants/constants.ts deleted file mode 100644 index 6fb9426b..00000000 --- a/server/src/libs/packages/server-application/libs/constants/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export { WHITE_ROUTES } from './api.constants.js'; diff --git a/server/src/libs/packages/server-application/libs/types/server-app-api.type.ts b/server/src/libs/packages/server-application/libs/types/server-app-api.type.ts deleted file mode 100644 index 16f7a64c..00000000 --- a/server/src/libs/packages/server-application/libs/types/server-app-api.type.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { type Controller } from '~/libs/packages/controller/controller.js'; - -type ServerApi = { - controllers: Controller[]; -}; - -export { type ServerApi }; diff --git a/server/src/libs/packages/server-application/libs/types/types.ts b/server/src/libs/packages/server-application/libs/types/types.ts deleted file mode 100644 index 46fdba3b..00000000 --- a/server/src/libs/packages/server-application/libs/types/types.ts +++ /dev/null @@ -1 +0,0 @@ -export { type ServerApi } from './server-app-api.type.js'; diff --git a/server/src/libs/packages/server-application/server-app-api.ts b/server/src/libs/packages/server-application/server-app-api.ts deleted file mode 100644 index 928d58b3..00000000 --- a/server/src/libs/packages/server-application/server-app-api.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { type Controller } from '../controller/controller.js'; -import { type ServerApi } from './libs/types/types.js'; - -type Constructor = { - controllers: Controller[]; -}; - -class ServerAppApi implements ServerApi { - #controllers: Controller[]; - - public constructor({ controllers }: Constructor) { - this.#controllers = controllers; - } - - public get controllers(): Controller[] { - return this.#controllers; - } -} - -export { ServerAppApi }; diff --git a/server/src/libs/packages/server-application/server-app.ts b/server/src/libs/packages/server-application/server-app.ts deleted file mode 100644 index 605a1837..00000000 --- a/server/src/libs/packages/server-application/server-app.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { dirname, join } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -import cors from '@fastify/cors'; -import fastifyStatic from '@fastify/static'; -import fastify, { - type FastifyInstance, - type FastifyServerOptions -} from 'fastify'; -import { type FastifyValidationResult } from 'fastify/types/schema.js'; -import multer from 'fastify-multer'; - -import { type ConfigPackage } from '~/libs/packages/config/config.js'; -import { joinPath } from '~/libs/packages/path/path.js'; -import { socketService } from '~/libs/packages/socket/socket.js'; -import { - authorization as authorizationPlugin, - socketInjector as socketInjectorPlugin -} from '~/libs/plugins/plugins.js'; -import { type ValidationSchema } from '~/libs/types/types.js'; -import { authService } from '~/packages/auth/auth.js'; -import { userService } from '~/packages/user/user.js'; - -import { type DatabasePackage } from '../database/database.js'; -import { WHITE_ROUTES } from './libs/constants/constants.js'; -import { type ServerApi } from './libs/types/types.js'; - -type Constructor = { - config: ConfigPackage; - api: ServerApi; - options: FastifyServerOptions; - database: DatabasePackage; -}; - -class ServerApp { - #app: FastifyInstance; - - #config: ConfigPackage; - - #api: ServerApi; - - #database: DatabasePackage; - - public constructor({ config, options, api, database }: Constructor) { - this.#config = config; - - this.#app = this.#initApp(options); - - this.#api = api; - this.#database = database; - } - - public get app(): FastifyInstance { - return this.#app; - } - - public get database(): DatabasePackage { - return this.#database; - } - - #initApp = (options: FastifyServerOptions): FastifyInstance => { - const app = fastify(options); - socketService.initializeIo(app.server); - - return app; - }; - - public initialize = async (): Promise => { - this.#initValidationCompiler(); - await this.#registerServe(); - await this.#registerPlugins(); - this.#registerRoutes(); - - this.#database.connect(); - - return this; - }; - - #registerServe = async (): Promise => { - const staticPath = join( - dirname(fileURLToPath(import.meta.url)), - '../../../../client/build' - ); - - await this.#app.register(fastifyStatic, { - root: staticPath, - prefix: '/' - }); - - this.#app.setNotFoundHandler(async (_request, response) => { - await response.sendFile('index.html', staticPath); - }); - }; - - #registerPlugins = async (): Promise => { - await this.#app.register(multer.contentParser); - await this.#app.register(cors, { - origin: 'http://localhost:3000', - methods: '*', - credentials: true - }); - await this.#app.register(authorizationPlugin, { - services: { - userService, - authService - }, - routesWhiteList: WHITE_ROUTES - }); - await this.#app.register(socketInjectorPlugin, { io: socketService.io }); - }; - - #registerRoutes = (): void => { - const routers = this.#api.controllers.flatMap(it => it.routes); - - for (const it of routers) { - const { url: path, ...parameters } = it; - - this.app.route({ - url: joinPath([this.#config.ENV.APP.API_PATH, path]), - ...parameters - }); - } - }; - - #initValidationCompiler = (): void => { - this.#app.setValidatorCompiler(({ schema }) => { - return (data => { - return schema.validate(data, { - abortEarly: true - }); - }) as FastifyValidationResult; - }); - }; - - public start = async (): Promise | never => { - try { - await this.#app.listen({ - port: this.#config.ENV.APP.PORT, - host: this.#config.ENV.APP.HOST - }); - } catch (error) { - this.#app.log.error(error); - } - }; -} - -export { ServerApp }; diff --git a/server/src/libs/packages/socket/libs/enums/enums.ts b/server/src/libs/packages/socket/libs/enums/enums.ts deleted file mode 100644 index c575b052..00000000 --- a/server/src/libs/packages/socket/libs/enums/enums.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { - NotificationSocketEvent, - SocketEvent, - SocketNamespace -} from 'shared/dist/libs/packages/socket/socket.js'; diff --git a/server/src/libs/packages/socket/libs/types/socket-service.type.ts b/server/src/libs/packages/socket/libs/types/socket-service.type.ts deleted file mode 100644 index 382a55ea..00000000 --- a/server/src/libs/packages/socket/libs/types/socket-service.type.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { type Server } from 'node:http'; - -type SocketService = { - initializeIo(_server: Server): void; -}; - -export { type SocketService }; diff --git a/server/src/libs/packages/socket/libs/types/types.ts b/server/src/libs/packages/socket/libs/types/types.ts deleted file mode 100644 index 8f61e12d..00000000 --- a/server/src/libs/packages/socket/libs/types/types.ts +++ /dev/null @@ -1 +0,0 @@ -export { type SocketService } from './socket-service.type.js'; diff --git a/server/src/libs/packages/socket/socket.service.ts b/server/src/libs/packages/socket/socket.service.ts deleted file mode 100644 index 1899f532..00000000 --- a/server/src/libs/packages/socket/socket.service.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { type Server } from 'node:http'; - -import { type Socket as TSocket } from 'socket.io'; -import { Server as SocketServer } from 'socket.io'; - -import { SocketEvent, SocketNamespace } from './libs/enums/enums.js'; -import { type SocketService } from './libs/types/types.js'; - -class Socket implements SocketService { - #io!: SocketServer; - - public get io(): SocketServer { - return this.#io; - } - - public initializeIo = (server: Server): void => { - this.#io = new SocketServer(server); - this.#io - .of(SocketNamespace.NOTIFICATION) - .on(SocketEvent.CONNECTION, this.#notificationHandler); - }; - - #notificationHandler = (socket: TSocket): void => { - socket.on(SocketEvent.NOTIFICATION_JOIN_ROOM, (roomId: string) => { - void socket.join(roomId); - }); - - socket.on(SocketEvent.NOTIFICATION_LEAVE_ROOM, (roomId: string) => { - void socket.leave(roomId); - }); - }; -} - -export { Socket }; diff --git a/server/src/libs/packages/socket/socket.ts b/server/src/libs/packages/socket/socket.ts deleted file mode 100644 index decbc8c4..00000000 --- a/server/src/libs/packages/socket/socket.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Socket as SocketService } from './socket.service.js'; - -const socketService = new SocketService(); - -export { socketService }; -export { - NotificationSocketEvent, - SocketEvent, - SocketNamespace -} from './libs/enums/enums.js'; -export { type SocketService } from './libs/types/types.js'; diff --git a/server/src/libs/plugins/authorization/authorization.plugin.ts b/server/src/libs/plugins/authorization/authorization.plugin.ts deleted file mode 100644 index d17fce23..00000000 --- a/server/src/libs/plugins/authorization/authorization.plugin.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* eslint-disable @typescript-eslint/require-await */ -import fp from 'fastify-plugin'; - -import { ExceptionMessage } from '~/libs/enums/enums.js'; -import { InvalidCredentialsError } from '~/libs/exceptions/exceptions.js'; -import { ControllerHook } from '~/libs/packages/controller/controller.js'; -import { HttpCode, HttpHeader } from '~/libs/packages/http/http.js'; -import { type AuthService } from '~/packages/auth/auth.js'; -import { type UserService } from '~/packages/user/user.js'; - -type Options = { - routesWhiteList: string[]; - services: { - userService: UserService; - authService: AuthService; - }; -}; - -const authorization = fp( - async (fastify, { routesWhiteList, services }): Promise => { - fastify.decorateRequest('user', null); - - fastify.addHook(ControllerHook.ON_REQUEST, async (request, reply) => { - try { - const isWhiteRoute = routesWhiteList.includes(request.routerPath); - - if (isWhiteRoute) { - return; - } - - const [, token] = - (request.headers[HttpHeader.AUTHORIZATION] as string).split(' ') ?? - []; - const { userService, authService } = services; - const { id } = await authService.verifyToken>( - token as string - ); - - const authorizedUser = await userService.getById(id); - - if (!authorizedUser) { - throw new InvalidCredentialsError(ExceptionMessage.INVALID_TOKEN); - } - - request.user = authorizedUser; - } catch (error) { - void reply.code(HttpCode.UNAUTHORIZED).send(error); - } - }); - } -); - -export { authorization }; diff --git a/server/src/libs/plugins/plugins.ts b/server/src/libs/plugins/plugins.ts deleted file mode 100644 index a8a6c710..00000000 --- a/server/src/libs/plugins/plugins.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { authorization } from './authorization/authorization.plugin.js'; -export { socketInjector } from './socket-injector/socket-injector.plugin.js'; diff --git a/server/src/libs/plugins/socket-injector/socket-injector.plugin.ts b/server/src/libs/plugins/socket-injector/socket-injector.plugin.ts deleted file mode 100644 index cdfce45d..00000000 --- a/server/src/libs/plugins/socket-injector/socket-injector.plugin.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* eslint-disable @typescript-eslint/require-await */ -import fp from 'fastify-plugin'; -import { type Server as SocketServer } from 'socket.io'; - -import { ControllerHook } from '~/libs/packages/controller/controller.js'; - -type Options = { - io: SocketServer; -}; - -const socketInjector = fp(async (fastify, { io }): Promise => { - fastify.decorateRequest('io', null); - - fastify.addHook(ControllerHook.PRE_HANDLER, async (request, _reply) => { - request.io = io; - }); -}); - -export { socketInjector }; diff --git a/server/src/libs/types/types.ts b/server/src/libs/types/types.ts deleted file mode 100644 index ba67349d..00000000 --- a/server/src/libs/types/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { - type ValidationSchema, - type ValueOf -} from 'shared/dist/libs/types/types.js'; diff --git a/server/src/main.ts b/server/src/main.ts deleted file mode 100644 index 9cfe70d9..00000000 --- a/server/src/main.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { serverApp } from './libs/packages/server-application/server-application.js'; - -await serverApp.initialize().then(app => app.start()); diff --git a/server/src/packages/auth/auth.controller.ts b/server/src/packages/auth/auth.controller.ts deleted file mode 100644 index fd82cc1e..00000000 --- a/server/src/packages/auth/auth.controller.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { type FastifyReply, type FastifyRequest } from 'fastify'; - -import { type ApiPath } from '~/libs/enums/enums.js'; -import { - Controller, - ControllerHook -} from '~/libs/packages/controller/controller.js'; -import { HttpCode, HttpMethod } from '~/libs/packages/http/http.js'; -import { type ValueOf } from '~/libs/types/types.js'; - -import { type UserAuthResponse, type UserService } from '../user/user.js'; -import { getErrorStatusCode } from './helpers/helpers.js'; -import { AuthApiPath } from './libs/enums/enums.js'; -import { - type AuthController, - type AuthService, - type UserLoginRequestDto, - type UserLoginResponseDto, - type UserRegisterRequestDto, - type UserWithImageRelation -} from './libs/types/types.js'; -import { - loginValidationSchema, - registrationValidationSchema -} from './libs/validation-schemas/validation-schemas.js'; - -type Constructor = { - apiPath: ValueOf; - authService: AuthService; - userService: UserService; -}; - -class Auth extends Controller implements AuthController { - #authService: AuthService; - - #userService: UserService; - - public constructor({ apiPath, authService, userService }: Constructor) { - super({ apiPath }); - this.#authService = authService; - this.#userService = userService; - - this.addRoute({ - method: HttpMethod.POST, - url: AuthApiPath.LOGIN, - schema: { - body: loginValidationSchema - }, - [ControllerHook.HANDLER]: this.login - }); - this.addRoute({ - method: HttpMethod.POST, - url: AuthApiPath.REGISTER, - schema: { - body: registrationValidationSchema - }, - [ControllerHook.HANDLER]: this.register - }); - this.addRoute({ - method: HttpMethod.GET, - url: AuthApiPath.USER, - [ControllerHook.HANDLER]: this.getUser - }); - } - - public login = async ( - request: FastifyRequest, - reply: FastifyReply - ): Promise => { - try { - const user = await this.#authService.verifyLoginCredentials( - request.body as UserLoginRequestDto - ); - - return await this.#authService.login(user); - } catch (error) { - return await reply.status(getErrorStatusCode(error as Error)).send(error); - } - }; - - public register = async ( - request: FastifyRequest, - reply: FastifyReply - ): Promise => { - try { - const createdUser = await this.#authService.register( - request.body as UserRegisterRequestDto - ); - - return await reply.status(HttpCode.CREATED).send(createdUser); - } catch (error) { - return await reply.status(getErrorStatusCode(error as Error)).send(error); - } - }; - - public getUser = ( - request: FastifyRequest - ): Promise => { - return this.#userService.getByIdWithImage( - (request.user as UserAuthResponse).id - ); - }; -} - -export { Auth }; diff --git a/server/src/packages/auth/auth.service.ts b/server/src/packages/auth/auth.service.ts deleted file mode 100644 index d5d6856b..00000000 --- a/server/src/packages/auth/auth.service.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { ExceptionMessage } from '~/libs/enums/enums.js'; -import { InvalidCredentialsError } from '~/libs/exceptions/exceptions.js'; -import { - createToken, - cryptCompare, - encrypt, - verifyToken -} from '~/packages/auth/helpers/helpers.js'; - -import { type UserRepository, type UserWithPassword } from '../user/user.js'; -import { - type AuthService, - type User, - type UserAuthResponse, - type UserLoginRequestDto, - type UserLoginResponseDto, - type UserRegisterRequestDto, - type UserRegisterResponseDto -} from './libs/types/types.js'; - -type Constructor = { - userRepository: UserRepository; -}; - -class Auth implements AuthService { - #userRepository: UserRepository; - - public constructor({ userRepository }: Constructor) { - this.#userRepository = userRepository; - } - - public async verifyLoginCredentials({ - email, - password - }: UserLoginRequestDto): Promise | never { - const user = await this.#userRepository.getByEmailWithPassword(email); - - if (user === null) { - throw new InvalidCredentialsError(ExceptionMessage.INCORRECT_EMAIL); - } - - const isEqualPassword = await cryptCompare(password, user.password); - - if (!isEqualPassword) { - throw new InvalidCredentialsError(ExceptionMessage.PASSWORDS_NOT_MATCH); - } - - return user; - } - - public async login({ id }: User): Promise { - return { - token: createToken({ id }), - user: (await this.#userRepository.getByIdWithImage( - id - )) as UserAuthResponse - }; - } - - public register = async ({ - password, - ...userData - }: UserRegisterRequestDto): Promise => { - const { email, username } = userData; - - const userByEmail = await this.#userRepository.getByEmail(email); - - if (userByEmail) { - throw new InvalidCredentialsError(ExceptionMessage.EMAIL_ALREADY_EXISTS); - } - - const userByUsername = await this.#userRepository.getByUsername(username); - - if (userByUsername) { - throw new InvalidCredentialsError( - ExceptionMessage.USERNAME_ALREADY_EXISTS - ); - } - - const newUser = await this.#userRepository.create({ - ...userData, - password: await encrypt(password) - } as Omit); - - return await this.login(newUser); - }; - - public verifyToken(token: string): T { - return verifyToken(token) as T; - } -} - -export { Auth }; diff --git a/server/src/packages/auth/helpers/crypt/crypt-compare/crypt-compare.helper.ts b/server/src/packages/auth/helpers/crypt/crypt-compare/crypt-compare.helper.ts deleted file mode 100644 index 371d24df..00000000 --- a/server/src/packages/auth/helpers/crypt/crypt-compare/crypt-compare.helper.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { compare } from 'bcrypt'; - -const cryptCompare = (data: string, encrypted: string): Promise => { - return compare(data, encrypted); -}; - -export { cryptCompare }; diff --git a/server/src/packages/auth/helpers/crypt/crypt.ts b/server/src/packages/auth/helpers/crypt/crypt.ts deleted file mode 100644 index 2fd2a690..00000000 --- a/server/src/packages/auth/helpers/crypt/crypt.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { cryptCompare } from './crypt-compare/crypt-compare.helper.js'; -export { encrypt } from './encrypt/encrypt.helper.js'; -export { encryptSync } from './encrypt-sync/encrypt-sync.helper.js'; diff --git a/server/src/packages/auth/helpers/crypt/encrypt-sync/encrypt-sync.helper.ts b/server/src/packages/auth/helpers/crypt/encrypt-sync/encrypt-sync.helper.ts deleted file mode 100644 index ac2e65cd..00000000 --- a/server/src/packages/auth/helpers/crypt/encrypt-sync/encrypt-sync.helper.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { hashSync } from 'bcrypt'; - -import { USER_PASSWORD_SALT_ROUNDS } from '../libs/constants/constants.js'; - -const encryptSync = (data: string): string => { - return hashSync(data, USER_PASSWORD_SALT_ROUNDS); -}; - -export { encryptSync }; diff --git a/server/src/packages/auth/helpers/crypt/encrypt/encrypt.helper.ts b/server/src/packages/auth/helpers/crypt/encrypt/encrypt.helper.ts deleted file mode 100644 index 541731fa..00000000 --- a/server/src/packages/auth/helpers/crypt/encrypt/encrypt.helper.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { hash } from 'bcrypt'; - -import { USER_PASSWORD_SALT_ROUNDS } from '../libs/constants/constants.js'; - -const encrypt = (data: string): Promise => { - return hash(data, USER_PASSWORD_SALT_ROUNDS); -}; - -export { encrypt }; diff --git a/server/src/packages/auth/helpers/crypt/libs/constants/constants.ts b/server/src/packages/auth/helpers/crypt/libs/constants/constants.ts deleted file mode 100644 index 172cdf50..00000000 --- a/server/src/packages/auth/helpers/crypt/libs/constants/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export { USER_PASSWORD_SALT_ROUNDS } from './user.constants.js'; diff --git a/server/src/packages/auth/helpers/crypt/libs/constants/user.constants.ts b/server/src/packages/auth/helpers/crypt/libs/constants/user.constants.ts deleted file mode 100644 index 05bd4ff4..00000000 --- a/server/src/packages/auth/helpers/crypt/libs/constants/user.constants.ts +++ /dev/null @@ -1,3 +0,0 @@ -const USER_PASSWORD_SALT_ROUNDS = 10; - -export { USER_PASSWORD_SALT_ROUNDS }; diff --git a/server/src/packages/auth/helpers/helpers.ts b/server/src/packages/auth/helpers/helpers.ts deleted file mode 100644 index 5df98650..00000000 --- a/server/src/packages/auth/helpers/helpers.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { cryptCompare, encrypt, encryptSync } from './crypt/crypt.js'; -export { getErrorStatusCode } from './http/http.js'; -export { createToken, verifyToken } from './token/token.js'; diff --git a/server/src/packages/auth/helpers/http/get-error-status-code/get-error-status-code.helper.ts b/server/src/packages/auth/helpers/http/get-error-status-code/get-error-status-code.helper.ts deleted file mode 100644 index d80be3bd..00000000 --- a/server/src/packages/auth/helpers/http/get-error-status-code/get-error-status-code.helper.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ExceptionName } from '~/libs/enums/enums.js'; -import { HttpCode } from '~/libs/packages/http/http.js'; -import { type ValueOf } from '~/libs/types/types.js'; - -const getErrorStatusCode = (error: Error): ValueOf => { - const hasNameProperty = 'name' in error; - - if (!hasNameProperty) { - return HttpCode.INTERNAL_SERVER_ERROR; - } - - if (error.name === ExceptionName.INVALID_CREDENTIALS) { - return HttpCode.UNAUTHORIZED; - } - - return HttpCode.INTERNAL_SERVER_ERROR; -}; - -export { getErrorStatusCode }; diff --git a/server/src/packages/auth/helpers/http/http.ts b/server/src/packages/auth/helpers/http/http.ts deleted file mode 100644 index 6ef611fa..00000000 --- a/server/src/packages/auth/helpers/http/http.ts +++ /dev/null @@ -1 +0,0 @@ -export { getErrorStatusCode } from './get-error-status-code/get-error-status-code.helper.js'; diff --git a/server/src/packages/auth/helpers/token/create-token/create-token.helper.ts b/server/src/packages/auth/helpers/token/create-token/create-token.helper.ts deleted file mode 100644 index 1a98b7d7..00000000 --- a/server/src/packages/auth/helpers/token/create-token/create-token.helper.ts +++ /dev/null @@ -1,11 +0,0 @@ -import jwt from 'jsonwebtoken'; - -import { config } from '~/libs/packages/config/config.js'; - -const createToken = (data: T): string => { - return jwt.sign(data, config.ENV.JWT.SECRET, { - expiresIn: config.ENV.JWT.EXPIRES_IN - }); -}; - -export { createToken }; diff --git a/server/src/packages/auth/helpers/token/token.ts b/server/src/packages/auth/helpers/token/token.ts deleted file mode 100644 index c084f2a6..00000000 --- a/server/src/packages/auth/helpers/token/token.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { createToken } from './create-token/create-token.helper.js'; -export { verifyToken } from './verify-token/verify-token.helper.js'; diff --git a/server/src/packages/auth/helpers/token/verify-token/verify-token.helper.ts b/server/src/packages/auth/helpers/token/verify-token/verify-token.helper.ts deleted file mode 100644 index b3847932..00000000 --- a/server/src/packages/auth/helpers/token/verify-token/verify-token.helper.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { type JwtPayload } from 'jsonwebtoken'; -import jwt from 'jsonwebtoken'; - -import { config } from '~/libs/packages/config/config.js'; - -const verifyToken = (token: string): JwtPayload | string => { - return jwt.verify(token, config.ENV.JWT.SECRET); -}; - -export { verifyToken }; diff --git a/server/src/packages/auth/libs/enums/enums.ts b/server/src/packages/auth/libs/enums/enums.ts deleted file mode 100644 index 8fc94732..00000000 --- a/server/src/packages/auth/libs/enums/enums.ts +++ /dev/null @@ -1 +0,0 @@ -export { AuthApiPath } from 'shared/dist/packages/auth/auth.js'; diff --git a/server/src/packages/auth/libs/types/auth-controller.type.ts b/server/src/packages/auth/libs/types/auth-controller.type.ts deleted file mode 100644 index c44a66da..00000000 --- a/server/src/packages/auth/libs/types/auth-controller.type.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { type FastifyReply, type FastifyRequest } from 'fastify'; - -import { - type UserLoginRequestDto, - type UserLoginResponseDto, - type UserRegisterRequestDto, - type UserWithImageRelation -} from './types.js'; - -type AuthController = { - login: ( - _request: FastifyRequest>, - _reply: FastifyReply - ) => Promise; - register: ( - _request: FastifyRequest>, - _reply: FastifyReply - ) => Promise; - getUser: ( - _request: FastifyRequest> - ) => Promise; -}; - -export { type AuthController }; diff --git a/server/src/packages/auth/libs/types/auth-service.type.ts b/server/src/packages/auth/libs/types/auth-service.type.ts deleted file mode 100644 index 6a568390..00000000 --- a/server/src/packages/auth/libs/types/auth-service.type.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { - type User, - type UserLoginRequestDto, - type UserLoginResponseDto, - type UserRegisterRequestDto, - type UserRegisterResponseDto -} from './types.js'; - -type AuthService = { - verifyLoginCredentials(_user: UserLoginRequestDto): Promise; - login(_user: User): Promise; - register(_user: UserRegisterRequestDto): Promise; - verifyToken(_token: string): Promise; -}; - -export { type AuthService }; diff --git a/server/src/packages/auth/libs/types/types.ts b/server/src/packages/auth/libs/types/types.ts deleted file mode 100644 index a5057d15..00000000 --- a/server/src/packages/auth/libs/types/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -export { type AuthController } from './auth-controller.type.js'; -export { type AuthService } from './auth-service.type.js'; -export { - type User, - type UserAuthResponse, - type UserLoginRequestDto, - type UserLoginResponseDto, - type UserRegisterRequestDto, - type UserRegisterResponseDto, - type UserWithImageRelation -} from 'shared/dist/packages/user/user.js'; diff --git a/server/src/packages/auth/libs/validation-schemas/validation-schemas.ts b/server/src/packages/auth/libs/validation-schemas/validation-schemas.ts deleted file mode 100644 index 6bd70c86..00000000 --- a/server/src/packages/auth/libs/validation-schemas/validation-schemas.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { - login as loginValidationSchema, - registration as registrationValidationSchema -} from 'shared/dist/packages/auth/auth.js'; diff --git a/server/src/packages/comment/comment.controller.ts b/server/src/packages/comment/comment.controller.ts deleted file mode 100644 index 71954208..00000000 --- a/server/src/packages/comment/comment.controller.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { type FastifyReply, type FastifyRequest } from 'fastify'; - -import { type ApiPath } from '~/libs/enums/enums.js'; -import { - Controller, - ControllerHook -} from '~/libs/packages/controller/controller.js'; -import { HttpCode, HttpMethod } from '~/libs/packages/http/http.js'; -import { type ValueOf } from '~/libs/types/types.js'; - -import { type UserAuthResponse } from '../user/user.js'; -import { CommentsApiPath } from './libs/enums/enums.js'; -import { - type Comment as TComment, - type CommentController, - type CommentService, - type CommentWithUserNestedRelations, - type CreateCommentRequestDto -} from './libs/types/types.js'; - -type Constructor = { - apiPath: ValueOf; - commentService: CommentService; -}; - -class Comment extends Controller implements CommentController { - #commentService: CommentService; - - public constructor({ apiPath, commentService }: Constructor) { - super({ apiPath }); - this.#commentService = commentService; - - this.addRoute({ - method: HttpMethod.GET, - url: CommentsApiPath.$ID, - [ControllerHook.HANDLER]: this.getById - }); - this.addRoute({ - method: HttpMethod.POST, - url: CommentsApiPath.ROOT, - [ControllerHook.HANDLER]: this.create - }); - } - - public getById = async ( - request: FastifyRequest - ): Promise => { - return await this.#commentService.getById( - (request.params as Record<'id', number>).id - ); - }; - - public create = async ( - request: FastifyRequest, - reply: FastifyReply - ): Promise => { - const comment = await this.#commentService.create( - (request.user as UserAuthResponse).id, - request.body as CreateCommentRequestDto - ); - - return await reply.status(HttpCode.CREATED).send(comment); - }; -} - -export { Comment }; diff --git a/server/src/packages/comment/comment.model.ts b/server/src/packages/comment/comment.model.ts deleted file mode 100644 index c21517dd..00000000 --- a/server/src/packages/comment/comment.model.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Model, type QueryBuilder, type RelationMappings } from 'objection'; - -import { - AbstractModel, - DatabaseTableName -} from '~/libs/packages/database/database.js'; -import { PostModel } from '~/packages/post/post.js'; -import { UserModel } from '~/packages/user/user.js'; - -class CommentModel extends AbstractModel { - public body!: string; - - public postId!: number; - - public userId!: number; - - public static get tableName(): typeof DatabaseTableName.COMMENTS { - return DatabaseTableName.COMMENTS; - } - - public static get relationMappings(): RelationMappings { - return { - post: { - relation: Model.HasOneRelation, - modelClass: PostModel, - join: { - from: `${DatabaseTableName.COMMENTS}.postId`, - to: `${DatabaseTableName.POSTS}.id` - } - }, - user: { - relation: Model.HasOneRelation, - modelClass: UserModel, - filter: (query: QueryBuilder): QueryBuilder => { - return query.select('id', 'username', 'imageId'); - }, - join: { - from: `${DatabaseTableName.COMMENTS}.userId`, - to: `${DatabaseTableName.USERS}.id` - } - } - }; - } -} - -export { CommentModel }; diff --git a/server/src/packages/comment/comment.repository.ts b/server/src/packages/comment/comment.repository.ts deleted file mode 100644 index 410f5175..00000000 --- a/server/src/packages/comment/comment.repository.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { AbstractRepository } from '~/libs/packages/database/database.js'; - -import { type CommentModel } from './comment.model.js'; -import { - type Comment as TComment, - type CommentRepository, - type CommentWithUserNestedRelations -} from './libs/types/types.js'; - -type Constructor = Record<'commentModel', typeof CommentModel>; - -class Comment - extends AbstractRepository - implements CommentRepository -{ - public constructor({ commentModel }: Constructor) { - super(commentModel); - } - - public async getById( - id: number - ): Promise { - const comment = await this.model - .query() - .findById(id) - .withGraphFetched('[user.image]') - .castTo(); - - return comment ?? null; - } -} - -export { Comment }; diff --git a/server/src/packages/comment/comment.service.ts b/server/src/packages/comment/comment.service.ts deleted file mode 100644 index 471f4ec0..00000000 --- a/server/src/packages/comment/comment.service.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { - type Comment as TComment, - type CommentRepository, - type CommentService, - type CreateCommentRequestDto, - type GetCommentByIdResponseDto -} from './libs/types/types.js'; - -type Constructor = { - commentRepository: CommentRepository; -}; - -class Comment implements CommentService { - #commentRepository: CommentRepository; - - public constructor({ commentRepository }: Constructor) { - this.#commentRepository = commentRepository; - } - - public create( - userId: number, - comment: CreateCommentRequestDto - ): Promise { - return this.#commentRepository.create({ - ...comment, - userId - }); - } - - public getById(id: number): Promise { - return this.#commentRepository.getById(id); - } -} - -export { Comment }; diff --git a/server/src/packages/comment/comment.ts b/server/src/packages/comment/comment.ts deleted file mode 100644 index 97d7ce9b..00000000 --- a/server/src/packages/comment/comment.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ApiPath } from '~/libs/enums/enums.js'; - -import { Comment as CommentController } from './comment.controller.js'; -import { CommentModel } from './comment.model.js'; -import { Comment as CommentRepository } from './comment.repository.js'; -import { Comment as CommentService } from './comment.service.js'; - -const commentRepository = new CommentRepository({ - commentModel: CommentModel -}); -const commentService = new CommentService({ - commentRepository -}); -const commentController = new CommentController({ - apiPath: ApiPath.COMMENTS, - commentService -}); - -export { commentController, commentRepository, commentService }; -export { CommentModel } from './comment.model.js'; -export { CommentPayloadKey, CommentsApiPath } from './libs/enums/enums.js'; -export { - type Comment, - type CommentRepository, - type CommentService -} from './libs/types/types.js'; diff --git a/server/src/packages/comment/libs/enums/enums.ts b/server/src/packages/comment/libs/enums/enums.ts deleted file mode 100644 index 2ffdbc9e..00000000 --- a/server/src/packages/comment/libs/enums/enums.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { - CommentPayloadKey, - CommentsApiPath -} from 'shared/dist/packages/comment/comment.js'; diff --git a/server/src/packages/comment/libs/types/comment-controller.type.ts b/server/src/packages/comment/libs/types/comment-controller.type.ts deleted file mode 100644 index d751cdd9..00000000 --- a/server/src/packages/comment/libs/types/comment-controller.type.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { type FastifyReply, type FastifyRequest } from 'fastify'; - -import { - type Comment, - type CommentWithUserNestedRelations, - type CreateCommentRequestDto -} from './types.js'; - -type CommentController = { - getById( - _request: FastifyRequest>> - ): Promise; - create( - _request: FastifyRequest>, - _reply: FastifyReply - ): Promise; -}; - -export { type CommentController }; diff --git a/server/src/packages/comment/libs/types/comment-repository.type.ts b/server/src/packages/comment/libs/types/comment-repository.type.ts deleted file mode 100644 index 4b5a3fa6..00000000 --- a/server/src/packages/comment/libs/types/comment-repository.type.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { type Repository } from '~/libs/packages/database/database.js'; - -import { type Comment, type CommentWithUserNestedRelations } from './types.js'; - -type CommentRepository = Pick, 'create'> & { - getById(_id: number): Promise; -}; - -export type { CommentRepository }; diff --git a/server/src/packages/comment/libs/types/comment-service.type.ts b/server/src/packages/comment/libs/types/comment-service.type.ts deleted file mode 100644 index d5c6a7e9..00000000 --- a/server/src/packages/comment/libs/types/comment-service.type.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { - type Comment, - type CreateCommentRequestDto, - type GetCommentByIdResponseDto -} from './types.js'; - -type CommentService = { - create(_userId: number, _comment: CreateCommentRequestDto): Promise; - getById(_id: number): Promise; -}; - -export { type CommentService }; diff --git a/server/src/packages/comment/libs/types/types.ts b/server/src/packages/comment/libs/types/types.ts deleted file mode 100644 index 833c8d29..00000000 --- a/server/src/packages/comment/libs/types/types.ts +++ /dev/null @@ -1,9 +0,0 @@ -export { type CommentController } from './comment-controller.type.js'; -export { type CommentRepository } from './comment-repository.type.js'; -export { type CommentService } from './comment-service.type.js'; -export { - type Comment, - type CommentWithUserNestedRelations, - type CreateCommentRequestDto, - type GetCommentByIdResponseDto -} from 'shared/dist/packages/comment/comment.js'; diff --git a/server/src/packages/image/image.controller.ts b/server/src/packages/image/image.controller.ts deleted file mode 100644 index b2280930..00000000 --- a/server/src/packages/image/image.controller.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { type FastifyRequest } from 'fastify'; -import { type File } from 'fastify-multer/lib/interfaces.js'; - -import { upload } from '~/libs/middlewares/middlewares.js'; -import { - Controller, - ControllerHook -} from '~/libs/packages/controller/controller.js'; -import { HttpMethod } from '~/libs/packages/http/http.js'; - -import { ImagePayloadKey, ImagesApiPath } from './libs/enums/enums.js'; -import { - type ImageController, - type ImageService, - type UploadImageResponseDto -} from './libs/types/types.js'; - -type Constructor = { - apiPath: string; - imageService: ImageService; -}; - -class Image extends Controller implements ImageController { - #imageService: ImageService; - - public constructor({ apiPath, imageService }: Constructor) { - super({ apiPath }); - this.#imageService = imageService; - - this.addRoute({ - method: HttpMethod.POST, - url: ImagesApiPath.ROOT, - [ControllerHook.PRE_HANDLER]: upload.single(ImagePayloadKey.IMAGE), - [ControllerHook.HANDLER]: this.upload - }); - } - - public upload = ( - request: FastifyRequest - ): Promise => { - return this.#imageService.upload(request.file as File); - }; -} - -export { Image }; diff --git a/server/src/packages/image/image.model.ts b/server/src/packages/image/image.model.ts deleted file mode 100644 index 15f66d68..00000000 --- a/server/src/packages/image/image.model.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { - AbstractModel, - DatabaseTableName -} from '~/libs/packages/database/database.js'; - -class ImageModel extends AbstractModel { - public link!: string; - - public static get tableName(): typeof DatabaseTableName.IMAGES { - return DatabaseTableName.IMAGES; - } -} - -export { ImageModel }; diff --git a/server/src/packages/image/image.repository.ts b/server/src/packages/image/image.repository.ts deleted file mode 100644 index c6b282fb..00000000 --- a/server/src/packages/image/image.repository.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { AbstractRepository } from '~/libs/packages/database/database.js'; - -import { type ImageModel } from './image.model.js'; -import { - type Image as TImage, - type ImageRepository -} from './libs/types/types.js'; - -type Constructor = Record<'imageModel', typeof ImageModel>; - -class Image - extends AbstractRepository - implements ImageRepository -{ - public constructor({ imageModel }: Constructor) { - super(imageModel); - } -} - -export { Image }; diff --git a/server/src/packages/image/image.service.ts b/server/src/packages/image/image.service.ts deleted file mode 100644 index bbb78ab8..00000000 --- a/server/src/packages/image/image.service.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { type File } from 'fastify-multer/lib/interfaces.js'; -import FormData from 'form-data'; - -import { type ConfigPackage } from '~/libs/packages/config/config.js'; -import { HttpMethod } from '~/libs/packages/http/http.js'; -import { type HttpService } from '~/libs/packages/http/http.js'; - -import { - type Image as TImage, - type ImageRepository, - type ImageService -} from './libs/types/types.js'; - -type Constructor = { - config: ConfigPackage; - httpService: HttpService; - imageRepository: ImageRepository; -}; - -class Image implements ImageService { - #config: ConfigPackage; - - #httpService: HttpService; - - #imageRepository: ImageRepository; - - public constructor({ config, httpService, imageRepository }: Constructor) { - this.#config = config; - this.#imageRepository = imageRepository; - this.#httpService = httpService; - } - - public async upload(file: File): Promise { - const formData = new FormData(); - - formData.append('imagedata', file.buffer, { - filename: file.originalname, - knownLength: file.size as number - }); - formData.append('access_token', this.#config.ENV.GYAZO.ACCESS_KEY); - - const response = await this.#httpService.load< - FormData, - Record<'url', string> - >(this.#config.ENV.GYAZO.UPLOAD_API_URL, { - method: HttpMethod.POST, - data: formData, - headers: formData.getHeaders() - }); - - return await this.#imageRepository.create({ link: response.url }); - } -} - -export { Image }; diff --git a/server/src/packages/image/image.ts b/server/src/packages/image/image.ts deleted file mode 100644 index 788bb045..00000000 --- a/server/src/packages/image/image.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { ApiPath } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { httpService } from '~/libs/packages/http/http.js'; - -import { Image as ImageController } from './image.controller.js'; -import { ImageModel } from './image.model.js'; -import { Image as ImageRepository } from './image.repository.js'; -import { Image as ImageService } from './image.service.js'; - -const imageRepository = new ImageRepository({ - imageModel: ImageModel -}); -const imageService = new ImageService({ - config, - httpService, - imageRepository -}); -const imageController = new ImageController({ - apiPath: ApiPath.IMAGES, - imageService -}); - -export { imageController, imageRepository, imageService }; -export { ImageModel } from './image.model.js'; -export { ImagePayloadKey, ImagesApiPath } from './libs/enums/enums.js'; -export { - type Image, - type ImageController, - type ImageRepository, - type ImageService -} from './libs/types/types.js'; diff --git a/server/src/packages/image/libs/enums/enums.ts b/server/src/packages/image/libs/enums/enums.ts deleted file mode 100644 index 83e42d24..00000000 --- a/server/src/packages/image/libs/enums/enums.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { - ImagePayloadKey, - ImagesApiPath -} from 'shared/dist/packages/image/image.js'; diff --git a/server/src/packages/image/libs/types/image-controller.type.ts b/server/src/packages/image/libs/types/image-controller.type.ts deleted file mode 100644 index 256e91a8..00000000 --- a/server/src/packages/image/libs/types/image-controller.type.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { type FastifyRequest } from 'fastify'; - -import { type UploadImageResponseDto } from './types.js'; - -type ImageController = { - upload: (_request: FastifyRequest) => Promise; -}; - -export { type ImageController }; diff --git a/server/src/packages/image/libs/types/image-repository.type.ts b/server/src/packages/image/libs/types/image-repository.type.ts deleted file mode 100644 index dc60a38d..00000000 --- a/server/src/packages/image/libs/types/image-repository.type.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { type Repository } from '~/libs/packages/database/libs/types/types.js'; - -import { type Image } from '../types/types.js'; - -type ImageRepository = Repository; - -export { type ImageRepository }; diff --git a/server/src/packages/image/libs/types/image-service.type.ts b/server/src/packages/image/libs/types/image-service.type.ts deleted file mode 100644 index cbc16edc..00000000 --- a/server/src/packages/image/libs/types/image-service.type.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { type File } from 'fastify-multer/lib/interfaces.js'; - -import { type Image } from './types.js'; - -type ImageService = { - upload(_file: File): Promise; -}; - -export { type ImageService }; diff --git a/server/src/packages/image/libs/types/types.ts b/server/src/packages/image/libs/types/types.ts deleted file mode 100644 index becf77a3..00000000 --- a/server/src/packages/image/libs/types/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -export { type ImageController } from './image-controller.type.js'; -export { type ImageRepository } from './image-repository.type.js'; -export { type ImageService } from './image-service.type.js'; -export { - type Image, - type UploadImageResponseDto -} from 'shared/dist/packages/image/image.js'; diff --git a/server/src/packages/password/libs/enums/enums.ts b/server/src/packages/password/libs/enums/enums.ts deleted file mode 100644 index 67334f9a..00000000 --- a/server/src/packages/password/libs/enums/enums.ts +++ /dev/null @@ -1 +0,0 @@ -export { PasswordApiPath } from 'shared/dist/packages/password/password.js'; diff --git a/server/src/packages/password/password.ts b/server/src/packages/password/password.ts deleted file mode 100644 index e9711362..00000000 --- a/server/src/packages/password/password.ts +++ /dev/null @@ -1 +0,0 @@ -export { PasswordApiPath } from './libs/enums/enums.js'; diff --git a/server/src/packages/post/libs/enums/enums.ts b/server/src/packages/post/libs/enums/enums.ts deleted file mode 100644 index bba84acb..00000000 --- a/server/src/packages/post/libs/enums/enums.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { - FilterUserMode, - PostPayloadKey, - PostsApiPath -} from 'shared/dist/packages/post/post.js'; diff --git a/server/src/packages/post/libs/helpers/get-comments-count-query.ts b/server/src/packages/post/libs/helpers/get-comments-count-query.ts deleted file mode 100644 index ee87193a..00000000 --- a/server/src/packages/post/libs/helpers/get-comments-count-query.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { type Model, type QueryBuilder } from 'objection'; - -import { type PostModel } from '../../post.model.js'; - -const getCommentsCountQuery = ( - model: typeof PostModel -): QueryBuilder => { - return model.relatedQuery('comments').count().as('commentCount'); -}; - -export { getCommentsCountQuery }; diff --git a/server/src/packages/post/libs/helpers/get-reactions-query.ts b/server/src/packages/post/libs/helpers/get-reactions-query.ts deleted file mode 100644 index d6becf17..00000000 --- a/server/src/packages/post/libs/helpers/get-reactions-query.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { type Model, type QueryBuilder } from 'objection'; - -import { type PostModel } from '../../post.model.js'; - -const getReactionsQuery = - (model: typeof PostModel) => - (isLike: boolean): QueryBuilder => { - const col = isLike ? 'likeCount' : 'dislikeCount'; - - return model - .relatedQuery('postReactions') - .count() - .where({ isLike }) - .as(col); - }; - -export { getReactionsQuery }; diff --git a/server/src/packages/post/libs/helpers/get-where-user-id-query.ts b/server/src/packages/post/libs/helpers/get-where-user-id-query.ts deleted file mode 100644 index 08215b9b..00000000 --- a/server/src/packages/post/libs/helpers/get-where-user-id-query.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* eslint-disable @typescript-eslint/no-floating-promises */ -import { type QueryBuilder } from 'objection'; - -import { type PostModel } from '../../post.model.js'; - -const getWhereUserIdQuery = (userId: number | undefined) => { - return (builder: QueryBuilder): void => { - if (userId) { - builder.where({ userId }); - } - }; -}; - -export { getWhereUserIdQuery }; diff --git a/server/src/packages/post/libs/helpers/helpers.ts b/server/src/packages/post/libs/helpers/helpers.ts deleted file mode 100644 index f06fef7f..00000000 --- a/server/src/packages/post/libs/helpers/helpers.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { getCommentsCountQuery } from './get-comments-count-query.js'; -export { getReactionsQuery } from './get-reactions-query.js'; -export { getWhereUserIdQuery } from './get-where-user-id-query.js'; diff --git a/server/src/packages/post/libs/types/post-controller.type.ts b/server/src/packages/post/libs/types/post-controller.type.ts deleted file mode 100644 index 08c19388..00000000 --- a/server/src/packages/post/libs/types/post-controller.type.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { type FastifyReply, type FastifyRequest } from 'fastify'; - -import { - type CreatePostReactionResponseDto, - type CreatePostRequestDto, - type GetPostsByFilterResponseDto, - type Post, - type PostWithCommentImageUserNestedRelationsWithCount -} from './types.js'; - -type PostController = { - getByFilter(_request: FastifyRequest): Promise; - getById( - _request: FastifyRequest - ): Promise; - create( - _request: FastifyRequest>, - _reply: FastifyReply - ): Promise; - react(_request: FastifyRequest): Promise; -}; - -export { type PostController }; diff --git a/server/src/packages/post/libs/types/post-reaction-repository.type.ts b/server/src/packages/post/libs/types/post-reaction-repository.type.ts deleted file mode 100644 index 79b22ff1..00000000 --- a/server/src/packages/post/libs/types/post-reaction-repository.type.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { type Repository } from '~/libs/packages/database/database.js'; - -import { - type PostReaction, - type PostReactionWithPostRelation -} from './types.js'; - -type PostReactionRepository = Pick< - Repository, - 'create' | 'updateById' | 'deleteById' -> & { - getByUserIdPostId( - _userId: number, - _postId: number - ): Promise; -}; - -export { type PostReactionRepository }; diff --git a/server/src/packages/post/libs/types/post-repository.type.ts b/server/src/packages/post/libs/types/post-repository.type.ts deleted file mode 100644 index cd5b4150..00000000 --- a/server/src/packages/post/libs/types/post-repository.type.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { type Repository } from '~/libs/packages/database/database.js'; - -import { - type Post, - type PostFilter, - type PostWithCommentImageUserNestedRelationsWithCount, - type PostWithImageUserNestedRelationsWithCount -} from './types.js'; - -type PostRepository = Pick< - Repository, - 'create' -> & { - getByFilter( - _filters: PostFilter - ): Promise; - getById( - _id: number - ): Promise; -}; - -export { type PostRepository }; diff --git a/server/src/packages/post/libs/types/post-service.type.ts b/server/src/packages/post/libs/types/post-service.type.ts deleted file mode 100644 index 85b4c68a..00000000 --- a/server/src/packages/post/libs/types/post-service.type.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { - type CreatePostReactionRequestDto, - type CreatePostReactionResponseDto, - type CreatePostRequestDto, - type GetPostByIdResponseDto, - type GetPostsByFilterRequestDto, - type GetPostsByFilterResponseDto, - type Post -} from './types.js'; - -type PostService = { - getByFilter( - _filter: GetPostsByFilterRequestDto - ): Promise; - getById(_id: number): Promise; - create(_userId: number, _post: CreatePostRequestDto): Promise; - setReaction( - _userId: number, - _postReaction: CreatePostReactionRequestDto - ): Promise; -}; - -export { type PostService }; diff --git a/server/src/packages/post/libs/types/types.ts b/server/src/packages/post/libs/types/types.ts deleted file mode 100644 index 3bb2aed8..00000000 --- a/server/src/packages/post/libs/types/types.ts +++ /dev/null @@ -1,18 +0,0 @@ -export { type PostController } from './post-controller.type.js'; -export { type PostReactionRepository } from './post-reaction-repository.type.js'; -export { type PostRepository } from './post-repository.type.js'; -export { type PostService } from './post-service.type.js'; -export { - type CreatePostReactionRequestDto, - type CreatePostReactionResponseDto, - type CreatePostRequestDto, - type GetPostByIdResponseDto, - type GetPostsByFilterRequestDto, - type GetPostsByFilterResponseDto, - type Post, - type PostFilter, - type PostReaction, - type PostReactionWithPostRelation, - type PostWithCommentImageUserNestedRelationsWithCount, - type PostWithImageUserNestedRelationsWithCount -} from 'shared/dist/packages/post/post.js'; diff --git a/server/src/packages/post/post-reaction.model.ts b/server/src/packages/post/post-reaction.model.ts deleted file mode 100644 index 5931fd99..00000000 --- a/server/src/packages/post/post-reaction.model.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Model, type QueryBuilder, type RelationMappings } from 'objection'; - -import { - AbstractModel, - DatabaseTableName -} from '~/libs/packages/database/database.js'; -import { UserModel } from '~/packages/user/user.js'; - -import { PostModel } from './post.js'; - -class PostReactionModel extends AbstractModel { - public isLike!: boolean; - - public postId!: number; - - public userId!: number; - - public static get tableName(): typeof DatabaseTableName.POST_REACTIONS { - return DatabaseTableName.POST_REACTIONS; - } - - public static get relationMappings(): RelationMappings { - return { - post: { - relation: Model.HasOneRelation, - modelClass: PostModel, - join: { - from: `${DatabaseTableName.POST_REACTIONS}.postId`, - to: `${DatabaseTableName.POSTS}.id` - } - }, - user: { - relation: Model.HasOneRelation, - modelClass: UserModel, - filter: (query: QueryBuilder): QueryBuilder => { - return query.select('id', 'username'); - }, - join: { - from: `${DatabaseTableName.POST_REACTIONS}.userId`, - to: `${DatabaseTableName.USERS}.id` - } - } - }; - } -} - -export { PostReactionModel }; diff --git a/server/src/packages/post/post-reaction.repository.ts b/server/src/packages/post/post-reaction.repository.ts deleted file mode 100644 index f42e101c..00000000 --- a/server/src/packages/post/post-reaction.repository.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { AbstractRepository } from '~/libs/packages/database/database.js'; - -import { - type PostReaction as TPostReaction, - type PostReactionRepository, - type PostReactionWithPostRelation -} from './libs/types/types.js'; -import { type PostReactionModel } from './post-reaction.model.js'; - -type Constructor = Record<'postReactionModel', typeof PostReactionModel>; - -class PostReaction - extends AbstractRepository - implements PostReactionRepository -{ - public constructor({ postReactionModel }: Constructor) { - super(postReactionModel); - } - - public async getByUserIdPostId( - userId: number, - postId: number - ): Promise { - const postReaction = await this.model - .query() - .select() - .findOne({ userId, postId }) - .withGraphFetched('[post]') - .castTo(); - - return postReaction ?? null; - } -} - -export { PostReaction }; diff --git a/server/src/packages/post/post.controller.ts b/server/src/packages/post/post.controller.ts deleted file mode 100644 index 7d88ba0a..00000000 --- a/server/src/packages/post/post.controller.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { type FastifyReply, type FastifyRequest } from 'fastify'; - -import { type ApiPath } from '~/libs/enums/enums.js'; -import { - Controller, - ControllerHook -} from '~/libs/packages/controller/controller.js'; -import { HttpCode, HttpMethod } from '~/libs/packages/http/http.js'; -import { - NotificationSocketEvent, - SocketNamespace -} from '~/libs/packages/socket/socket.js'; -import { type ValueOf } from '~/libs/types/types.js'; - -import { type UserAuthResponse } from '../user/user.js'; -import { PostsApiPath } from './libs/enums/enums.js'; -import { - type CreatePostReactionRequestDto, - type CreatePostReactionResponseDto, - type CreatePostRequestDto, - type GetPostsByFilterRequestDto, - type GetPostsByFilterResponseDto, - type Post as TPost, - type PostController, - type PostService, - type PostWithCommentImageUserNestedRelationsWithCount -} from './libs/types/types.js'; - -type Constructor = { - apiPath: ValueOf; - postService: PostService; -}; - -class Post extends Controller implements PostController { - #postService: PostService; - - public constructor({ apiPath, postService }: Constructor) { - super({ apiPath }); - this.#postService = postService; - - this.addRoute({ - method: HttpMethod.GET, - url: PostsApiPath.ROOT, - [ControllerHook.HANDLER]: this.getByFilter - }); - this.addRoute({ - method: HttpMethod.GET, - url: PostsApiPath.$ID, - [ControllerHook.HANDLER]: this.getById - }); - this.addRoute({ - method: HttpMethod.POST, - url: PostsApiPath.ROOT, - [ControllerHook.HANDLER]: this.create - }); - this.addRoute({ - method: HttpMethod.PUT, - url: PostsApiPath.REACT, - [ControllerHook.HANDLER]: this.react - }); - } - - public getByFilter = ( - request: FastifyRequest - ): Promise => { - return this.#postService.getByFilter( - request.query as GetPostsByFilterRequestDto - ); - }; - - public getById = ( - request: FastifyRequest - ): Promise => { - return this.#postService.getById( - (request.params as Record<'id', number>).id - ); - }; - - public create = async ( - request: FastifyRequest, - reply: FastifyReply - ): Promise => { - const post = await this.#postService.create( - (request.user as UserAuthResponse).id, - request.body as CreatePostRequestDto - ); - - request.io - .of(SocketNamespace.NOTIFICATION) - .emit(NotificationSocketEvent.NEW_POST, post); // notify all users that a new post was created - - return await reply.status(HttpCode.CREATED).send(post); - }; - - public react = async ( - request: FastifyRequest - ): Promise => { - const authUserId = (request.user as UserAuthResponse).id; - const reaction = await this.#postService.setReaction( - authUserId, - request.body as CreatePostReactionRequestDto - ); - - if (reaction.post && reaction.post.userId !== authUserId) { - // notify a user if someone (not himself) liked his post - request.io - .of(SocketNamespace.NOTIFICATION) - .to(`${reaction.post.userId}`) - .emit(NotificationSocketEvent.LIKE_POST); - } - - return reaction; - }; -} - -export { Post }; diff --git a/server/src/packages/post/post.model.ts b/server/src/packages/post/post.model.ts deleted file mode 100644 index 3ded52af..00000000 --- a/server/src/packages/post/post.model.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Model, type QueryBuilder, type RelationMappings } from 'objection'; - -import { - AbstractModel, - DatabaseTableName -} from '~/libs/packages/database/database.js'; -import { CommentModel } from '~/packages/comment/comment.js'; -import { ImageModel } from '~/packages/image/image.js'; -import { UserModel } from '~/packages/user/user.js'; - -import { PostReactionModel } from './post.js'; - -class PostModel extends AbstractModel { - public body!: string; - - public imageId!: number | null; - - public userId!: number; - - public static get tableName(): typeof DatabaseTableName.POSTS { - return DatabaseTableName.POSTS; - } - - public static get relationMappings(): RelationMappings { - return { - comments: { - relation: Model.HasManyRelation, - modelClass: CommentModel, - join: { - from: `${DatabaseTableName.POSTS}.id`, - to: `${DatabaseTableName.COMMENTS}.postId` - } - }, - image: { - relation: Model.HasOneRelation, - modelClass: ImageModel, - filter: (query: QueryBuilder): QueryBuilder => { - return query.select('id', 'link'); - }, - join: { - from: `${DatabaseTableName.POSTS}.imageId`, - to: `${DatabaseTableName.IMAGES}.id` - } - }, - postReactions: { - relation: Model.HasManyRelation, - modelClass: PostReactionModel, - join: { - from: `${DatabaseTableName.POSTS}.id`, - to: `${DatabaseTableName.POST_REACTIONS}.postId` - } - }, - user: { - relation: Model.HasOneRelation, - modelClass: UserModel, - filter: (query: QueryBuilder): QueryBuilder => { - return query.select('id', 'username', 'imageId'); - }, - join: { - from: `${DatabaseTableName.POSTS}.userId`, - to: `${DatabaseTableName.USERS}.id` - } - } - }; - } -} - -export { PostModel }; diff --git a/server/src/packages/post/post.repository.ts b/server/src/packages/post/post.repository.ts deleted file mode 100644 index 279ee417..00000000 --- a/server/src/packages/post/post.repository.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { AbstractRepository } from '~/libs/packages/database/database.js'; - -import { - getCommentsCountQuery, - getReactionsQuery, - getWhereUserIdQuery -} from './libs/helpers/helpers.js'; -import { - type Post as TPost, - type PostFilter, - type PostRepository, - type PostWithCommentImageUserNestedRelationsWithCount, - type PostWithImageUserNestedRelationsWithCount -} from './libs/types/types.js'; -import { type PostModel } from './post.model.js'; - -type Constructor = Record<'postModel', typeof PostModel>; - -class Post - extends AbstractRepository< - typeof PostModel, - TPost | PostWithCommentImageUserNestedRelationsWithCount - > - implements PostRepository -{ - public constructor({ postModel }: Constructor) { - super(postModel); - } - - public getByFilter( - filter: PostFilter - ): Promise { - const { from: offset, count: limit, userId } = filter; - - return this.model - .query() - .select( - 'posts.*', - getCommentsCountQuery(this.model), - getReactionsQuery(this.model)(true), - getReactionsQuery(this.model)(false) - ) - .where(getWhereUserIdQuery(userId)) - .withGraphFetched('[image, user.image]') - .orderBy('createdAt', 'desc') - .offset(offset) - .limit(limit) - .castTo() - .execute(); - } - - public async getById( - id: number - ): Promise { - const post = await this.model - .query() - .select( - 'posts.*', - getCommentsCountQuery(this.model), - getReactionsQuery(this.model)(true), - getReactionsQuery(this.model)(false) - ) - .findOne({ id }) - .withGraphFetched('[comments.user.image, user.image, image]') - .castTo(); - - return post ?? null; - } -} - -export { Post }; diff --git a/server/src/packages/post/post.service.ts b/server/src/packages/post/post.service.ts deleted file mode 100644 index caa3908f..00000000 --- a/server/src/packages/post/post.service.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { - type CreatePostReactionRequestDto, - type CreatePostReactionResponseDto, - type CreatePostRequestDto, - type Post as TPost, - type PostFilter, - type PostReaction, - type PostReactionRepository, - type PostRepository, - type PostService, - type PostWithCommentImageUserNestedRelationsWithCount, - type PostWithImageUserNestedRelationsWithCount -} from './libs/types/types.js'; - -type Constructor = { - postRepository: PostRepository; - postReactionRepository: PostReactionRepository; -}; - -class Post implements PostService { - #postRepository: PostRepository; - - #postReactionRepository: PostReactionRepository; - - public constructor({ postRepository, postReactionRepository }: Constructor) { - this.#postRepository = postRepository; - this.#postReactionRepository = postReactionRepository; - } - - public getByFilter( - filter: PostFilter - ): Promise { - return this.#postRepository.getByFilter(filter); - } - - public getById( - id: number - ): Promise { - return this.#postRepository.getById(id); - } - - public create(userId: number, post: CreatePostRequestDto): Promise { - return this.#postRepository.create({ - ...post, - userId - }); - } - - public async setReaction( - userId: number, - { postId, isLike = true }: CreatePostReactionRequestDto - ): Promise { - // define the callback for future use as a promise - const updateOrDelete = ( - react: PostReaction - ): Promise => { - return react.isLike === isLike - ? this.#postReactionRepository.deleteById(react.id) - : this.#postReactionRepository.updateById(react.id, { isLike }); - }; - - const reaction = await this.#postReactionRepository.getByUserIdPostId( - userId, - postId - ); - - const result = reaction - ? await updateOrDelete(reaction) - : await this.#postReactionRepository.create({ userId, postId, isLike }); - - // the result is an integer when an entity is deleted - const resultReaction = await this.#postReactionRepository.getByUserIdPostId( - userId, - postId - ); - - return Number.isInteger(result) - ? {} - : (resultReaction as NonNullable); - } -} - -export { Post }; diff --git a/server/src/packages/post/post.ts b/server/src/packages/post/post.ts deleted file mode 100644 index 3dc38927..00000000 --- a/server/src/packages/post/post.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { ApiPath } from '~/libs/enums/enums.js'; - -import { Post as PostController } from './post.controller.js'; -import { PostModel } from './post.model.js'; -import { Post as PostRepository } from './post.repository.js'; -import { Post as PostService } from './post.service.js'; -import { PostReactionModel } from './post-reaction.model.js'; -import { PostReaction as PostReactionRepository } from './post-reaction.repository.js'; - -const postRepository = new PostRepository({ - postModel: PostModel -}); -const postReactionRepository = new PostReactionRepository({ - postReactionModel: PostReactionModel -}); -const postService = new PostService({ - postRepository, - postReactionRepository -}); -const postController = new PostController({ - apiPath: ApiPath.POSTS, - postService -}); - -export { postController, postReactionRepository, postRepository, postService }; -export { - FilterUserMode, - PostPayloadKey, - PostsApiPath -} from './libs/enums/enums.js'; -export { - type CreatePostRequestDto, - type Post, - type PostController, - type PostReactionRepository, - type PostRepository, - type PostService, - type PostWithCommentImageUserNestedRelationsWithCount -} from './libs/types/types.js'; -export { PostModel } from './post.model.js'; -export { PostReactionModel } from './post-reaction.model.js'; diff --git a/server/src/packages/user/libs/types/types.ts b/server/src/packages/user/libs/types/types.ts deleted file mode 100644 index 60be3cfa..00000000 --- a/server/src/packages/user/libs/types/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -export { type UserRepository } from './user-repository.type.js'; -export { type UserService } from './user-service.type.js'; -export { - type User, - type UserAuthResponse, - type UserWithImageRelation, - type UserWithPassword -} from 'shared/dist/packages/user/user.js'; diff --git a/server/src/packages/user/libs/types/user-repository.type.ts b/server/src/packages/user/libs/types/user-repository.type.ts deleted file mode 100644 index 4a8c0f95..00000000 --- a/server/src/packages/user/libs/types/user-repository.type.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { type Repository } from '~/libs/packages/database/database.js'; - -import { - type User, - type UserWithImageRelation, - type UserWithPassword -} from './types.js'; - -type UserRepository = Pick, 'create'> & { - getByEmail(_email: string): Promise; - - getByEmailWithPassword(_email: string): Promise; - - getByUsername(_username: string): Promise; - - getByIdWithImage(_id: number): Promise; -}; - -export { type UserRepository }; diff --git a/server/src/packages/user/libs/types/user-service.type.ts b/server/src/packages/user/libs/types/user-service.type.ts deleted file mode 100644 index df330deb..00000000 --- a/server/src/packages/user/libs/types/user-service.type.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { type User, type UserWithImageRelation } from './types.js'; - -type UserService = { - getById(_id: number): Promise; - getByIdWithImage(_id: number): Promise; -}; - -export { type UserService }; diff --git a/server/src/packages/user/user.model.ts b/server/src/packages/user/user.model.ts deleted file mode 100644 index d28393d4..00000000 --- a/server/src/packages/user/user.model.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { - Model, - type Modifiers, - type QueryBuilder, - type RelationMappings -} from 'objection'; - -import { - AbstractModel, - DatabaseTableName -} from '~/libs/packages/database/database.js'; -import { ImageModel } from '~/packages/image/image.js'; - -class User extends AbstractModel { - public email!: string; - - public username!: string; - - public password!: string; - - public imageId!: number | null; - - public static get tableName(): typeof DatabaseTableName.USERS { - return DatabaseTableName.USERS; - } - - public static override get modifiers(): Modifiers> { - return { - withoutPassword(builder): QueryBuilder { - return builder.select( - 'id', - 'email', - 'username', - 'imageId', - 'createdAt', - 'updatedAt' - ); - } - }; - } - - public static get relationMappings(): RelationMappings { - return { - image: { - relation: Model.HasOneRelation, - modelClass: ImageModel, - filter: (query: QueryBuilder): QueryBuilder => { - return query.select('id', 'link'); - }, - join: { - from: `${DatabaseTableName.USERS}.imageId`, - to: `${DatabaseTableName.IMAGES}.id` - } - } - }; - } -} - -export { User }; diff --git a/server/src/packages/user/user.repository.ts b/server/src/packages/user/user.repository.ts deleted file mode 100644 index f46ec1f9..00000000 --- a/server/src/packages/user/user.repository.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { AbstractRepository } from '~/libs/packages/database/database.js'; - -import { - type User as TUser, - type UserRepository, - type UserWithImageRelation, - type UserWithPassword -} from './libs/types/types.js'; -import { type User as UserModel } from './user.model.js'; - -type Constructor = Record<'userModel', typeof UserModel>; - -class User - extends AbstractRepository - implements UserRepository -{ - public constructor({ userModel }: Constructor) { - super(userModel); - } - - public async getByEmailWithPassword( - email: string - ): Promise { - const user = await this.model - .query() - .findOne({ email }) - .castTo(); - - return user ?? null; - } - - public async getByEmail(email: string): Promise { - const user = await this.model - .query() - .modify('withoutPassword') - .findOne({ email }); - - return user ?? null; - } - - public async getByUsername(username: string): Promise { - const user = await this.model - .query() - .modify('withoutPassword') - .select() - .findOne({ username }); - - return user ?? null; - } - - public async getByIdWithImage( - id: number - ): Promise { - const user = await this.model - .query() - .modify('withoutPassword') - .findById(id) - .withGraphFetched('[image]') - .castTo(); - - return user ?? null; - } -} - -export { User }; diff --git a/server/tests/api/0-starter/auth.api.spec.ts b/server/tests/api/0-starter/auth.api.spec.ts deleted file mode 100644 index 02da7fbe..00000000 --- a/server/tests/api/0-starter/auth.api.spec.ts +++ /dev/null @@ -1,373 +0,0 @@ -import { faker } from '@faker-js/faker'; -import { describe, expect, it } from '@jest/globals'; - -import { ApiPath } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { DatabaseTableName } from '~/libs/packages/database/database.js'; -import { HttpCode, HttpHeader, HttpMethod } from '~/libs/packages/http/http.js'; -import { joinPath } from '~/libs/packages/path/path.js'; -import { - AuthApiPath, - type UserLoginResponseDto, - type UserRegisterRequestDto -} from '~/packages/auth/auth.js'; -import { - UserPayloadKey, - UserValidationMessage, - UserValidationRule -} from '~/packages/user/user.js'; -import { type User } from '~/packages/user/user.js'; - -import { buildApp } from '../../libs/packages/app/app.js'; -import { - getCrudHandlers, - KNEX_SELECT_ONE_RECORD -} from '../../libs/packages/database/database.js'; -import { getBearerAuthHeader } from '../../libs/packages/http/http.js'; -import { TEST_USERS_CREDENTIALS } from '../../packages/user/user.js'; - -const authApiPath = joinPath([config.ENV.APP.API_PATH, ApiPath.AUTH]); - -const registerEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.REGISTER -]); - -const loginEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.LOGIN -]); - -const userEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.USER -]); - -describe(`${authApiPath} routes`, () => { - const { getApp, getKnex } = buildApp(); - const { select } = getCrudHandlers(getKnex); - - describe(`${registerEndpoint} (${HttpMethod.POST}) endpoint`, () => { - const app = getApp(); - - it(`should return ${HttpCode.BAD_REQUEST} of empty ${UserPayloadKey.USERNAME} validation error`, async () => { - const response = await app.inject().post(registerEndpoint).body({}); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.USERNAME_REQUIRE - ); - }); - - it(`should return ${HttpCode.BAD_REQUEST} of too short ${UserPayloadKey.USERNAME} validation error`, async () => { - const [validTestUser] = TEST_USERS_CREDENTIALS; - - const response = await app - .inject() - .post(registerEndpoint) - .body({ - ...validTestUser, - [UserPayloadKey.USERNAME]: faker.string.alpha( - UserValidationRule.USERNAME_MIN_LENGTH - 1 - ) - }); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.USERNAME_MIN_LENGTH - ); - }); - - it(`should return ${HttpCode.BAD_REQUEST} of too long ${UserPayloadKey.USERNAME} validation error`, async () => { - const [validTestUser] = TEST_USERS_CREDENTIALS; - - const response = await app - .inject() - .post(registerEndpoint) - .body({ - ...validTestUser, - [UserPayloadKey.USERNAME]: faker.string.alpha( - UserValidationRule.USERNAME_MAX_LENGTH + 2 - ) - }); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.USERNAME_MAX_LENGTH - ); - }); - - it(`should return ${HttpCode.BAD_REQUEST} of empty ${UserPayloadKey.EMAIL} validation error`, async () => { - const [validTestUser] = TEST_USERS_CREDENTIALS; - const { [UserPayloadKey.EMAIL]: _email, ...user } = - validTestUser as UserRegisterRequestDto; - - const response = await app.inject().post(registerEndpoint).body(user); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.EMAIL_REQUIRE - ); - }); - - it(`should return ${HttpCode.BAD_REQUEST} of wrong ${UserPayloadKey.EMAIL} validation error`, async () => { - const [validTestUser] = TEST_USERS_CREDENTIALS; - - const response = await app - .inject() - .post(registerEndpoint) - .body({ - ...validTestUser, - [UserPayloadKey.EMAIL]: faker.person.firstName() - }); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.EMAIL_WRONG - ); - }); - - it(`should return ${HttpCode.BAD_REQUEST} of empty ${UserPayloadKey.PASSWORD} validation error`, async () => { - const [validTestUser] = TEST_USERS_CREDENTIALS; - const { [UserPayloadKey.PASSWORD]: _password, ...user } = - validTestUser as UserRegisterRequestDto; - - const response = await app.inject().post(registerEndpoint).body(user); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.PASSWORD_REQUIRE - ); - }); - - it(`should return ${HttpCode.BAD_REQUEST} of too short ${UserPayloadKey.PASSWORD} validation error`, async () => { - const [validTestUser] = TEST_USERS_CREDENTIALS; - - const response = await app - .inject() - .post(registerEndpoint) - .body({ - ...validTestUser, - [UserPayloadKey.PASSWORD]: faker.internet.password({ - length: UserValidationRule.PASSWORD_MIN_LENGTH - 2 - }) - }); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.PASSWORD_MIN_LENGTH - ); - }); - - it(`should return ${HttpCode.BAD_REQUEST} of too long ${UserPayloadKey.PASSWORD} validation error`, async () => { - const [validTestUser] = TEST_USERS_CREDENTIALS; - - const response = await app - .inject() - .post(registerEndpoint) - .body({ - ...validTestUser, - [UserPayloadKey.PASSWORD]: faker.internet.password({ - length: UserValidationRule.PASSWORD_MAX_LENGTH + 2 - }) - }); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.PASSWORD_MAX_LENGTH - ); - }); - - it(`should return ${HttpCode.CREATED} and create a new user`, async () => { - const [validTestUser] = TEST_USERS_CREDENTIALS as [ - UserRegisterRequestDto - ]; - - const response = await app - .inject() - .post(registerEndpoint) - .body(validTestUser); - - expect(response.statusCode).toBe(HttpCode.CREATED); - expect(response.json()).toEqual( - expect.objectContaining({ - user: expect.objectContaining({ - [UserPayloadKey.USERNAME]: validTestUser[UserPayloadKey.USERNAME], - [UserPayloadKey.EMAIL]: validTestUser[UserPayloadKey.EMAIL] - }) - }) - ); - - const savedDatabaseUser = await select({ - table: DatabaseTableName.USERS, - condition: { id: response.json().user.id }, - limit: KNEX_SELECT_ONE_RECORD - }); - - expect(savedDatabaseUser).toEqual( - expect.objectContaining({ - [UserPayloadKey.USERNAME]: validTestUser[UserPayloadKey.USERNAME], - [UserPayloadKey.EMAIL]: validTestUser[UserPayloadKey.EMAIL] - }) - ); - }); - }); - - describe(`${loginEndpoint} (${HttpMethod.POST}) endpoint`, () => { - const app = getApp(); - - it(`should return ${HttpCode.BAD_REQUEST} of empty ${UserPayloadKey.EMAIL} validation error`, async () => { - const response = await app.inject().post(loginEndpoint).body({}); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.EMAIL_REQUIRE - ); - }); - - it(`should return ${HttpCode.BAD_REQUEST} of wrong ${UserPayloadKey.EMAIL} validation error`, async () => { - const response = await app - .inject() - .post(loginEndpoint) - .body({ [UserPayloadKey.EMAIL]: faker.person.fullName() }); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.EMAIL_WRONG - ); - }); - - it(`should return ${HttpCode.BAD_REQUEST} of empty ${UserPayloadKey.PASSWORD} validation error`, async () => { - const [validTestUser] = TEST_USERS_CREDENTIALS as [ - UserRegisterRequestDto - ]; - - const response = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestUser[UserPayloadKey.EMAIL] - }); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.PASSWORD_REQUIRE - ); - }); - - it(`should return ${HttpCode.BAD_REQUEST} of too short ${UserPayloadKey.PASSWORD} validation error`, async () => { - const [validTestUser] = TEST_USERS_CREDENTIALS as [ - UserRegisterRequestDto - ]; - - const response = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: faker.internet.password({ - length: UserValidationRule.PASSWORD_MIN_LENGTH - 2 - }) - }); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.PASSWORD_MIN_LENGTH - ); - }); - - it(`should return ${HttpCode.BAD_REQUEST} of too long ${UserPayloadKey.PASSWORD} validation error`, async () => { - const [validTestUser] = TEST_USERS_CREDENTIALS as [ - UserRegisterRequestDto - ]; - - const response = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: faker.internet.password({ - length: UserValidationRule.PASSWORD_MAX_LENGTH + 2 - }) - }); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.PASSWORD_MAX_LENGTH - ); - }); - - it(`should return ${HttpCode.OK} with auth result`, async () => { - const [validTestUser] = TEST_USERS_CREDENTIALS as [ - UserRegisterRequestDto - ]; - - const response = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestUser[UserPayloadKey.PASSWORD] - }); - - expect(response.statusCode).toBe(HttpCode.OK); - expect(response.json()).toEqual( - expect.objectContaining({ - user: expect.objectContaining({ - [UserPayloadKey.USERNAME]: validTestUser[UserPayloadKey.USERNAME], - [UserPayloadKey.EMAIL]: validTestUser[UserPayloadKey.EMAIL] - }) - }) - ); - }); - }); - - describe(`${userEndpoint} (${HttpMethod.GET}) endpoint`, () => { - const app = getApp(); - - it(`should return ${HttpCode.OK} with auth user`, async () => { - const [{ email, username, password }] = TEST_USERS_CREDENTIALS as [ - UserRegisterRequestDto - ]; - - const loginResponse = await app - .inject() - .post(loginEndpoint) - .body({ email, password }); - - const response = await app - .inject() - .get(userEndpoint) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader( - loginResponse.json().token - ) - }); - - expect(response.statusCode).toBe(HttpCode.OK); - expect(response.json()).toEqual( - expect.objectContaining({ - username, - email - }) - ); - - const databaseUser = await select({ - table: DatabaseTableName.USERS, - condition: { id: response.json().id }, - limit: KNEX_SELECT_ONE_RECORD - }); - - expect(databaseUser).toEqual( - expect.objectContaining({ - id: response.json().id, - username, - email - }) - ); - }); - }); -}); diff --git a/server/tests/api/0-starter/comment.api.spec.ts b/server/tests/api/0-starter/comment.api.spec.ts deleted file mode 100644 index 812b3cbf..00000000 --- a/server/tests/api/0-starter/comment.api.spec.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { beforeAll, describe, expect, it } from '@jest/globals'; - -import { ApiPath } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { DatabaseTableName } from '~/libs/packages/database/database.js'; -import { HttpCode, HttpHeader, HttpMethod } from '~/libs/packages/http/http.js'; -import { joinPath } from '~/libs/packages/path/path.js'; -import { - AuthApiPath, - type UserLoginResponseDto, - type UserRegisterRequestDto -} from '~/packages/auth/auth.js'; -import { - type Comment, - CommentPayloadKey, - CommentsApiPath -} from '~/packages/comment/comment.js'; -import { type Post } from '~/packages/post/post.js'; -import { UserPayloadKey } from '~/packages/user/user.js'; - -import { buildApp } from '../../libs/packages/app/app.js'; -import { - getCrudHandlers, - KNEX_SELECT_ONE_RECORD -} from '../../libs/packages/database/database.js'; -import { getBearerAuthHeader } from '../../libs/packages/http/http.js'; -import { setupTestPosts, TEST_POSTS } from '../../packages/post/post.js'; -import { - setupTestUsers, - TEST_USERS_CREDENTIALS -} from '../../packages/user/user.js'; - -const loginEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.LOGIN -]); - -const commentApiPath = joinPath([config.ENV.APP.API_PATH, ApiPath.COMMENTS]); - -const commentsEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.COMMENTS, - CommentsApiPath.ROOT -]); - -const commentIdEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.COMMENTS, - CommentsApiPath.$ID -]); - -describe(`${commentApiPath} routes`, () => { - const { getApp, getKnex } = buildApp(); - const { select, insert } = getCrudHandlers(getKnex); - - let token: string; - let userId: number; - - beforeAll(async () => { - await setupTestUsers({ handlers: { insert } }); - await setupTestPosts({ handlers: { select, insert } }); - - const [validTestUser] = TEST_USERS_CREDENTIALS as [UserRegisterRequestDto]; - - const loginResponse = await getApp() - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestUser[UserPayloadKey.PASSWORD] - }); - - token = loginResponse.json().token; - userId = loginResponse.json().user.id; - }); - - describe(`${commentsEndpoint} (${HttpMethod.POST}) endpoint`, () => { - const app = getApp(); - - it(`should return ${HttpCode.CREATED} with a new comment`, async () => { - const [validTestPost] = TEST_POSTS; - - const result = await select({ - table: DatabaseTableName.POSTS, - limit: KNEX_SELECT_ONE_RECORD - }); - const { id: postId } = (result ?? {}) as Post; - - const testComment = { - ...validTestPost, - postId - }; - - const response = await app - .inject() - .post(commentsEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body(testComment); - - expect(response.statusCode).toBe(HttpCode.CREATED); - expect(response.json()).toEqual( - expect.objectContaining({ - userId, - ...testComment - }) - ); - expect(response.json()).toHaveProperty('id'); - expect(response.json()).toHaveProperty('createdAt'); - expect(response.json()).toHaveProperty('updatedAt'); - - const savedDatabaseComment = await select({ - table: DatabaseTableName.COMMENTS, - condition: { id: response.json().id }, - limit: KNEX_SELECT_ONE_RECORD - }); - - expect(savedDatabaseComment).toEqual( - expect.objectContaining({ - [CommentPayloadKey.BODY]: testComment[CommentPayloadKey.BODY], - postId: testComment.postId - }) - ); - }); - }); - - describe(`${commentIdEndpoint} (${HttpMethod.GET}) endpoint`, () => { - const app = getApp(); - - it(`should return ${HttpCode.OK} with comment by id`, async () => { - const result = await select({ - table: DatabaseTableName.COMMENTS, - limit: KNEX_SELECT_ONE_RECORD - }); - const { id: commentId, body } = (result ?? {}) as Post; - - const response = await app - .inject() - .get(commentIdEndpoint.replace(':id', commentId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - - expect(response.statusCode).toBe(HttpCode.OK); - expect(response.json()).toEqual( - expect.objectContaining({ - id: commentId, - body - }) - ); - expect(response.json()).toHaveProperty('createdAt'); - expect(response.json()).toHaveProperty('updatedAt'); - }); - }); -}); diff --git a/server/tests/api/0-starter/image.api.spec.ts b/server/tests/api/0-starter/image.api.spec.ts deleted file mode 100644 index a100384b..00000000 --- a/server/tests/api/0-starter/image.api.spec.ts +++ /dev/null @@ -1,114 +0,0 @@ -import fs from 'node:fs'; -import { join } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -import { beforeAll, describe, expect, it } from '@jest/globals'; -import FormData from 'form-data'; - -import { ApiPath } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { DatabaseTableName } from '~/libs/packages/database/database.js'; -import { HttpCode, HttpHeader, HttpMethod } from '~/libs/packages/http/http.js'; -import { joinPath } from '~/libs/packages/path/path.js'; -import { - AuthApiPath, - type UserLoginResponseDto, - type UserRegisterRequestDto -} from '~/packages/auth/auth.js'; -import { ImagePayloadKey, ImagesApiPath } from '~/packages/image/image.js'; -import { type Image } from '~/packages/image/image.js'; -import { UserPayloadKey } from '~/packages/user/user.js'; - -import { buildApp } from '../../libs/packages/app/app.js'; -import { - getCrudHandlers, - KNEX_SELECT_ONE_RECORD -} from '../../libs/packages/database/database.js'; -import { getBearerAuthHeader } from '../../libs/packages/http/http.js'; -import { - setupTestUsers, - TEST_USERS_CREDENTIALS -} from '../../packages/user/user.js'; - -const loginEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.LOGIN -]); - -const imageEndpoint = joinPath([config.ENV.APP.API_PATH, ApiPath.IMAGES]); - -const imagesEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.IMAGES, - ImagesApiPath.ROOT -]); - -describe(`${imageEndpoint} routes`, () => { - const { getApp, getKnex } = buildApp(); - const { select, insert } = getCrudHandlers(getKnex); - - let token: string; - - beforeAll(async () => { - await setupTestUsers({ handlers: { insert } }); - - const [validTestUser] = TEST_USERS_CREDENTIALS as [UserRegisterRequestDto]; - - const loginResponse = await getApp() - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestUser[UserPayloadKey.PASSWORD] - }); - - token = loginResponse.json().token; - }); - - describe(`${imagesEndpoint} (${HttpMethod.POST}) endpoint`, () => { - const app = getApp(); - - it(`should return ${HttpCode.OK} with uploaded image`, async () => { - const formData = new FormData(); - - formData.append( - ImagePayloadKey.IMAGE, - fs.createReadStream( - join( - fileURLToPath(import.meta.url), - '../../../data/images/test-image.png' - ) - ) - ); - - const response = await app - .inject() - .post(imagesEndpoint) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token), - ...formData.getHeaders() - }) - .body(formData); - - expect(response.statusCode).toBe(HttpCode.OK); - expect(response.json()).toHaveProperty('id'); - expect(response.json()).toHaveProperty('link'); - expect(response.json()).toHaveProperty('createdAt'); - expect(response.json()).toHaveProperty('updatedAt'); - - const savedDatabaseImage = await select({ - table: DatabaseTableName.IMAGES, - condition: { id: response.json().id }, - limit: KNEX_SELECT_ONE_RECORD - }); - - expect(savedDatabaseImage).toEqual( - expect.objectContaining({ - id: response.json().id, - link: response.json().link - }) - ); - }); - }); -}); diff --git a/server/tests/api/0-starter/post.api.spec.ts b/server/tests/api/0-starter/post.api.spec.ts deleted file mode 100644 index 198fabdf..00000000 --- a/server/tests/api/0-starter/post.api.spec.ts +++ /dev/null @@ -1,272 +0,0 @@ -import { beforeAll, describe, expect, it } from '@jest/globals'; - -import { ApiPath } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { DatabaseTableName } from '~/libs/packages/database/database.js'; -import { HttpCode, HttpHeader, HttpMethod } from '~/libs/packages/http/http.js'; -import { joinPath } from '~/libs/packages/path/path.js'; -import { - AuthApiPath, - type UserLoginResponseDto, - type UserRegisterRequestDto -} from '~/packages/auth/auth.js'; -import { - type CreatePostRequestDto, - type Post, - type PostWithCommentImageUserNestedRelationsWithCount -} from '~/packages/post/post.js'; -import { PostPayloadKey, PostsApiPath } from '~/packages/post/post.js'; -import { UserPayloadKey } from '~/packages/user/user.js'; - -import { buildApp } from '../../libs/packages/app/app.js'; -import { - getCrudHandlers, - KNEX_SELECT_ONE_RECORD -} from '../../libs/packages/database/database.js'; -import { getBearerAuthHeader } from '../../libs/packages/http/http.js'; -import { TEST_POSTS } from '../../packages/post/post.js'; -import { - setupTestUsers, - TEST_USERS_CREDENTIALS -} from '../../packages/user/user.js'; - -const loginEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.LOGIN -]); - -const postApiPath = joinPath([config.ENV.APP.API_PATH, ApiPath.POSTS]); - -const postsEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.POSTS, - PostsApiPath.ROOT -]); - -const postIdEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.POSTS, - PostsApiPath.$ID -]); - -const postReactEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.POSTS, - PostsApiPath.REACT -]); - -describe(`${postApiPath} routes`, () => { - const { getApp, getKnex } = buildApp(); - const { select, insert } = getCrudHandlers(getKnex); - - let token: string; - let userId: number; - - beforeAll(async () => { - await setupTestUsers({ handlers: { insert } }); - - const [validTestUser] = TEST_USERS_CREDENTIALS as [UserRegisterRequestDto]; - - const loginResponse = await getApp() - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestUser[UserPayloadKey.PASSWORD] - }); - - token = loginResponse.json().token; - userId = loginResponse.json().user.id; - }); - - describe(`${postsEndpoint} (${HttpMethod.POST}) endpoint`, () => { - const app = getApp(); - - it(`should return ${HttpCode.CREATED} with a new post`, async () => { - const [validTestPost] = TEST_POSTS as [ - Omit - ]; - - const response = await app - .inject() - .post(postsEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body(validTestPost); - - expect(response.statusCode).toBe(HttpCode.CREATED); - expect(response.json()).toEqual( - expect.objectContaining({ - userId, - [PostPayloadKey.BODY]: validTestPost[PostPayloadKey.BODY] - }) - ); - expect(response.json()).toHaveProperty('id'); - expect(response.json()).toHaveProperty('createdAt'); - expect(response.json()).toHaveProperty('updatedAt'); - - const savedDatabasePost = await select({ - table: DatabaseTableName.POSTS, - condition: { id: response.json().id }, - limit: KNEX_SELECT_ONE_RECORD - }); - - expect(savedDatabasePost).toEqual( - expect.objectContaining({ - [PostPayloadKey.BODY]: validTestPost[PostPayloadKey.BODY] - }) - ); - }); - }); - - describe(`${postIdEndpoint} (${HttpMethod.GET}) endpoint`, () => { - const app = getApp(); - - it(`should return ${HttpCode.OK} with post by id`, async () => { - const result = await select({ - table: DatabaseTableName.POSTS, - limit: KNEX_SELECT_ONE_RECORD - }); - const { id: postId, body } = (result ?? {}) as Post; - - const response = await app - .inject() - .get(postIdEndpoint.replace(':id', postId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - - expect(response.statusCode).toBe(HttpCode.OK); - expect(response.json()).toEqual( - expect.objectContaining({ - id: postId, - body - }) - ); - expect(response.json()).toHaveProperty('likeCount'); - expect(response.json()).toHaveProperty('createdAt'); - expect(response.json()).toHaveProperty('updatedAt'); - expect(response.json()).toHaveProperty('dislikeCount'); - expect(response.json()).toHaveProperty('commentCount'); - }); - }); - - describe(`${postsEndpoint} (${HttpMethod.GET}) endpoint`, () => { - const app = getApp(); - - it(`should return ${HttpCode.OK} with all posts`, async () => { - const posts = - (await select({ - table: DatabaseTableName.POSTS, - condition: { userId }, - offset: 0, - limit: TEST_POSTS.length - })) as PostWithCommentImageUserNestedRelationsWithCount[]; - - const response = await app - .inject() - .get(postsEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .query({ - from: '0', - count: TEST_POSTS.length.toString(), - userId: userId.toString() - }); - - expect(response.statusCode).toBe(HttpCode.OK); - expect(response.json()).toEqual( - posts.map(post => expect.objectContaining({ ...post })) - ); - - const [post] = - response.json(); - - expect(post).toHaveProperty('id'); - expect(post).toHaveProperty('likeCount'); - expect(post).toHaveProperty('createdAt'); - expect(post).toHaveProperty('updatedAt'); - expect(post).toHaveProperty('dislikeCount'); - expect(post).toHaveProperty('commentCount'); - }); - }); - - describe(`${postReactEndpoint} (${HttpMethod.PUT}) endpoint`, () => { - const app = getApp(); - - it(`should return ${HttpCode.OK} with liked post`, async () => { - const result = await select({ - table: DatabaseTableName.POSTS, - limit: KNEX_SELECT_ONE_RECORD - }); - const { id: postId } = (result ?? {}) as Post; - - const getPostBeforeLikeResponse = await app - .inject() - .get(postIdEndpoint.replace(':id', postId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - const likePostResponse = await app - .inject() - .put(postReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ postId }); - const getPostAfterLikeResponse = await app - .inject() - .get(postIdEndpoint.replace(':id', postId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - - expect(likePostResponse.statusCode).toBe(HttpCode.OK); - expect(likePostResponse.json()).toEqual( - expect.objectContaining({ - userId, - postId, - isLike: true - }) - ); - expect(likePostResponse.json()).toHaveProperty('createdAt'); - expect(likePostResponse.json()).toHaveProperty('updatedAt'); - expect(getPostAfterLikeResponse.json()).toEqual( - expect.objectContaining({ - likeCount: String( - Number( - getPostBeforeLikeResponse.json>() - .likeCount - ) + 1 - ) - }) - ); - }); - - it(`should return ${HttpCode.OK} with removed user's like post`, async () => { - const result = await select({ - table: DatabaseTableName.POSTS, - limit: KNEX_SELECT_ONE_RECORD - }); - const { id: postId } = (result ?? {}) as Post; - - const getPostBeforeLikeResponse = await app - .inject() - .get(postIdEndpoint.replace(':id', postId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - const likePostResponse = await app - .inject() - .put(postReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ postId }); - const getPostAfterLikeResponse = await app - .inject() - .get(postIdEndpoint.replace(':id', postId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - - expect(likePostResponse.statusCode).toBe(HttpCode.OK); - expect(likePostResponse.json()).toEqual({}); - expect(getPostAfterLikeResponse.json()).toEqual( - expect.objectContaining({ - likeCount: String( - Number( - getPostBeforeLikeResponse.json>() - .likeCount - ) - 1 - ) - }) - ); - }); - }); -}); diff --git a/server/tests/api/1-dislike-post/post.api.spec.ts b/server/tests/api/1-dislike-post/post.api.spec.ts deleted file mode 100644 index f44a19be..00000000 --- a/server/tests/api/1-dislike-post/post.api.spec.ts +++ /dev/null @@ -1,319 +0,0 @@ -import { beforeAll, describe, expect, it } from '@jest/globals'; - -import { ApiPath } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { DatabaseTableName } from '~/libs/packages/database/database.js'; -import { HttpCode, HttpHeader, HttpMethod } from '~/libs/packages/http/http.js'; -import { joinPath } from '~/libs/packages/path/path.js'; -import { - type UserLoginResponseDto, - type UserRegisterRequestDto -} from '~/packages/auth/auth.js'; -import { AuthApiPath } from '~/packages/auth/auth.js'; -import { type Post, PostsApiPath } from '~/packages/post/post.js'; -import { UserPayloadKey } from '~/packages/user/user.js'; - -import { buildApp } from '../../libs/packages/app/app.js'; -import { - getCrudHandlers, - KNEX_SELECT_ONE_RECORD -} from '../../libs/packages/database/database.js'; -import { getBearerAuthHeader } from '../../libs/packages/http/http.js'; -import { setupTestPosts } from '../../packages/post/post.js'; -import { - setupTestUsers, - TEST_USERS_CREDENTIALS -} from '../../packages/user/user.js'; - -const loginEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.LOGIN -]); - -const postApiPath = joinPath([config.ENV.APP.API_PATH, ApiPath.POSTS]); - -const postIdEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.POSTS, - PostsApiPath.$ID -]); - -const postReactEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.POSTS, - PostsApiPath.REACT -]); - -describe(`${postApiPath} routes`, () => { - const { getApp, getKnex } = buildApp(); - const { select, insert } = getCrudHandlers(getKnex); - - const app = getApp(); - - let token: string; - - beforeAll(async () => { - await setupTestUsers({ handlers: { insert } }); - await setupTestPosts({ handlers: { select, insert } }); - - const [validTestUser] = TEST_USERS_CREDENTIALS as [UserRegisterRequestDto]; - - const loginResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestUser[UserPayloadKey.PASSWORD] - }); - - token = loginResponse.json().token; - }); - - describe(`${postReactEndpoint} (${HttpMethod.PUT}) endpoint`, () => { - it(`should return ${HttpCode.OK} with liked post`, async () => { - const result = await select({ - table: DatabaseTableName.POSTS, - limit: KNEX_SELECT_ONE_RECORD - }); - const { id: postId } = (result ?? {}) as Post; - - const getPostBeforeLikeResponse = await app - .inject() - .get(postIdEndpoint.replace(':id', postId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - const likePostResponse = await app - .inject() - .put(postReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ postId }); - - expect(likePostResponse.statusCode).toBe(HttpCode.OK); - expect(likePostResponse.json()).toEqual( - expect.objectContaining({ - likeCount: String( - Number( - getPostBeforeLikeResponse.json>() - .likeCount - ) + 1 - ), - dislikeCount: - getPostBeforeLikeResponse.json>() - .dislikeCount - }) - ); - }); - - it(`should return ${HttpCode.OK} with removed user's like post`, async () => { - const result = await select({ - table: DatabaseTableName.POSTS, - limit: KNEX_SELECT_ONE_RECORD - }); - const { id: postId } = (result ?? {}) as Post; - - const getPostBeforeLikeResponse = await app - .inject() - .get(postIdEndpoint.replace(':id', postId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - const likePostResponse = await app - .inject() - .put(`${config.ENV.APP.API_PATH}${ApiPath.POSTS}${PostsApiPath.REACT}`) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ postId }); - - expect(likePostResponse.statusCode).toBe(HttpCode.OK); - expect(likePostResponse.json()).toEqual( - expect.objectContaining({ - likeCount: String( - Number( - getPostBeforeLikeResponse.json>() - .likeCount - ) - 1 - ), - dislikeCount: - getPostBeforeLikeResponse.json>() - .dislikeCount - }) - ); - }); - - it(`should return ${HttpCode.OK} with disliked post`, async () => { - const result = await select({ - table: DatabaseTableName.POSTS, - limit: KNEX_SELECT_ONE_RECORD - }); - const { id: postId } = (result ?? {}) as Post; - - const getPostBeforeLikeResponse = await app - .inject() - .get(postIdEndpoint.replace(':id', postId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - const dislikePostResponse = await app - .inject() - .put(postReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ postId, isLike: false }); - - expect(dislikePostResponse.statusCode).toBe(HttpCode.OK); - expect(dislikePostResponse.json()).toEqual( - expect.objectContaining({ - likeCount: - getPostBeforeLikeResponse.json>() - .likeCount, - dislikeCount: String( - Number( - getPostBeforeLikeResponse.json>() - .dislikeCount - ) + 1 - ) - }) - ); - }); - - it(`should return ${HttpCode.OK} with removed user's dislike post`, async () => { - const result = await select({ - table: DatabaseTableName.POSTS, - limit: KNEX_SELECT_ONE_RECORD - }); - const { id: postId } = (result ?? {}) as Post; - - const getPostBeforeLikeResponse = await app - .inject() - .get(postIdEndpoint.replace(':id', postId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - const dislikePostResponse = await app - .inject() - .put(postReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ postId, isLike: false }); - - expect(dislikePostResponse.statusCode).toBe(HttpCode.OK); - expect(dislikePostResponse.json()).toEqual( - expect.objectContaining({ - likeCount: - getPostBeforeLikeResponse.json>() - .likeCount, - dislikeCount: String( - Number( - getPostBeforeLikeResponse.json>() - .dislikeCount - ) - 1 - ) - }) - ); - }); - - it(`should return ${HttpCode.OK} with switched like to dislike post`, async () => { - const result = await select({ - table: DatabaseTableName.POSTS, - limit: KNEX_SELECT_ONE_RECORD - }); - const { id: postId } = (result ?? {}) as Post; - - const getPostBeforeLikeResponse = await app - .inject() - .get(postIdEndpoint.replace(':id', postId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - const likePostResponse = await app - .inject() - .put(postReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ postId, isLike: true }); - const dislikePostResponse = await app - .inject() - .put(postReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ postId, isLike: false }); - await app - .inject() - .put(postReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ postId, isLike: false }); - - expect(likePostResponse.statusCode).toBe(HttpCode.OK); - expect(dislikePostResponse.statusCode).toBe(HttpCode.OK); - expect(likePostResponse.json()).toEqual( - expect.objectContaining({ - likeCount: String( - Number( - getPostBeforeLikeResponse.json>() - .likeCount - ) + 1 - ), - dislikeCount: - getPostBeforeLikeResponse.json>() - .dislikeCount - }) - ); - expect(dislikePostResponse.json()).toEqual( - expect.objectContaining({ - likeCount: String( - Number( - likePostResponse.json>().likeCount - ) - 1 - ), - dislikeCount: String( - Number( - likePostResponse.json>() - .dislikeCount - ) + 1 - ) - }) - ); - }); - - it(`should return ${HttpCode.OK} with switched dislike to like post`, async () => { - const result = await select({ - table: DatabaseTableName.POSTS, - limit: KNEX_SELECT_ONE_RECORD - }); - const { id: postId } = (result ?? {}) as Post; - - const getPostBeforeLikeResponse = await app - .inject() - .get(postIdEndpoint.replace(':id', postId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - const dislikePostResponse = await app - .inject() - .put(postReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ postId, isLike: false }); - const likePostResponse = await app - .inject() - .put(postReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ postId, isLike: true }); - - expect(likePostResponse.statusCode).toBe(HttpCode.OK); - expect(dislikePostResponse.statusCode).toBe(HttpCode.OK); - expect(dislikePostResponse.json()).toEqual( - expect.objectContaining({ - likeCount: - getPostBeforeLikeResponse.json>() - .likeCount, - dislikeCount: String( - Number( - getPostBeforeLikeResponse.json>() - .dislikeCount - ) + 1 - ) - }) - ); - expect(likePostResponse.json()).toEqual( - expect.objectContaining({ - likeCount: String( - Number( - dislikePostResponse.json>().likeCount - ) + 1 - ), - dislikeCount: String( - Number( - dislikePostResponse.json>() - .dislikeCount - ) - 1 - ) - }) - ); - }); - }); -}); diff --git a/server/tests/api/10-show-who-liked-comment/post-comment.api.spec.ts b/server/tests/api/10-show-who-liked-comment/post-comment.api.spec.ts deleted file mode 100644 index 0a45cfa8..00000000 --- a/server/tests/api/10-show-who-liked-comment/post-comment.api.spec.ts +++ /dev/null @@ -1,199 +0,0 @@ -import { beforeAll, describe, expect, it } from '@jest/globals'; - -import { ApiPath } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { DatabaseTableName } from '~/libs/packages/database/database.js'; -import { HttpCode, HttpHeader, HttpMethod } from '~/libs/packages/http/http.js'; -import { joinPath } from '~/libs/packages/path/path.js'; -import { - type UserLoginResponseDto, - type UserRegisterRequestDto -} from '~/packages/auth/auth.js'; -import { AuthApiPath } from '~/packages/auth/auth.js'; -import { type Comment, CommentsApiPath } from '~/packages/comment/comment.js'; -import { PostsApiPath } from '~/packages/post/post.js'; -import { UserPayloadKey } from '~/packages/user/user.js'; - -import { buildApp } from '../../libs/packages/app/app.js'; -import { getCrudHandlers } from '../../libs/packages/database/database.js'; -import { getBearerAuthHeader } from '../../libs/packages/http/http.js'; -import { setupTestComments } from '../../packages/comment/comment.js'; -import { setupTestPosts } from '../../packages/post/post.js'; -import { - setupTestUsers, - TEST_USERS_CREDENTIALS -} from '../../packages/user/user.js'; - -const loginEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.LOGIN -]); - -const commentApiPath = joinPath([config.ENV.APP.API_PATH, ApiPath.COMMENTS]); - -const postApiPath = joinPath([config.ENV.APP.API_PATH, ApiPath.POSTS]); - -const postIdEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.POSTS, - PostsApiPath.$ID -]); - -const commentReactEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.COMMENTS, - CommentsApiPath.REACT -]); - -const commentIdEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.COMMENTS, - CommentsApiPath.$ID -]); - -describe(`${commentApiPath} and ${postApiPath} routes`, () => { - const { getApp, getKnex } = buildApp(); - const { select, insert } = getCrudHandlers(getKnex); - - const app = getApp(); - - let token: string; - let userId: number; - - beforeAll(async () => { - await setupTestUsers({ handlers: { insert } }); - await setupTestPosts({ handlers: { select, insert } }); - await setupTestComments({ handlers: { select, insert } }); - - const [validTestUser] = TEST_USERS_CREDENTIALS as [UserRegisterRequestDto]; - - const loginUserResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestUser[UserPayloadKey.PASSWORD] - }); - - token = loginUserResponse.json().token; - userId = loginUserResponse.json().user.id; - - const result = await select({ - table: DatabaseTableName.COMMENTS - }); - const [{ id: firstCommentId }, { id: secondCommentId }] = result as [ - Comment, - Comment - ]; - - await app - .inject() - .put(commentReactEndpoint) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) - }) - .body({ commentId: firstCommentId }); - await app - .inject() - .put(commentReactEndpoint) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) - }) - .body({ postId: secondCommentId, isLike: false }); - }); - - describe(`${commentIdEndpoint} (${HttpMethod.GET}) endpoint`, () => { - it(`should return ${HttpCode.OK} with likes and dislikes of comment`, async () => { - const result = await select({ - table: DatabaseTableName.COMMENTS - }); - const [{ id: firstCommentId }, { id: secondCommentId }] = result as [ - Comment, - Comment - ]; - - const firstResponse = await app - .inject() - .get(commentIdEndpoint.replace(':id', firstCommentId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - - const secondResponse = await app - .inject() - .get(commentIdEndpoint.replace(':id', secondCommentId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - - expect(firstResponse.statusCode).toBe(HttpCode.OK); - expect(firstResponse.json()).toEqual( - expect.objectContaining({ - id: firstCommentId, - likes: expect.arrayContaining([expect.objectContaining({ userId })]), - dislikes: [] - }) - ); - - expect(secondResponse.statusCode).toBe(HttpCode.OK); - expect(secondResponse.json()).toEqual( - expect.objectContaining({ - id: secondCommentId, - likes: [], - dislikes: expect.arrayContaining([ - expect.objectContaining({ userId }) - ]) - }) - ); - }); - }); - - describe(`${postIdEndpoint} (${HttpMethod.GET}) endpoint`, () => { - it(`should return ${HttpCode.OK} with likes and dislikes of post's comment`, async () => { - const result = await select({ table: DatabaseTableName.COMMENTS }); - const [ - { id: firstCommentId, postId: firstPostId }, - { id: secondCommentId, postId: secondPostId } - ] = result as [Comment, Comment]; - - const firstPostResponse = await app - .inject() - .get(postIdEndpoint.replace(':id', firstPostId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - - const secondPostResponse = await app - .inject() - .get(postIdEndpoint.replace(':id', secondPostId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - - expect(firstPostResponse.statusCode).toBe(HttpCode.OK); - expect(firstPostResponse.json()).toEqual( - expect.objectContaining({ - id: firstPostId, - comments: expect.arrayContaining([ - expect.objectContaining({ - id: firstCommentId, - likes: expect.arrayContaining([ - expect.objectContaining({ userId }) - ]), - dislikes: [] - }) - ]) - }) - ); - - expect(secondPostResponse.statusCode).toBe(HttpCode.OK); - expect(secondPostResponse.json()).toEqual( - expect.objectContaining({ - id: secondPostId, - comments: expect.arrayContaining([ - expect.objectContaining({ - id: secondCommentId, - likes: [], - dilikes: expect.arrayContaining([ - expect.objectContaining({ userId }) - ]) - }) - ]) - }) - ); - }); - }); -}); diff --git a/server/tests/api/11-update-profile/user.api.spec.ts b/server/tests/api/11-update-profile/user.api.spec.ts deleted file mode 100644 index 0d55a713..00000000 --- a/server/tests/api/11-update-profile/user.api.spec.ts +++ /dev/null @@ -1,165 +0,0 @@ -import fs from 'node:fs'; -import { join } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -import { faker } from '@faker-js/faker'; -import { beforeAll, describe, expect, it } from '@jest/globals'; -import FormData from 'form-data'; - -import { ApiPath } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { HttpCode, HttpHeader, HttpMethod } from '~/libs/packages/http/http.js'; -import { joinPath } from '~/libs/packages/path/path.js'; -import { - type UserLoginResponseDto, - type UserRegisterRequestDto -} from '~/packages/auth/auth.js'; -import { AuthApiPath } from '~/packages/auth/auth.js'; -import { ImagePayloadKey, ImagesApiPath } from '~/packages/image/image.js'; -import { type Image } from '~/packages/image/image.js'; -import { - type UserAuthResponse, - UserPayloadKey, - UsersApiPath -} from '~/packages/user/user.js'; - -import { buildApp } from '../../libs/packages/app/app.js'; -import { getCrudHandlers } from '../../libs/packages/database/database.js'; -import { getBearerAuthHeader } from '../../libs/packages/http/http.js'; -import { - setupTestUsers, - TEST_USERS_CREDENTIALS -} from '../../packages/user/user.js'; - -const loginEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.LOGIN -]); - -const userApiPath = joinPath([config.ENV.APP.API_PATH, ApiPath.USERS]); - -const userIdEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.USERS, - UsersApiPath.$ID -]); - -const imagesEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.IMAGES, - ImagesApiPath.ROOT -]); - -describe(`${userApiPath} routes`, () => { - const { getApp, getKnex } = buildApp(); - const { insert } = getCrudHandlers(getKnex); - - const app = getApp(); - - let tokenMainUser: string; - let tokenMinorUser: string; - let userMain: UserAuthResponse; - - beforeAll(async () => { - await setupTestUsers({ handlers: { insert } }); - - const [validTestMainUser, validTestMinorUser] = TEST_USERS_CREDENTIALS as [ - UserRegisterRequestDto, - UserRegisterRequestDto - ]; - - const loginMainUserResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestMainUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestMainUser[UserPayloadKey.PASSWORD] - }); - - const loginMinorUserResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestMinorUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestMinorUser[UserPayloadKey.PASSWORD] - }); - - tokenMainUser = loginMainUserResponse.json().token; - tokenMinorUser = loginMinorUserResponse.json().token; - userMain = loginMainUserResponse.json().user; - }); - - describe(`${userIdEndpoint} (${HttpMethod.PUT}) endpoint`, () => { - it(`should return ${HttpCode.FORBIDDEN} with attempt to update user by not own one`, async () => { - const updatedMainUser = { - ...userMain, - [UserPayloadKey.USERNAME]: faker.person.firstName() - }; - - const updateUserResponse = await app - .inject() - .put(userIdEndpoint.replace(':id', userMain.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMinorUser) - }) - .body(updatedMainUser); - - const getUserResponse = await app - .inject() - .get(userIdEndpoint.replace(':id', userMain.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMinorUser) - }); - - expect(updateUserResponse.statusCode).toBe(HttpCode.FORBIDDEN); - expect(getUserResponse.json()).toEqual(userMain); - }); - - it(`should return ${HttpCode.OK} with updated user`, async () => { - const formData = new FormData(); - - formData.append( - ImagePayloadKey.IMAGE, - fs.createReadStream( - join( - fileURLToPath(import.meta.url), - '../../../data/images/test-image.png' - ) - ) - ); - - const uploadImageResponse = await app - .inject() - .post(imagesEndpoint) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMainUser), - ...formData.getHeaders() - }) - .body(formData); - - const { id: imageId } = uploadImageResponse.json(); - const updatedMainUser = { - ...userMain, - [UserPayloadKey.USERNAME]: faker.person.firstName(), - imageId - }; - const response = await app - .inject() - .put(userIdEndpoint.replace(':id', userMain.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMainUser) - }) - .body(updatedMainUser); - - expect(response.statusCode).toBe(HttpCode.OK); - expect(response.json()).toEqual( - expect.objectContaining({ - id: userMain.id, - imageId: updatedMainUser.imageId, - [UserPayloadKey.USERNAME]: updatedMainUser[UserPayloadKey.USERNAME] - }) - ); - }); - }); -}); diff --git a/server/tests/api/12-set-user-status/auth-user.api.spec.ts b/server/tests/api/12-set-user-status/auth-user.api.spec.ts deleted file mode 100644 index 531d80fb..00000000 --- a/server/tests/api/12-set-user-status/auth-user.api.spec.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { faker } from '@faker-js/faker'; -import { beforeAll, describe, expect, it } from '@jest/globals'; - -import { ApiPath } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { HttpCode, HttpHeader, HttpMethod } from '~/libs/packages/http/http.js'; -import { joinPath } from '~/libs/packages/path/path.js'; -import { - type UserLoginResponseDto, - type UserRegisterRequestDto -} from '~/packages/auth/auth.js'; -import { AuthApiPath } from '~/packages/auth/auth.js'; -import { - type UserAuthResponse, - UserPayloadKey, - UsersApiPath -} from '~/packages/user/user.js'; - -import { buildApp } from '../../libs/packages/app/app.js'; -import { getCrudHandlers } from '../../libs/packages/database/database.js'; -import { getBearerAuthHeader } from '../../libs/packages/http/http.js'; -import { - setupTestUsers, - TEST_USERS_CREDENTIALS -} from '../../packages/user/user.js'; - -const loginEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.LOGIN -]); - -const authApiPath = joinPath([config.ENV.APP.API_PATH, ApiPath.AUTH]); - -const userApiPath = joinPath([config.ENV.APP.API_PATH, ApiPath.USERS]); - -const userIdEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.USERS, - UsersApiPath.$ID -]); - -const authUserEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.USER -]); - -describe(`${userApiPath} and ${authApiPath} routes`, () => { - const { getApp, getKnex } = buildApp(); - const { insert } = getCrudHandlers(getKnex); - - const app = getApp(); - - let tokenMainUser: string; - let tokenMinorUser: string; - let userMain: UserAuthResponse; - - beforeAll(async () => { - await setupTestUsers({ handlers: { insert } }); - - const [validTestMainUser, validTestMinorUser] = TEST_USERS_CREDENTIALS as [ - UserRegisterRequestDto, - UserRegisterRequestDto - ]; - - const loginMainUserResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestMainUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestMainUser[UserPayloadKey.PASSWORD] - }); - - const loginMinorUserResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestMinorUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestMinorUser[UserPayloadKey.PASSWORD] - }); - - tokenMainUser = loginMainUserResponse.json().token; - tokenMinorUser = loginMinorUserResponse.json().token; - userMain = loginMainUserResponse.json().user; - }); - - describe(`${userIdEndpoint} (${HttpMethod.PUT}) endpoint`, () => { - it(`should return ${HttpCode.FORBIDDEN} with attempt to update user by not own one`, async () => { - const updatedMainUser = { - ...userMain, - [UserPayloadKey.STATUS]: faker.lorem.words() - }; - - const updateUserResponse = await app - .inject() - .put(userIdEndpoint.replace(':id', userMain.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMinorUser) - }) - .body(updatedMainUser); - - const getUserResponse = await app - .inject() - .get(userIdEndpoint.replace(':id', userMain.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMinorUser) - }); - - expect(updateUserResponse.statusCode).toBe(HttpCode.FORBIDDEN); - expect(getUserResponse.json()).toEqual(userMain); - }); - - it(`should return ${HttpCode.OK} with user's status`, async () => { - const updatedMainUser = { - ...userMain, - [UserPayloadKey.STATUS]: faker.lorem.words() - }; - const response = await app - .inject() - .put(userIdEndpoint.replace(':id', userMain.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMainUser) - }) - .body(updatedMainUser); - - expect(response.statusCode).toBe(HttpCode.OK); - expect(response.json()).toEqual( - expect.objectContaining({ - id: userMain.id, - [UserPayloadKey.STATUS]: updatedMainUser[UserPayloadKey.STATUS] - }) - ); - }); - }); - - describe(`${authUserEndpoint} endpoints`, () => { - it(`should return ${HttpCode.OK} with auth user`, async () => { - const response = await app - .inject() - .get(authUserEndpoint) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMainUser) - }); - - expect(response.statusCode).toBe(HttpCode.OK); - expect(response.json()).toEqual( - expect.objectContaining({ id: userMain.id }) - ); - expect(response.json()).toHaveProperty('status'); - }); - }); -}); diff --git a/server/tests/api/13-reset-set-password/password.api.spec.ts b/server/tests/api/13-reset-set-password/password.api.spec.ts deleted file mode 100644 index 9e8da347..00000000 --- a/server/tests/api/13-reset-set-password/password.api.spec.ts +++ /dev/null @@ -1,226 +0,0 @@ -import { faker } from '@faker-js/faker'; -import { beforeAll, describe, expect, it } from '@jest/globals'; - -import { ApiPath, ExceptionMessage } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { HttpCode } from '~/libs/packages/http/http.js'; -import { joinPath } from '~/libs/packages/path/path.js'; -import { - type UserLoginResponseDto, - type UserRegisterRequestDto -} from '~/packages/auth/auth.js'; -import { AuthApiPath } from '~/packages/auth/auth.js'; -import { PasswordApiPath } from '~/packages/password/password.js'; -import { - type UserAuthResponse, - UserPayloadKey, - UserValidationMessage, - UserValidationRule -} from '~/packages/user/user.js'; - -import { buildApp } from '../../libs/packages/app/app.js'; -import { getCrudHandlers } from '../../libs/packages/database/database.js'; -import { - setupTestUsers, - TEST_USERS_CREDENTIALS -} from '../../packages/user/user.js'; - -const passwordEndpoint = joinPath([config.ENV.APP.API_PATH, ApiPath.PASSWORD]); - -const loginEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.LOGIN -]); - -const resetPasswordEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.PASSWORD, - PasswordApiPath.RESET -]); - -const setPasswordEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.PASSWORD, - PasswordApiPath.SET -]); - -describe(`${passwordEndpoint} routes`, () => { - const { getApp, getKnex } = buildApp(); - const { insert } = getCrudHandlers(getKnex); - - const app = getApp(); - - let user: UserAuthResponse; - - beforeAll(async () => { - await setupTestUsers({ handlers: { insert } }); - const [validTestUser] = TEST_USERS_CREDENTIALS as [UserRegisterRequestDto]; - - const loginUserResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestUser[UserPayloadKey.PASSWORD] - }); - - user = loginUserResponse.json().user; - }); - - describe(`${resetPasswordEndpoint} endpoint`, () => { - it(`should return ${HttpCode.BAD_REQUEST} of empty ${UserPayloadKey.EMAIL} validation error`, async () => { - const response = await app.inject().post(resetPasswordEndpoint).body({}); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.EMAIL_REQUIRE - ); - }); - - it(`should return ${HttpCode.BAD_REQUEST} of wrong ${UserPayloadKey.EMAIL} validation error`, async () => { - const response = await app - .inject() - .post(resetPasswordEndpoint) - .body({ - [UserPayloadKey.EMAIL]: faker.person.firstName() - }); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.EMAIL_WRONG - ); - }); - - it(`should return ${HttpCode.NOT_FOUND} if email not exists`, async () => { - const response = await app - .inject() - .post(resetPasswordEndpoint) - .body({ - [UserPayloadKey.EMAIL]: faker.internet.email() - }); - - expect(response.statusCode).toBe(HttpCode.NOT_FOUND); - expect(response.json>().message).toBe( - ExceptionMessage.USER_WITH_EMAIL_NOT_FOUND - ); - }); - - it(`should return ${HttpCode.OK} with token`, async () => { - const response = await app - .inject() - .post(resetPasswordEndpoint) - .body({ - [UserPayloadKey.EMAIL]: user[UserPayloadKey.EMAIL] - }); - - expect(response.statusCode).toBe(HttpCode.OK); - expect(response.json()).toHaveProperty(UserPayloadKey.TOKEN as string); - }); - }); - - describe(`${setPasswordEndpoint} endpoint`, () => { - it(`should return ${HttpCode.BAD_REQUEST} of empty ${UserPayloadKey.TOKEN} validation error`, async () => { - const response = await app.inject().post(setPasswordEndpoint).body({}); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.TOKEN_REQUIRE - ); - }); - - it(`should return ${HttpCode.BAD_REQUEST} of empty ${UserPayloadKey.PASSWORD} validation error`, async () => { - const response = await app - .inject() - .post(setPasswordEndpoint) - .body({ - [UserPayloadKey.TOKEN]: faker.string.sample() - }); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.PASSWORD_REQUIRE - ); - }); - - it(`should return ${HttpCode.BAD_REQUEST} of too short ${UserPayloadKey.PASSWORD} validation error`, async () => { - const response = await app - .inject() - .post(setPasswordEndpoint) - .body({ - [UserPayloadKey.TOKEN]: faker.string.sample(), - [UserPayloadKey.PASSWORD]: faker.internet.password({ - length: UserValidationRule.PASSWORD_MIN_LENGTH - 2 - }) - }); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.PASSWORD_MIN_LENGTH - ); - }); - - it(`should return ${HttpCode.BAD_REQUEST} of too long ${UserPayloadKey.PASSWORD} validation error`, async () => { - const response = await app - .inject() - .post(setPasswordEndpoint) - .body({ - [UserPayloadKey.TOKEN]: faker.string.sample(), - [UserPayloadKey.PASSWORD]: faker.internet.password({ - length: UserValidationRule.PASSWORD_MAX_LENGTH + 2 - }) - }); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - UserValidationMessage.PASSWORD_MAX_LENGTH - ); - }); - - it(`should return ${HttpCode.BAD_REQUEST} of invalid ${UserPayloadKey.TOKEN} validation error`, async () => { - const response = await app - .inject() - .post(setPasswordEndpoint) - .body({ - [UserPayloadKey.TOKEN]: faker.string.sample(), - [UserPayloadKey.PASSWORD]: faker.internet.password() - }); - - expect(response.statusCode).toBe(HttpCode.BAD_REQUEST); - expect(response.json>().message).toBe( - ExceptionMessage.INVALID_TOKEN - ); - }); - - it(`should return ${HttpCode.OK} with auth result`, async () => { - const resetPasswordResponse = await app - .inject() - .post(resetPasswordEndpoint) - .body({ - [UserPayloadKey.EMAIL]: user[UserPayloadKey.EMAIL] - }); - - const newPassword = faker.internet.password(); - - const setPasswordResponse = await app - .inject() - .post(setPasswordEndpoint) - .body({ - [UserPayloadKey.TOKEN]: - resetPasswordResponse.json>().token, - [UserPayloadKey.PASSWORD]: newPassword - }); - - const response = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: user[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: newPassword - }); - - expect(setPasswordResponse.statusCode).toBe(HttpCode.OK); - expect(response.statusCode).toBe(HttpCode.OK); - }); - }); -}); diff --git a/server/tests/api/2-update-post/post.api.spec.ts b/server/tests/api/2-update-post/post.api.spec.ts deleted file mode 100644 index fabf2656..00000000 --- a/server/tests/api/2-update-post/post.api.spec.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { faker } from '@faker-js/faker'; -import { beforeAll, describe, expect, it } from '@jest/globals'; - -import { ApiPath } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { DatabaseTableName } from '~/libs/packages/database/database.js'; -import { HttpCode, HttpHeader, HttpMethod } from '~/libs/packages/http/http.js'; -import { joinPath } from '~/libs/packages/path/path.js'; -import { - type UserLoginResponseDto, - type UserRegisterRequestDto -} from '~/packages/auth/auth.js'; -import { AuthApiPath } from '~/packages/auth/auth.js'; -import { - type Post, - PostPayloadKey, - PostsApiPath -} from '~/packages/post/post.js'; -import { UserPayloadKey } from '~/packages/user/user.js'; - -import { buildApp } from '../../libs/packages/app/app.js'; -import { - getCrudHandlers, - KNEX_SELECT_ONE_RECORD -} from '../../libs/packages/database/database.js'; -import { getBearerAuthHeader } from '../../libs/packages/http/http.js'; -import { setupTestPosts } from '../../packages/post/post.js'; -import { - setupTestUsers, - TEST_USERS_CREDENTIALS -} from '../../packages/user/user.js'; - -const loginEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.LOGIN -]); - -const postApiPath = joinPath([config.ENV.APP.API_PATH, ApiPath.POSTS]); - -const postIdEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.POSTS, - PostsApiPath.$ID -]); - -describe(`${postApiPath} routes`, () => { - const { getApp, getKnex } = buildApp(); - const { select, insert } = getCrudHandlers(getKnex); - - const app = getApp(); - - let tokenMainUser: string; - let tokenMinorUser: string; - - beforeAll(async () => { - await setupTestUsers({ handlers: { insert } }); - await setupTestPosts({ handlers: { select, insert } }); - - const [validTestMainUser, validTestMinorUser] = TEST_USERS_CREDENTIALS as [ - UserRegisterRequestDto, - UserRegisterRequestDto - ]; - - const loginMainUserResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestMainUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestMainUser[UserPayloadKey.PASSWORD] - }); - - const loginMinorUserResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestMinorUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestMinorUser[UserPayloadKey.PASSWORD] - }); - - tokenMainUser = loginMainUserResponse.json().token; - tokenMinorUser = loginMinorUserResponse.json().token; - }); - - describe(`${postIdEndpoint} (${HttpMethod.PUT}) endpoint`, () => { - it(`should return ${HttpCode.FORBIDDEN} with attempt to update post by not own user`, async () => { - const post = (await select({ - table: DatabaseTableName.POSTS, - limit: KNEX_SELECT_ONE_RECORD - })) as Post; - - const testUpdatedPost = { - ...post, - [PostPayloadKey.BODY]: faker.lorem.paragraph() - }; - - const updatePostResponse = await app - .inject() - .put(postIdEndpoint.replace(':id', post.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMinorUser) - }) - .body(testUpdatedPost); - - const getPostResponse = await app - .inject() - .get(postIdEndpoint.replace(':id', post.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMinorUser) - }); - - expect(updatePostResponse.statusCode).toBe(HttpCode.FORBIDDEN); - expect(getPostResponse.json()).toMatchObject(post); - }); - - it(`should return ${HttpCode.OK} with updated post`, async () => { - const post = (await select({ - table: DatabaseTableName.POSTS, - limit: KNEX_SELECT_ONE_RECORD - })) as Post; - - const testUpdatedPost = { - ...post, - [PostPayloadKey.BODY]: faker.lorem.paragraph() - }; - - const updatePostResponse = await app - .inject() - .put(postIdEndpoint.replace(':id', post.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMainUser) - }) - .body(testUpdatedPost); - - expect(updatePostResponse.statusCode).toBe(HttpCode.OK); - expect(updatePostResponse.json()).toEqual( - expect.objectContaining({ - id: testUpdatedPost.id, - createdAt: post.createdAt, - [PostPayloadKey.BODY]: testUpdatedPost[PostPayloadKey.BODY] - }) - ); - }); - }); -}); diff --git a/server/tests/api/3-delete-post/post.api.spec.ts b/server/tests/api/3-delete-post/post.api.spec.ts deleted file mode 100644 index 982f063e..00000000 --- a/server/tests/api/3-delete-post/post.api.spec.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { beforeAll, describe, expect, it } from '@jest/globals'; - -import { ApiPath } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { DatabaseTableName } from '~/libs/packages/database/database.js'; -import { HttpCode, HttpHeader, HttpMethod } from '~/libs/packages/http/http.js'; -import { joinPath } from '~/libs/packages/path/path.js'; -import { - type UserLoginResponseDto, - type UserRegisterRequestDto -} from '~/packages/auth/auth.js'; -import { AuthApiPath } from '~/packages/auth/auth.js'; -import { - type Post, - PostPayloadKey, - PostsApiPath -} from '~/packages/post/post.js'; -import { UserPayloadKey } from '~/packages/user/user.js'; - -import { buildApp } from '../../libs/packages/app/app.js'; -import { - getCrudHandlers, - KNEX_SELECT_ONE_RECORD -} from '../../libs/packages/database/database.js'; -import { getBearerAuthHeader } from '../../libs/packages/http/http.js'; -import { setupTestPosts } from '../../packages/post/post.js'; -import { - setupTestUsers, - TEST_USERS_CREDENTIALS -} from '../../packages/user/user.js'; - -const loginEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.LOGIN -]); - -const postApiPath = joinPath([config.ENV.APP.API_PATH, ApiPath.POSTS]); - -const postIdEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.POSTS, - PostsApiPath.$ID -]); - -const postsEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.POSTS, - PostsApiPath.ROOT -]); - -describe(`${postApiPath} routes`, () => { - const { getApp, getKnex } = buildApp(); - const { select, insert } = getCrudHandlers(getKnex); - - const app = getApp(); - - let tokenMainUser: string; - let tokenMinorUser: string; - - beforeAll(async () => { - await setupTestUsers({ handlers: { insert } }); - await setupTestPosts({ handlers: { select, insert } }); - - const [validTestMainUser, validTestMinorUser] = TEST_USERS_CREDENTIALS as [ - UserRegisterRequestDto, - UserRegisterRequestDto - ]; - - const loginMainUserResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestMainUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestMainUser[UserPayloadKey.PASSWORD] - }); - - const loginMinorUserResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestMinorUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestMinorUser[UserPayloadKey.PASSWORD] - }); - - tokenMainUser = loginMainUserResponse.json().token; - tokenMinorUser = loginMinorUserResponse.json().token; - }); - - describe(`${postIdEndpoint} (${HttpMethod.DELETE}) endpoint`, () => { - it(`should return ${HttpCode.FORBIDDEN} with attempt to delete post by not own user`, async () => { - const postToDelete = (await select({ - table: DatabaseTableName.POSTS, - limit: KNEX_SELECT_ONE_RECORD - })) as Post; - - const deletePostResponse = await app - .inject() - .delete(postIdEndpoint.replace(':id', postToDelete.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMinorUser) - }); - - const getPostResponse = await app - .inject() - .get(postIdEndpoint.replace(':id', postToDelete.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMinorUser) - }); - - expect(deletePostResponse.statusCode).toBe(HttpCode.FORBIDDEN); - expect(getPostResponse.json()).toMatchObject(postToDelete); - }); - - it(`should return ${HttpCode.OK} with soft deleted post`, async () => { - const postToDelete = (await select({ - table: DatabaseTableName.POSTS, - limit: KNEX_SELECT_ONE_RECORD - })) as Post; - - const deletePostResponse = await app - .inject() - .delete(postIdEndpoint.replace(':id', postToDelete.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMainUser) - }); - - const getPostResponse = await app - .inject() - .get(postIdEndpoint.replace(':id', postToDelete.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMainUser) - }); - - expect(deletePostResponse.statusCode).toBe(HttpCode.OK); - expect(getPostResponse.json()).toEqual( - expect.objectContaining({ - id: postToDelete.id, - createdAt: postToDelete.createdAt, - [PostPayloadKey.BODY]: postToDelete[PostPayloadKey.BODY] - }) - ); - expect(getPostResponse.json()).toHaveProperty('deletedAt'); - }); - }); - - describe(`${postsEndpoint} (${HttpMethod.GET}) endpoint`, () => { - it(`should return ${HttpCode.OK} with ignoring soft deleted post`, async () => { - const postToDelete = (await select({ - table: DatabaseTableName.POSTS, - limit: KNEX_SELECT_ONE_RECORD - })) as Post; - - await app - .inject() - .delete(postIdEndpoint.replace(':id', postToDelete.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMainUser) - }); - - const getPostsResponse = await app - .inject() - .get(postsEndpoint) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMinorUser) - }) - .query({ from: '0', count: '1' }); - - expect(getPostsResponse.statusCode).toBe(HttpCode.OK); - expect(getPostsResponse.json()).not.toEqual( - expect.arrayContaining([ - expect.objectContaining({ id: postToDelete.id }) - ]) - ); - }); - }); -}); diff --git a/server/tests/api/4-update-comment/comment.api.spec.ts b/server/tests/api/4-update-comment/comment.api.spec.ts deleted file mode 100644 index 4cde0722..00000000 --- a/server/tests/api/4-update-comment/comment.api.spec.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { faker } from '@faker-js/faker'; -import { beforeAll, describe, expect, it } from '@jest/globals'; - -import { ApiPath } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { DatabaseTableName } from '~/libs/packages/database/database.js'; -import { HttpCode, HttpHeader, HttpMethod } from '~/libs/packages/http/http.js'; -import { joinPath } from '~/libs/packages/path/path.js'; -import { - type UserLoginResponseDto, - type UserRegisterRequestDto -} from '~/packages/auth/auth.js'; -import { AuthApiPath } from '~/packages/auth/auth.js'; -import { - type Comment, - CommentPayloadKey, - CommentsApiPath -} from '~/packages/comment/comment.js'; -import { PostPayloadKey } from '~/packages/post/post.js'; -import { UserPayloadKey } from '~/packages/user/user.js'; - -import { buildApp } from '../../libs/packages/app/app.js'; -import { - getCrudHandlers, - KNEX_SELECT_ONE_RECORD -} from '../../libs/packages/database/database.js'; -import { getBearerAuthHeader } from '../../libs/packages/http/http.js'; -import { setupTestComments } from '../../packages/comment/comment.js'; -import { setupTestPosts } from '../../packages/post/post.js'; -import { - setupTestUsers, - TEST_USERS_CREDENTIALS -} from '../../packages/user/user.js'; - -const loginEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.LOGIN -]); - -const commentApiPath = joinPath([config.ENV.APP.API_PATH, ApiPath.COMMENTS]); - -const commentIdEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.COMMENTS, - CommentsApiPath.$ID -]); - -describe(`${commentApiPath} routes`, () => { - const { getApp, getKnex } = buildApp(); - const { select, insert } = getCrudHandlers(getKnex); - - const app = getApp(); - - let tokenMainUser: string; - let tokenMinorUser: string; - - beforeAll(async () => { - await setupTestUsers({ handlers: { insert } }); - await setupTestPosts({ handlers: { select, insert } }); - await setupTestComments({ handlers: { select, insert } }); - - const [validTestMainUser, validTestMinorUser] = TEST_USERS_CREDENTIALS as [ - UserRegisterRequestDto, - UserRegisterRequestDto - ]; - - const loginMainUserResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestMainUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestMainUser[UserPayloadKey.PASSWORD] - }); - - const loginMinorUserResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestMinorUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestMinorUser[UserPayloadKey.PASSWORD] - }); - - tokenMainUser = loginMainUserResponse.json().token; - tokenMinorUser = loginMinorUserResponse.json().token; - }); - - describe(`${commentIdEndpoint} (${HttpMethod.PUT}) endpoint`, () => { - it(`should return ${HttpCode.FORBIDDEN} with attempt to update comment by not own user`, async () => { - const comment = (await select({ - table: DatabaseTableName.COMMENTS, - limit: KNEX_SELECT_ONE_RECORD - })) as Comment; - - const testUpdatedComment = { - ...comment, - [CommentPayloadKey.BODY]: faker.lorem.paragraph() - }; - - const updateCommentResponse = await app - .inject() - .put(commentIdEndpoint.replace(':id', comment.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMinorUser) - }) - .body(testUpdatedComment); - - const getCommentResponse = await app - .inject() - .get(commentIdEndpoint.replace(':id', comment.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMinorUser) - }); - - expect(updateCommentResponse.statusCode).toBe(HttpCode.FORBIDDEN); - expect(getCommentResponse.json()).toMatchObject(comment); - }); - - it(`should return ${HttpCode.OK} with updated comment`, async () => { - const comment = (await select({ - table: DatabaseTableName.COMMENTS, - limit: KNEX_SELECT_ONE_RECORD - })) as Comment; - - const testUpdatedComment = { - ...comment, - [CommentPayloadKey.BODY]: faker.lorem.paragraph() - }; - - const updateCommentResponse = await app - .inject() - .put(commentIdEndpoint.replace(':id', comment.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMainUser) - }) - .body(testUpdatedComment); - - expect(updateCommentResponse.statusCode).toBe(HttpCode.OK); - expect(updateCommentResponse.json()).toEqual( - expect.objectContaining({ - id: testUpdatedComment.id, - createdAt: testUpdatedComment.createdAt, - [CommentPayloadKey.BODY]: testUpdatedComment[PostPayloadKey.BODY] - }) - ); - }); - }); -}); diff --git a/server/tests/api/5-delete-comment/comment.api.spec.ts b/server/tests/api/5-delete-comment/comment.api.spec.ts deleted file mode 100644 index 845d5f95..00000000 --- a/server/tests/api/5-delete-comment/comment.api.spec.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { beforeAll, describe, expect, it } from '@jest/globals'; - -import { ApiPath } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { DatabaseTableName } from '~/libs/packages/database/database.js'; -import { HttpCode, HttpHeader, HttpMethod } from '~/libs/packages/http/http.js'; -import { joinPath } from '~/libs/packages/path/path.js'; -import { - type UserLoginResponseDto, - type UserRegisterRequestDto -} from '~/packages/auth/auth.js'; -import { AuthApiPath } from '~/packages/auth/auth.js'; -import { type Comment, CommentsApiPath } from '~/packages/comment/comment.js'; -import { UserPayloadKey } from '~/packages/user/user.js'; - -import { buildApp } from '../../libs/packages/app/app.js'; -import { - getCrudHandlers, - KNEX_SELECT_ONE_RECORD -} from '../../libs/packages/database/database.js'; -import { getBearerAuthHeader } from '../../libs/packages/http/http.js'; -import { setupTestComments } from '../../packages/comment/comment.js'; -import { setupTestPosts } from '../../packages/post/post.js'; -import { - setupTestUsers, - TEST_USERS_CREDENTIALS -} from '../../packages/user/user.js'; - -const loginEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.LOGIN -]); - -const commentApiPath = joinPath([config.ENV.APP.API_PATH, ApiPath.COMMENTS]); - -const commentIdEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.COMMENTS, - CommentsApiPath.$ID -]); - -describe(`${commentApiPath} routes`, () => { - const { getApp, getKnex } = buildApp(); - const { select, insert } = getCrudHandlers(getKnex); - - const app = getApp(); - - let tokenMainUser: string; - let tokenMinorUser: string; - - beforeAll(async () => { - await setupTestUsers({ handlers: { insert } }); - await setupTestPosts({ handlers: { select, insert } }); - await setupTestComments({ handlers: { select, insert } }); - - const [validTestMainUser, validTestMinorUser] = TEST_USERS_CREDENTIALS as [ - UserRegisterRequestDto, - UserRegisterRequestDto - ]; - - const loginMainUserResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestMainUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestMainUser[UserPayloadKey.PASSWORD] - }); - - const loginMinorUserResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestMinorUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestMinorUser[UserPayloadKey.PASSWORD] - }); - - tokenMainUser = loginMainUserResponse.json().token; - tokenMinorUser = loginMinorUserResponse.json().token; - }); - - describe(`${commentIdEndpoint} (${HttpMethod.DELETE}) endpoint`, () => { - it(`should return ${HttpCode.FORBIDDEN} with attempt to delete comment by not own user`, async () => { - const commentToDelete = (await select({ - table: DatabaseTableName.COMMENTS, - limit: KNEX_SELECT_ONE_RECORD - })) as Comment; - - const deleteCommentResponse = await app - .inject() - .delete(commentIdEndpoint.replace(':id', commentToDelete.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMinorUser) - }); - - const getCommentResponse = await app - .inject() - .get(commentIdEndpoint.replace(':id', commentToDelete.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMinorUser) - }); - - expect(deleteCommentResponse.statusCode).toBe(HttpCode.FORBIDDEN); - expect(getCommentResponse.json()).toEqual( - expect.objectContaining(commentToDelete) - ); - }); - - it(`should return ${HttpCode.OK} with deleted comment`, async () => { - const commentToDelete = (await select({ - table: DatabaseTableName.COMMENTS, - limit: KNEX_SELECT_ONE_RECORD - })) as Comment; - - const deleteCommentResponse = await app - .inject() - .delete(commentIdEndpoint.replace(':id', commentToDelete.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMainUser) - }); - - const getCommentResponse = await app - .inject() - .get(commentIdEndpoint.replace(':id', commentToDelete.id.toString())) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(tokenMainUser) - }); - - expect(deleteCommentResponse.statusCode).toBe(HttpCode.OK); - expect(getCommentResponse.statusCode).toEqual(HttpCode.NOT_FOUND); - }); - }); -}); diff --git a/server/tests/api/6-like-dislike-comment/comment.api.spec.ts b/server/tests/api/6-like-dislike-comment/comment.api.spec.ts deleted file mode 100644 index 7d309b22..00000000 --- a/server/tests/api/6-like-dislike-comment/comment.api.spec.ts +++ /dev/null @@ -1,322 +0,0 @@ -import { beforeAll, describe, expect, it } from '@jest/globals'; - -import { ApiPath } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { DatabaseTableName } from '~/libs/packages/database/database.js'; -import { HttpCode, HttpHeader, HttpMethod } from '~/libs/packages/http/http.js'; -import { joinPath } from '~/libs/packages/path/path.js'; -import { AuthApiPath } from '~/packages/auth/auth.js'; -import { - type UserLoginResponseDto, - type UserRegisterRequestDto -} from '~/packages/auth/libs/types/types.js'; -import { type Comment } from '~/packages/comment/comment.js'; -import { PostsApiPath } from '~/packages/post/post.js'; -import { UserPayloadKey } from '~/packages/user/user.js'; - -import { buildApp } from '../../libs/packages/app/app.js'; -import { - getCrudHandlers, - KNEX_SELECT_ONE_RECORD -} from '../../libs/packages/database/database.js'; -import { getBearerAuthHeader } from '../../libs/packages/http/http.js'; -import { setupTestComments } from '../../packages/comment/comment.js'; -import { setupTestPosts } from '../../packages/post/post.js'; -import { - setupTestUsers, - TEST_USERS_CREDENTIALS -} from '../../packages/user/user.js'; - -const loginEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.LOGIN -]); - -const commentApiPath = joinPath([config.ENV.APP.API_PATH, ApiPath.COMMENTS]); - -const commentIdEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.COMMENTS, - PostsApiPath.$ID -]); - -const commentReactEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.COMMENTS, - PostsApiPath.REACT -]); - -describe(`${commentApiPath} routes`, () => { - const { getApp, getKnex } = buildApp(); - const { select, insert } = getCrudHandlers(getKnex); - - const app = getApp(); - - let token: string; - - beforeAll(async () => { - await setupTestUsers({ handlers: { insert } }); - await setupTestPosts({ handlers: { select, insert } }); - await setupTestComments({ handlers: { select, insert } }); - - const [validTestUser] = TEST_USERS_CREDENTIALS as [UserRegisterRequestDto]; - - const loginResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestUser[UserPayloadKey.PASSWORD] - }); - - token = loginResponse.json().token; - }); - - describe(`${commentReactEndpoint} (${HttpMethod.PUT}) endpoint`, () => { - it(`should return ${HttpCode.OK} with liked comment`, async () => { - const result = await select({ - table: DatabaseTableName.COMMENTS, - limit: KNEX_SELECT_ONE_RECORD - }); - - const { id: commentId } = (result as Comment) ?? {}; - - const getCommentBeforeLikeResponse = await app - .inject() - .get(commentIdEndpoint.replace(':id', commentId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - const likeCommentResponse = await app - .inject() - .put(commentReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ commentId }); - - expect(likeCommentResponse.statusCode).toBe(HttpCode.OK); - expect(likeCommentResponse.json()).toEqual( - expect.objectContaining({ - likeCount: String( - Number( - getCommentBeforeLikeResponse.json>() - .likeCount - ) + 1 - ), - dislikeCount: - getCommentBeforeLikeResponse.json>() - .dislikeCount - }) - ); - }); - - it(`should return ${HttpCode.OK} with removed user's like comment`, async () => { - const { id: commentId } = (await select({ - table: DatabaseTableName.COMMENTS, - limit: KNEX_SELECT_ONE_RECORD - })) as Comment; - - const getCommentBeforeLikeResponse = await app - .inject() - .get(commentIdEndpoint.replace(':id', commentId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - const likeCommentResponse = await app - .inject() - .put(commentReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ commentId }); - - expect(likeCommentResponse.statusCode).toBe(HttpCode.OK); - expect(likeCommentResponse.json()).toEqual( - expect.objectContaining({ - likeCount: String( - Number( - getCommentBeforeLikeResponse.json>() - .likeCount - ) - 1 - ), - dislikeCount: - getCommentBeforeLikeResponse.json>() - .dislikeCount - }) - ); - }); - - it(`should return ${HttpCode.OK} with disliked comment`, async () => { - const { id: commentId } = (await select({ - table: DatabaseTableName.COMMENTS, - limit: KNEX_SELECT_ONE_RECORD - })) as Comment; - - const getCommentBeforeLikeResponse = await app - .inject() - .get(commentIdEndpoint.replace(':id', commentId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - const dislikeCommentResponse = await app - .inject() - .put(commentReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ commentId, isLike: false }); - - expect(dislikeCommentResponse.statusCode).toBe(HttpCode.OK); - expect(dislikeCommentResponse.json()).toEqual( - expect.objectContaining({ - likeCount: - getCommentBeforeLikeResponse.json>() - .likeCount, - dislikeCount: String( - Number( - getCommentBeforeLikeResponse.json< - Record<'dislikeCount', number> - >().dislikeCount - ) + 1 - ) - }) - ); - }); - - it(`should return ${HttpCode.OK} with removed user's dislike comment`, async () => { - const { id: commentId } = (await select({ - table: DatabaseTableName.COMMENTS, - limit: KNEX_SELECT_ONE_RECORD - })) as Comment; - - const getCommentBeforeLikeResponse = await app - .inject() - .get(commentIdEndpoint.replace(':id', commentId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - const dislikeCommentResponse = await app - .inject() - .put(commentReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ commentId, isLike: false }); - - expect(dislikeCommentResponse.statusCode).toBe(HttpCode.OK); - expect(dislikeCommentResponse.json()).toEqual( - expect.objectContaining({ - likeCount: - getCommentBeforeLikeResponse.json>() - .likeCount, - dislikeCount: String( - Number( - getCommentBeforeLikeResponse.json< - Record<'dislikeCount', number> - >().dislikeCount - ) - 1 - ) - }) - ); - }); - - it(`should return ${HttpCode.OK} with switched like to dislike comment`, async () => { - const { id: commentId } = (await select({ - table: DatabaseTableName.COMMENTS, - limit: KNEX_SELECT_ONE_RECORD - })) as Comment; - - const getCommentBeforeLikeResponse = await app - .inject() - .get(commentIdEndpoint.replace(':id', commentId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - const likeCommentResponse = await app - .inject() - .put(commentReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ commentId, isLike: true }); - const dislikeCommentResponse = await app - .inject() - .put(commentReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ commentId, isLike: false }); - await app - .inject() - .put(commentReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ commentId, isLike: false }); - - expect(likeCommentResponse.statusCode).toBe(HttpCode.OK); - expect(dislikeCommentResponse.statusCode).toBe(HttpCode.OK); - expect(likeCommentResponse.json()).toEqual( - expect.objectContaining({ - likeCount: String( - Number( - getCommentBeforeLikeResponse.json>() - .likeCount - ) + 1 - ), - dislikeCount: - getCommentBeforeLikeResponse.json>() - .dislikeCount - }) - ); - expect(dislikeCommentResponse.json()).toEqual( - expect.objectContaining({ - likeCount: String( - Number( - likeCommentResponse.json>().likeCount - ) - 1 - ), - dislikeCount: String( - Number( - likeCommentResponse.json>() - .dislikeCount - ) + 1 - ) - }) - ); - }); - - it(`should return ${HttpCode.OK} with switched dislike to like comment`, async () => { - const { id: commentId } = (await select({ - table: DatabaseTableName.COMMENTS, - limit: KNEX_SELECT_ONE_RECORD - })) as Comment; - - const getCommentBeforeLikeResponse = await app - .inject() - .get(commentIdEndpoint.replace(':id', commentId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - const dislikeCommentResponse = await app - .inject() - .put(commentReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ commentId, isLike: false }); - const likeCommentResponse = await app - .inject() - .put(commentReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ commentId, isLike: true }); - - expect(likeCommentResponse.statusCode).toBe(HttpCode.OK); - expect(dislikeCommentResponse.statusCode).toBe(HttpCode.OK); - expect(dislikeCommentResponse.json()).toEqual( - expect.objectContaining({ - likeCount: - getCommentBeforeLikeResponse.json>() - .likeCount, - dislikeCount: String( - Number( - getCommentBeforeLikeResponse.json< - Record<'dislikeCount', number> - >().dislikeCount - ) + 1 - ) - }) - ); - expect(likeCommentResponse.json()).toEqual( - expect.objectContaining({ - likeCount: String( - Number( - dislikeCommentResponse.json>() - .likeCount - ) + 1 - ), - dislikeCount: String( - Number( - dislikeCommentResponse.json>() - .dislikeCount - ) - 1 - ) - }) - ); - }); - }); -}); diff --git a/server/tests/api/7-show-hide-own-posts/post.api.spec.ts b/server/tests/api/7-show-hide-own-posts/post.api.spec.ts deleted file mode 100644 index edcff642..00000000 --- a/server/tests/api/7-show-hide-own-posts/post.api.spec.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { beforeAll, describe, expect, it } from '@jest/globals'; - -import { ApiPath } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { HttpCode, HttpHeader, HttpMethod } from '~/libs/packages/http/http.js'; -import { joinPath } from '~/libs/packages/path/path.js'; -import { - AuthApiPath, - type UserLoginResponseDto, - type UserRegisterRequestDto -} from '~/packages/auth/auth.js'; -import { FilterUserMode, PostsApiPath } from '~/packages/post/post.js'; -import { UserPayloadKey } from '~/packages/user/user.js'; - -import { buildApp } from '../../libs/packages/app/app.js'; -import { getCrudHandlers } from '../../libs/packages/database/database.js'; -import { getBearerAuthHeader } from '../../libs/packages/http/http.js'; -import { setupTestPosts, TEST_POSTS } from '../../packages/post/post.js'; -import { - setupTestUsers, - TEST_USERS_CREDENTIALS -} from '../../packages/user/user.js'; - -const loginEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.LOGIN -]); - -const postApiPath = joinPath([config.ENV.APP.API_PATH, ApiPath.POSTS]); - -const postsEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.POSTS, - PostsApiPath.ROOT -]); - -describe(`${postApiPath} routes`, () => { - const { getApp, getKnex } = buildApp(); - const { select, insert } = getCrudHandlers(getKnex); - - const app = getApp(); - - let token: string; - let userId: number; - - beforeAll(async () => { - await setupTestUsers({ handlers: { insert } }); - await setupTestPosts({ handlers: { select, insert } }); - - const [validUser] = TEST_USERS_CREDENTIALS as [UserRegisterRequestDto]; - - const loginResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validUser[UserPayloadKey.PASSWORD] - }); - - token = loginResponse.json().token; - userId = loginResponse.json().user.id; - }); - - describe(`${postsEndpoint} (${HttpMethod.GET}) endpoint`, () => { - it(`should return ${HttpCode.OK} with own posts`, async () => { - const response = await app - .inject() - .get(postsEndpoint) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) - }) - .query({ - from: '0', - count: '1', - userId: userId.toString(), - userMode: FilterUserMode.INCLUDE - }); - - expect(response.statusCode).toBe(HttpCode.OK); - expect(response.json()).toEqual([ - expect.objectContaining({ - userId - }) - ]); - }); - - it(`should return ${HttpCode.OK} with not own posts`, async () => { - const response = await app - .inject() - .get(postsEndpoint) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) - }) - .query({ - from: '0', - count: '1', - userId: userId.toString(), - userMode: FilterUserMode.EXCLUDE - }); - - expect(response.statusCode).toBe(HttpCode.OK); - expect(response.json()).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - userId: expect.not.stringContaining(userId.toString()) - }) - ]) - ); - }); - - it(`should return ${HttpCode.OK} with all users' posts`, async () => { - const response = await app - .inject() - .get(postsEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .query({ - from: '0', - count: TEST_POSTS.length.toString() - }); - - expect(response.statusCode).toBe(HttpCode.OK); - expect(response.json()).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - userId: expect.not.stringContaining(userId.toString()) - }), - expect.objectContaining({ userId }) - ]) - ); - }); - }); -}); diff --git a/server/tests/api/8-show-liked-by-own-posts/post.api.spec.ts b/server/tests/api/8-show-liked-by-own-posts/post.api.spec.ts deleted file mode 100644 index 1e646308..00000000 --- a/server/tests/api/8-show-liked-by-own-posts/post.api.spec.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { beforeAll, describe, expect, it } from '@jest/globals'; - -import { ApiPath } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { DatabaseTableName } from '~/libs/packages/database/database.js'; -import { HttpCode, HttpHeader, HttpMethod } from '~/libs/packages/http/http.js'; -import { joinPath } from '~/libs/packages/path/path.js'; -import { - type UserLoginResponseDto, - type UserRegisterRequestDto -} from '~/packages/auth/auth.js'; -import { AuthApiPath } from '~/packages/auth/auth.js'; -import { - FilterUserMode, - type Post, - PostsApiPath -} from '~/packages/post/post.js'; -import { UserPayloadKey } from '~/packages/user/user.js'; - -import { buildApp } from '../../libs/packages/app/app.js'; -import { - getCrudHandlers, - KNEX_SELECT_ONE_RECORD -} from '../../libs/packages/database/database.js'; -import { getBearerAuthHeader } from '../../libs/packages/http/http.js'; -import { setupTestPosts, TEST_POSTS } from '../../packages/post/post.js'; -import { - setupTestUsers, - TEST_USERS_CREDENTIALS -} from '../../packages/user/user.js'; - -const loginEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.LOGIN -]); - -const postApiPath = joinPath([config.ENV.APP.API_PATH, ApiPath.POSTS]); - -const postsEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.POSTS, - PostsApiPath.ROOT -]); - -const postReactEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.POSTS, - PostsApiPath.REACT -]); - -describe(`${postApiPath} routes`, () => { - const { getApp, getKnex } = buildApp(); - const { select, insert } = getCrudHandlers(getKnex); - - const app = getApp(); - - let token: string; - let userId: number; - - beforeAll(async () => { - await setupTestUsers({ handlers: { insert } }); - await setupTestPosts({ handlers: { select, insert } }); - - const [validUser] = TEST_USERS_CREDENTIALS as [UserRegisterRequestDto]; - - const loginResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validUser[UserPayloadKey.PASSWORD] - }); - - token = loginResponse.json().token; - userId = loginResponse.json().user.id; - }); - - describe(`${postsEndpoint} (${HttpMethod.GET}) endpoint`, () => { - it(`should return ${HttpCode.OK} with liked by own posts`, async () => { - const { id: postId } = (await select({ - table: DatabaseTableName.POSTS, - limit: KNEX_SELECT_ONE_RECORD - })) as Post; - - await app - .inject() - .put(postReactEndpoint) - .headers({ - [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) - }) - .body({ postId }); - - const response = await app - .inject() - .get(postsEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .query({ - from: '0', - count: '1', - userId: userId.toString(), - userMode: FilterUserMode.LIKED_BY_OWN - }); - - expect(response.statusCode).toBe(HttpCode.OK); - expect(response.json()).toEqual( - expect.arrayContaining([expect.objectContaining({ id: postId })]) - ); - }); - - it(`should return ${HttpCode.OK} with all users' posts`, async () => { - const response = await app - .inject() - .get(postsEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .query({ - from: '0', - count: TEST_POSTS.length.toString() - }); - - expect(response.statusCode).toBe(HttpCode.OK); - expect(response.json()).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - userId: expect.not.stringContaining(userId.toString()) - }), - expect.objectContaining({ userId }) - ]) - ); - }); - }); -}); diff --git a/server/tests/api/9-show-who-liked-post/post.api.spec.ts b/server/tests/api/9-show-who-liked-post/post.api.spec.ts deleted file mode 100644 index 8564177c..00000000 --- a/server/tests/api/9-show-who-liked-post/post.api.spec.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { beforeAll, describe, expect, it } from '@jest/globals'; - -import { ApiPath } from '~/libs/enums/enums.js'; -import { config } from '~/libs/packages/config/config.js'; -import { DatabaseTableName } from '~/libs/packages/database/database.js'; -import { HttpCode, HttpHeader, HttpMethod } from '~/libs/packages/http/http.js'; -import { joinPath } from '~/libs/packages/path/path.js'; -import { - AuthApiPath, - type UserLoginResponseDto, - type UserRegisterRequestDto -} from '~/packages/auth/auth.js'; -import { type Post, PostsApiPath } from '~/packages/post/post.js'; -import { UserPayloadKey } from '~/packages/user/user.js'; - -import { buildApp } from '../../libs/packages/app/app.js'; -import { getCrudHandlers } from '../../libs/packages/database/database.js'; -import { getBearerAuthHeader } from '../../libs/packages/http/http.js'; -import { setupTestPosts } from '../../packages/post/post.js'; -import { - setupTestUsers, - TEST_USERS_CREDENTIALS -} from '../../packages/user/user.js'; - -const loginEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.AUTH, - AuthApiPath.LOGIN -]); - -const postApiPath = joinPath([config.ENV.APP.API_PATH, ApiPath.POSTS]); - -const postIdEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.POSTS, - PostsApiPath.$ID -]); - -const postReactEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.POSTS, - PostsApiPath.REACT -]); - -const postsEndpoint = joinPath([ - config.ENV.APP.API_PATH, - ApiPath.POSTS, - PostsApiPath.ROOT -]); - -describe(`${postApiPath} routes`, () => { - const { getApp, getKnex } = buildApp(); - const { select, insert } = getCrudHandlers(getKnex); - - const app = getApp(); - - let token: string; - let userId: number; - - beforeAll(async () => { - await setupTestUsers({ handlers: { insert } }); - await setupTestPosts({ handlers: { select, insert } }); - - const [validTestUser] = TEST_USERS_CREDENTIALS as [UserRegisterRequestDto]; - - const loginUserResponse = await app - .inject() - .post(loginEndpoint) - .body({ - [UserPayloadKey.EMAIL]: validTestUser[UserPayloadKey.EMAIL], - [UserPayloadKey.PASSWORD]: validTestUser[UserPayloadKey.PASSWORD] - }); - - token = loginUserResponse.json().token; - userId = loginUserResponse.json().user.id; - - const [{ id: firstPostId }, { id: secondPostId }] = (await select({ - table: DatabaseTableName.POSTS - })) as [Post, Post]; - - await app - .inject() - .put(postReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ postId: firstPostId }); - await app - .inject() - .put(postReactEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }) - .body({ postId: secondPostId, isLike: false }); - }); - - describe(`${postsEndpoint} (${HttpMethod.GET}) endpoint`, () => { - it(`should return ${HttpCode.OK} with likes and dislikes of posts`, async () => { - const [{ id: firstPostId }, { id: secondPostId }] = (await select({ - table: DatabaseTableName.POSTS - })) as [Post, Post]; - - const response = await app - .inject() - .get(postsEndpoint) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - - expect(response.statusCode).toBe(HttpCode.OK); - expect(response.json()).toEqual([ - expect.objectContaining({ - id: firstPostId, - likes: [], - dislikes: expect.arrayContaining([ - expect.objectContaining({ userId }) - ]) - }), - expect.objectContaining({ - id: secondPostId, - likes: expect.arrayContaining([expect.objectContaining({ userId })]), - dislikes: [] - }) - ]); - }); - }); - - describe(`${postIdEndpoint} (${HttpMethod.GET}) endpoint`, () => { - it(`should return ${HttpCode.OK} with likes and dislikes of post`, async () => { - const [{ id: firstPostId }, { id: secondPostId }] = (await select({ - table: DatabaseTableName.POSTS - })) as [Post, Post]; - - const firstPostResponse = await app - .inject() - .get(postIdEndpoint.replace(':id', firstPostId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - - const secondPostResponse = await app - .inject() - .get(postIdEndpoint.replace(':id', secondPostId.toString())) - .headers({ [HttpHeader.AUTHORIZATION]: getBearerAuthHeader(token) }); - - expect(firstPostResponse.statusCode).toBe(HttpCode.OK); - expect(firstPostResponse.json()).toEqual( - expect.objectContaining({ - id: firstPostId, - likes: expect.arrayContaining([expect.objectContaining({ userId })]), - dislikes: [] - }) - ); - - expect(secondPostResponse.statusCode).toBe(HttpCode.OK); - expect(secondPostResponse.json()).toEqual( - expect.objectContaining({ - id: secondPostId, - likes: [], - dislikes: expect.arrayContaining([ - expect.objectContaining({ userId }) - ]) - }) - ); - }); - }); -}); diff --git a/server/tests/data/images/test-image.png b/server/tests/data/images/test-image.png deleted file mode 100644 index 4ae1a36e6462e697e55403f81d164770d7166033..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35204 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 P00000NkvXXu0mjf3o#+x diff --git a/server/tests/libs/packages/http/http.ts b/server/tests/libs/packages/http/http.ts deleted file mode 100644 index 9540f552..00000000 --- a/server/tests/libs/packages/http/http.ts +++ /dev/null @@ -1 +0,0 @@ -export { getBearerAuthHeader } from './libs/helpers/helpers.js'; diff --git a/server/tests/libs/packages/http/libs/helpers/get-bearer-auth-header/get-bearer-auth-header.helper.ts b/server/tests/libs/packages/http/libs/helpers/get-bearer-auth-header/get-bearer-auth-header.helper.ts deleted file mode 100644 index 649a9010..00000000 --- a/server/tests/libs/packages/http/libs/helpers/get-bearer-auth-header/get-bearer-auth-header.helper.ts +++ /dev/null @@ -1,5 +0,0 @@ -const getBearerAuthHeader = (accessToken: string): string => { - return `Bearer ${accessToken}`; -}; - -export { getBearerAuthHeader }; diff --git a/server/tests/libs/packages/http/libs/helpers/helpers.ts b/server/tests/libs/packages/http/libs/helpers/helpers.ts deleted file mode 100644 index 35fc3770..00000000 --- a/server/tests/libs/packages/http/libs/helpers/helpers.ts +++ /dev/null @@ -1 +0,0 @@ -export { getBearerAuthHeader } from './get-bearer-auth-header/get-bearer-auth-header.helper.js'; diff --git a/server/tests/packages/comment/comment.ts b/server/tests/packages/comment/comment.ts deleted file mode 100644 index c0421f67..00000000 --- a/server/tests/packages/comment/comment.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { setupTestComments } from './helpers/helpers.js'; -export { TEST_COMMENTS } from './libs/constants/constants.js'; diff --git a/server/tests/packages/comment/helpers/helpers.ts b/server/tests/packages/comment/helpers/helpers.ts deleted file mode 100644 index 1b6debd3..00000000 --- a/server/tests/packages/comment/helpers/helpers.ts +++ /dev/null @@ -1 +0,0 @@ -export { setupTestComments } from './setup-test-comments/setup-test-comments.helper.js'; diff --git a/server/tests/packages/comment/helpers/setup-test-comments/setup-test-comments.helper.ts b/server/tests/packages/comment/helpers/setup-test-comments/setup-test-comments.helper.ts deleted file mode 100644 index 95e06439..00000000 --- a/server/tests/packages/comment/helpers/setup-test-comments/setup-test-comments.helper.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { DatabaseTableName } from '~/libs/packages/database/database.js'; -import { type Post } from '~/packages/post/post.js'; -import { type User } from '~/packages/user/user.js'; - -import { type GetCrudHandlersFunction } from '../../../../libs/packages/database/libs/types/types.js'; -import { TEST_COMMENTS } from '../../libs/constants/constants.js'; - -const getRandomIndex = (length: number): number => { - return Math.floor(Math.random() * length); -}; - -const setupTestComments = async ({ - handlers: { select, insert } -}: Record< - 'handlers', - Pick, 'select' | 'insert'> ->): Promise => { - const testUsers = (await select({ - table: DatabaseTableName.USERS - })) as User[]; - - const testPosts = (await select({ - table: DatabaseTableName.POSTS - })) as Post[]; - - const commentsToInsert = TEST_COMMENTS.map(comment => ({ - ...comment, - userId: (testUsers[getRandomIndex(testUsers.length)] as User).id, - postId: (testPosts[getRandomIndex(testPosts.length)] as Post).id - })); - - await insert({ - table: DatabaseTableName.COMMENTS, - data: commentsToInsert - }); -}; - -export { setupTestComments }; diff --git a/server/tests/packages/comment/libs/constants/constants.ts b/server/tests/packages/comment/libs/constants/constants.ts deleted file mode 100644 index e9e75e9c..00000000 --- a/server/tests/packages/comment/libs/constants/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export { TEST_COMMENTS } from './test-comments.constant.js'; diff --git a/server/tests/packages/comment/libs/constants/test-comments.constant.ts b/server/tests/packages/comment/libs/constants/test-comments.constant.ts deleted file mode 100644 index 2daba176..00000000 --- a/server/tests/packages/comment/libs/constants/test-comments.constant.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { faker } from '@faker-js/faker'; - -import { CommentPayloadKey } from '~/packages/comment/comment.js'; - -const COMMENTS_COUNT = 5; - -const TEST_COMMENTS = Array.from({ length: COMMENTS_COUNT }, () => ({ - [CommentPayloadKey.BODY]: faker.lorem.paragraph() -})); - -export { TEST_COMMENTS }; diff --git a/server/tests/packages/post/helpers/helpers.ts b/server/tests/packages/post/helpers/helpers.ts deleted file mode 100644 index da6c7e30..00000000 --- a/server/tests/packages/post/helpers/helpers.ts +++ /dev/null @@ -1 +0,0 @@ -export { setupTestPosts } from './setup-test-posts/setup-test-posts.helper.js'; diff --git a/server/tests/packages/post/helpers/setup-test-posts/setup-test-posts.helper.ts b/server/tests/packages/post/helpers/setup-test-posts/setup-test-posts.helper.ts deleted file mode 100644 index 53baa23d..00000000 --- a/server/tests/packages/post/helpers/setup-test-posts/setup-test-posts.helper.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { DatabaseTableName } from '~/libs/packages/database/database.js'; -import { type User } from '~/packages/user/user.js'; - -import { type GetCrudHandlersFunction } from '../../../../libs/packages/database/libs/types/types.js'; -import { TEST_POSTS } from '../../libs/constants/constants.js'; - -const getRandomIndex = (length: number): number => { - return Math.floor(Math.random() * length); -}; - -const setupTestPosts = async ({ - handlers: { select, insert } -}: Record< - 'handlers', - Pick, 'select' | 'insert'> ->): Promise => { - const testUsers = (await select({ - table: DatabaseTableName.USERS - })) as User[]; - - const postsToInsert = TEST_POSTS.map(post => ({ - ...post, - userId: (testUsers[getRandomIndex(testUsers.length)] as User).id - })); - - await insert({ - table: DatabaseTableName.POSTS, - data: postsToInsert - }); -}; - -export { setupTestPosts }; diff --git a/server/tests/packages/post/libs/constants/constants.ts b/server/tests/packages/post/libs/constants/constants.ts deleted file mode 100644 index 69b372f0..00000000 --- a/server/tests/packages/post/libs/constants/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export { TEST_POSTS } from './test-posts.constant.js'; diff --git a/server/tests/packages/post/libs/constants/test-posts.constant.ts b/server/tests/packages/post/libs/constants/test-posts.constant.ts deleted file mode 100644 index 149263ed..00000000 --- a/server/tests/packages/post/libs/constants/test-posts.constant.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { faker } from '@faker-js/faker'; - -import { - type CreatePostRequestDto, - PostPayloadKey -} from '~/packages/post/post.js'; - -const POSTS_COUNT = 5; - -const TEST_POSTS = Array.from( - { length: POSTS_COUNT }, - (): Omit => ({ - [PostPayloadKey.BODY]: faker.lorem.paragraph() - }) -); - -export { TEST_POSTS }; diff --git a/server/tests/packages/post/post.ts b/server/tests/packages/post/post.ts deleted file mode 100644 index 88fddff5..00000000 --- a/server/tests/packages/post/post.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { setupTestPosts } from './helpers/helpers.js'; -export { TEST_POSTS } from './libs/constants/constants.js'; From 4e8985b2959529ceb9657cfd00c3a099fdab5ac6 Mon Sep 17 00:00:00 2001 From: Volodymyr Minchenko Date: Mon, 10 Jun 2024 00:47:07 +0300 Subject: [PATCH 03/28] thjs-122: * prepare packages/frontend workspace --- apps/backend/package.json | 4 +- .../src/packages/auth/auth.controller.ts | 17 +- .../backend/src/packages/auth/auth.service.ts | 8 +- apps/backend/src/packages/auth/auth.ts | 4 +- .../auth/libs/types/auth-controller.type.ts | 8 +- .../auth/libs/types/auth-service.type.ts | 6 +- .../src/packages/auth/libs/types/types.ts | 4 +- .../validation-schemas/validation-schemas.ts | 2 +- .../tests/modules/auth/auth.api.spec.ts | 16 +- .../test-user-credentials.constant.ts | 4 +- apps/frontend/.env.example | 8 + {client => apps/frontend}/.eslintrc.yml | 0 {client => apps/frontend}/.stylelintrc.yml | 0 {client => apps/frontend}/index.html | 0 {client => apps/frontend}/package.json | 7 +- {client => apps/frontend}/public/favicon.ico | Bin .../frontend}/public/manifest.json | 0 .../frontend/src/assets/css/scaffolding.css | 0 apps/frontend/src/assets/css/styles.css | 2 + .../frontend/src/assets/css/variables.css | 0 {client => apps/frontend}/src/index.tsx | 7 +- .../src/libs/components/button/button.tsx | 20 +- .../libs/components/button/styles.module.scss | 0 .../src/libs/components/components.ts | 5 + .../src/libs/components/image/image.tsx | 0 .../libs/components/image/styles.module.scss | 0 .../src/libs/components/input/input.tsx | 15 +- .../libs/components/input/styles.module.scss | 10 - .../router-provider/router-provider.tsx | 15 ++ .../src/libs/enums/app/app-route.enum.ts | 8 + .../frontend}/src/libs/enums/app/app.ts | 1 + .../src/libs/enums/app/data-status.enum.ts | 8 + .../src/libs/enums/app/environment.enum.ts | 7 + .../src/libs/enums/app/storage-key.enum.ts | 0 .../enums/components/button-color.enum.ts | 0 .../libs/enums/components/button-size.enum.ts | 0 .../src/libs/enums/components/components.ts | 3 - .../libs/enums/components/image-size.enum.ts | 0 apps/frontend/src/libs/enums/enums.ts | 5 + .../src/libs/enums/exception/exception.ts | 1 + .../src/libs/enums/file/content-type.enum.ts | 0 .../frontend}/src/libs/enums/file/file.ts | 0 .../frontend}/src/libs/hooks/hooks.ts | 0 .../use-app-dispatch/use-app-dispatch.hook.ts | 4 +- .../hooks/use-app-form/use-app-form.hook.ts | 0 .../use-app-selector/use-app-selector.hook.ts | 8 + .../libs/packages/config/config.package.ts | 4 +- .../src/libs/packages/config/config.ts | 2 +- .../config/libs/types/config-package.type.ts | 7 + .../libs/types/environment-schema.type.ts | 0 .../libs/packages/config/libs/types/types.ts | 2 +- .../packages/notification/libs/enums/enums.ts | 1 - .../libs/enums/notification-message.enum.ts | 0 .../libs/enums/notification-type.enum.ts | 0 .../libs/types/notification-api.type.ts | 0 .../libs/types/notification-payload.type.ts | 0 .../packages/notification/libs/types/types.ts | 0 .../packages/notification/notification-api.ts | 0 .../packages/notification/notification.ts | 0 .../store/libs/types/store-package.type.ts | 33 ++++ .../libs/packages/store/libs/types/types.ts | 0 .../src/libs/packages/store/store.package.ts | 46 +++++ .../src/libs/packages/store/store.ts | 0 .../types/components}/button-type.type.ts | 0 .../src/libs/types/components/components.ts | 1 + .../src/libs/types/store/app-dispatch.type.ts | 0 .../types/store/async-thunk-config.type.ts | 0 .../frontend}/src/libs/types/store/store.ts | 0 apps/frontend/src/libs/types/types.ts | 9 + apps/frontend/src/modules/auth/auth-api.ts | 40 ++++ .../frontend/src/modules}/auth/auth.ts | 13 +- .../src/modules/auth/libs/enums/enums.ts | 1 + .../modules/auth/libs/types/auth-api.type.ts | 10 + .../src/modules/auth/libs/types/types.ts | 5 + .../validation-schemas/validation-schemas.ts | 1 + .../src/modules/auth/slices/actions.ts | 21 ++ .../src/modules/auth/slices/auth.slice.ts | 39 ++++ apps/frontend/src/modules/auth/slices/auth.ts | 10 + .../src/modules/auth/slices}/common.ts | 2 +- .../frontend/src/modules}/http/http-api.ts | 64 +++--- .../frontend/src/modules}/http/http.ts | 3 +- .../src/modules/http/libs/enums/enums.ts | 2 + .../http/libs/enums/http-header.enum.ts | 0 .../http/libs/exceptions/exceptions.ts | 1 + .../libs/exceptions/http-error.exception.ts | 42 ++++ .../get-stringified-query.helper.ts | 0 .../src/modules/http/libs/helpers/helpers.ts | 0 .../modules}/http/libs/types/http-api.type.ts | 0 .../http/libs/types/http-options.type.ts | 4 +- .../src/modules}/http/libs/types/types.ts | 0 .../storage/libs/types/storage-api.type.ts | 0 .../src/modules}/storage/libs/types/types.ts | 0 .../src/modules}/storage/storage-api.ts | 0 .../frontend/src/modules}/storage/storage.ts | 0 .../src/modules}/user/constants/constants.ts | 0 .../modules}/user/constants/user.constants.ts | 0 apps/frontend/src/modules/user/enums/enums.ts | 1 + .../frontend/src/modules}/user/user.ts | 1 - apps/frontend/src/pages/app/app.tsx | 33 ++++ .../frontend/src/pages/auth/auth.tsx | 33 ++-- .../src/pages/auth/components/components.ts | 2 + .../sign-in-form/libs/common/constants.ts | 8 + .../components/sign-in-form/sign-in-form.tsx | 50 +++++ .../sign-in-form}/styles.module.scss | 0 .../sign-up-form}/libs/common/constants.ts | 2 +- .../components/sign-up-form/sign-up-form.tsx | 82 ++++++++ .../sign-up-form}/styles.module.scss | 0 .../src/pages/auth}/styles.module.scss | 0 .../frontend}/src/vite-environment.d.ts | 0 {client => apps/frontend}/tsconfig.json | 2 +- {client => apps/frontend}/vite.config.ts | 19 +- client/.env.example | 10 - client/src/assets/css/mixins.scss | 4 - client/src/assets/css/styles.scss | 2 - .../src/libs/components/checkbox/checkbox.tsx | 41 ---- .../components/checkbox/styles.module.scss | 49 ----- client/src/libs/components/components.ts | 17 -- .../copy-buffer-input/copy-buffer-input.tsx | 38 ---- .../copy-buffer-input/styles.module.scss | 48 ----- client/src/libs/components/header/header.tsx | 51 ----- .../libs/components/header/styles.module.scss | 30 --- .../components/icon-button/icon-button.tsx | 24 --- .../components/icon-button/styles.module.scss | 16 -- client/src/libs/components/icon/common.ts | 35 ---- client/src/libs/components/icon/icon.tsx | 34 ---- .../src/libs/components/message/message.tsx | 13 -- .../components/message/styles.module.scss | 13 -- .../src/libs/components/modal/hooks/hooks.ts | 1 - .../modal/hooks/use-modal/use-modal.hook.ts | 30 --- client/src/libs/components/modal/modal.tsx | 51 ----- .../libs/components/modal/styles.module.scss | 52 ----- .../notifications/notifications.tsx | 32 --- client/src/libs/components/portal/portal.tsx | 39 ---- .../libs/components/portal/styles.module.scss | 12 -- client/src/libs/components/post/post.tsx | 80 -------- .../libs/components/post/styles.module.scss | 32 --- .../private-route/private-route.tsx | 32 --- .../components/public-route/public-route.tsx | 31 --- .../src/libs/components/segment/segment.tsx | 13 -- .../components/segment/styles.module.scss | 19 -- .../src/libs/components/spinner/spinner.tsx | 16 -- .../components/spinner/styles.module.scss | 35 ---- client/src/libs/enums/app/app-route.enum.ts | 10 - client/src/libs/enums/app/environment.enum.ts | 8 - .../libs/enums/components/icon-color.enum.ts | 5 - .../libs/enums/components/icon-name.enum.ts | 17 -- .../libs/enums/components/icon-size.enum.ts | 7 - client/src/libs/enums/enums.ts | 14 -- client/src/libs/enums/exception/exception.ts | 1 - .../enums/thread/post-filter-action.enum.ts | 5 - .../enums/thread/thread-toolbar-key.enum.ts | 5 - client/src/libs/enums/thread/thread.ts | 2 - client/src/libs/helpers/helpers.ts | 2 - .../use-app-selector/use-app-selector.hook.ts | 9 - .../config/libs/types/config-package.type.ts | 7 - .../store/libs/types/store-package.type.ts | 43 ---- .../packages/store/middlewares/middlewares.ts | 1 - .../notification-socket.middleware.ts | 61 ------ .../src/libs/packages/store/store.package.ts | 58 ------ client/src/libs/types/location.type.ts | 8 - client/src/libs/types/types.ts | 8 - client/src/packages/auth/auth-api.ts | 66 ------- client/src/packages/auth/libs/enums/enums.ts | 1 - .../packages/auth/libs/types/auth-api.type.ts | 19 -- client/src/packages/auth/libs/types/types.ts | 8 - .../validation-schemas/validation-schemas.ts | 1 - client/src/packages/comment/comment-api.ts | 46 ----- client/src/packages/comment/comment.ts | 17 -- .../src/packages/comment/libs/enums/enums.ts | 4 - .../comment/libs/types/comment-api.type.ts | 13 -- .../src/packages/comment/libs/types/types.ts | 7 - client/src/packages/http/libs/enums/enums.ts | 2 - .../http/libs/exceptions/exceptions.ts | 1 - client/src/packages/image/image-api.ts | 38 ---- client/src/packages/image/image.ts | 12 -- client/src/packages/image/libs/enums/enums.ts | 4 - .../image/libs/types/image-api.type.ts | 7 - client/src/packages/image/libs/types/types.ts | 5 - client/src/packages/post/libs/enums/enums.ts | 4 - .../packages/post/libs/types/post-api.type.ts | 22 --- client/src/packages/post/libs/types/types.ts | 12 -- client/src/packages/post/post-api.ts | 67 ------- client/src/packages/post/post.ts | 24 --- .../src/packages/socket/libs/enums/enums.ts | 4 - .../socket/libs/types/socket-api.type.ts | 7 - .../src/packages/socket/libs/types/types.ts | 1 - client/src/packages/socket/socket-api.ts | 13 -- client/src/packages/socket/socket.ts | 6 - client/src/packages/user/enums/enums.ts | 1 - client/src/packages/user/types/types.ts | 1 - client/src/pages/app/app.tsx | 88 --------- client/src/pages/not-found/not-found.tsx | 18 -- client/src/pages/not-found/styles.module.scss | 10 - client/src/pages/profile/profile.tsx | 50 ----- client/src/pages/profile/styles.module.scss | 14 -- client/src/pages/shared-post/shared-post.tsx | 26 --- .../src/pages/sign/components/components.ts | 2 - .../login-form/libs/common/constants.ts | 8 - .../sign/components/login-form/login-form.tsx | 89 --------- .../registration-form/registration-form.tsx | 97 --------- .../components/add-comment/add-comment.tsx | 45 ----- .../add-comment/libs/constants/constants.ts | 7 - .../components/add-comment/styles.module.scss | 3 - .../thread/components/add-post/add-post.tsx | 116 ----------- .../add-post/libs/constants/constants.ts | 7 - .../components/add-post/styles.module.scss | 18 -- .../thread/components/comment/comment.tsx | 32 --- .../components/comment/styles.module.scss | 24 --- .../src/pages/thread/components/components.ts | 5 - .../expanded-post/expanded-post.tsx | 74 ------- .../get-sorted-comments.helper.ts | 10 - .../expanded-post/libs/helpers/helpers.ts | 1 - .../shared-post-link/shared-post-link.tsx | 50 ----- .../shared-post-link/styles.module.scss | 5 - .../src/pages/thread/libs/common/constants.ts | 9 - .../use-posts-filter/use-posts-filter.ts | 42 ---- client/src/pages/thread/styles.module.scss | 16 -- client/src/pages/thread/thread.tsx | 165 ---------------- client/src/slices/app/actions.ts | 20 -- client/src/slices/app/app.ts | 7 - client/src/slices/notifications/actions.ts | 23 --- client/src/slices/notifications/common.ts | 6 - .../src/slices/notifications/notifications.ts | 8 - client/src/slices/profile/actions.ts | 73 ------- client/src/slices/profile/common.ts | 7 - client/src/slices/profile/profile.slice.ts | 46 ----- client/src/slices/profile/profile.ts | 13 -- client/src/slices/thread/actions.ts | 184 ------------------ client/src/slices/thread/common.ts | 10 - client/src/slices/thread/thread.slice.ts | 83 -------- client/src/slices/thread/thread.ts | 24 --- packages/shared/package.json | 2 +- packages/shared/src/index.ts | 8 +- .../src/libs/enums/exception-name.enum.ts | 2 +- .../shared/src/libs/exceptions/exceptions.ts | 2 +- .../http-error/http-error.exception.ts | 8 +- packages/shared/src/modules/auth/auth.ts | 2 +- .../auth/libs/enums/auth-api-path.enum.ts | 2 +- ...schema.ts => sign-up.validation-schema.ts} | 4 +- .../validation-schemas/validation-schemas.ts | 2 +- .../src/modules/user/libs/types/types.ts | 4 +- .../types/user-register-request-dto.type.ts | 4 +- .../types/user-register-response-dto.type.ts | 4 +- packages/shared/src/modules/user/user.ts | 4 +- 244 files changed, 654 insertions(+), 3316 deletions(-) create mode 100644 apps/frontend/.env.example rename {client => apps/frontend}/.eslintrc.yml (100%) rename {client => apps/frontend}/.stylelintrc.yml (100%) rename {client => apps/frontend}/index.html (100%) rename {client => apps/frontend}/package.json (92%) rename {client => apps/frontend}/public/favicon.ico (100%) rename {client => apps/frontend}/public/manifest.json (100%) rename client/src/assets/css/common.scss => apps/frontend/src/assets/css/scaffolding.css (100%) create mode 100644 apps/frontend/src/assets/css/styles.css rename client/src/assets/css/variables.scss => apps/frontend/src/assets/css/variables.css (100%) rename {client => apps/frontend}/src/index.tsx (73%) rename {client => apps/frontend}/src/libs/components/button/button.tsx (70%) rename {client => apps/frontend}/src/libs/components/button/styles.module.scss (100%) create mode 100644 apps/frontend/src/libs/components/components.ts rename {client => apps/frontend}/src/libs/components/image/image.tsx (100%) rename {client => apps/frontend}/src/libs/components/image/styles.module.scss (100%) rename {client => apps/frontend}/src/libs/components/input/input.tsx (78%) rename {client => apps/frontend}/src/libs/components/input/styles.module.scss (86%) create mode 100644 apps/frontend/src/libs/components/router-provider/router-provider.tsx create mode 100644 apps/frontend/src/libs/enums/app/app-route.enum.ts rename {client => apps/frontend}/src/libs/enums/app/app.ts (73%) create mode 100644 apps/frontend/src/libs/enums/app/data-status.enum.ts create mode 100644 apps/frontend/src/libs/enums/app/environment.enum.ts rename {client => apps/frontend}/src/libs/enums/app/storage-key.enum.ts (100%) rename {client => apps/frontend}/src/libs/enums/components/button-color.enum.ts (100%) rename {client => apps/frontend}/src/libs/enums/components/button-size.enum.ts (100%) rename {client => apps/frontend}/src/libs/enums/components/components.ts (51%) rename {client => apps/frontend}/src/libs/enums/components/image-size.enum.ts (100%) create mode 100644 apps/frontend/src/libs/enums/enums.ts create mode 100644 apps/frontend/src/libs/enums/exception/exception.ts rename {client => apps/frontend}/src/libs/enums/file/content-type.enum.ts (100%) rename {client => apps/frontend}/src/libs/enums/file/file.ts (100%) rename {client => apps/frontend}/src/libs/hooks/hooks.ts (100%) rename {client => apps/frontend}/src/libs/hooks/use-app-dispatch/use-app-dispatch.hook.ts (51%) rename {client => apps/frontend}/src/libs/hooks/use-app-form/use-app-form.hook.ts (100%) create mode 100644 apps/frontend/src/libs/hooks/use-app-selector/use-app-selector.hook.ts rename {client => apps/frontend}/src/libs/packages/config/config.package.ts (93%) rename {client => apps/frontend}/src/libs/packages/config/config.ts (88%) create mode 100644 apps/frontend/src/libs/packages/config/libs/types/config-package.type.ts rename {client => apps/frontend}/src/libs/packages/config/libs/types/environment-schema.type.ts (100%) rename {client => apps/frontend}/src/libs/packages/config/libs/types/types.ts (52%) rename {client => apps/frontend}/src/libs/packages/notification/libs/enums/enums.ts (60%) rename {client => apps/frontend}/src/libs/packages/notification/libs/enums/notification-message.enum.ts (100%) rename {client => apps/frontend}/src/libs/packages/notification/libs/enums/notification-type.enum.ts (100%) rename {client => apps/frontend}/src/libs/packages/notification/libs/types/notification-api.type.ts (100%) rename {client => apps/frontend}/src/libs/packages/notification/libs/types/notification-payload.type.ts (100%) rename {client => apps/frontend}/src/libs/packages/notification/libs/types/types.ts (100%) rename {client => apps/frontend}/src/libs/packages/notification/notification-api.ts (100%) rename {client => apps/frontend}/src/libs/packages/notification/notification.ts (100%) create mode 100644 apps/frontend/src/libs/packages/store/libs/types/store-package.type.ts rename {client => apps/frontend}/src/libs/packages/store/libs/types/types.ts (100%) create mode 100644 apps/frontend/src/libs/packages/store/store.package.ts rename {client => apps/frontend}/src/libs/packages/store/store.ts (100%) rename {client/src/libs/types => apps/frontend/src/libs/types/components}/button-type.type.ts (100%) create mode 100644 apps/frontend/src/libs/types/components/components.ts rename {client => apps/frontend}/src/libs/types/store/app-dispatch.type.ts (100%) rename {client => apps/frontend}/src/libs/types/store/async-thunk-config.type.ts (100%) rename {client => apps/frontend}/src/libs/types/store/store.ts (100%) create mode 100644 apps/frontend/src/libs/types/types.ts create mode 100644 apps/frontend/src/modules/auth/auth-api.ts rename {client/src/packages => apps/frontend/src/modules}/auth/auth.ts (55%) create mode 100644 apps/frontend/src/modules/auth/libs/enums/enums.ts create mode 100644 apps/frontend/src/modules/auth/libs/types/auth-api.type.ts create mode 100644 apps/frontend/src/modules/auth/libs/types/types.ts create mode 100644 apps/frontend/src/modules/auth/libs/validation-schemas/validation-schemas.ts create mode 100644 apps/frontend/src/modules/auth/slices/actions.ts create mode 100644 apps/frontend/src/modules/auth/slices/auth.slice.ts create mode 100644 apps/frontend/src/modules/auth/slices/auth.ts rename {client/src/slices/app => apps/frontend/src/modules/auth/slices}/common.ts (68%) rename {client/src/packages => apps/frontend/src/modules}/http/http-api.ts (52%) rename {client/src/packages => apps/frontend/src/modules}/http/http.ts (61%) create mode 100644 apps/frontend/src/modules/http/libs/enums/enums.ts rename {client/src/packages => apps/frontend/src/modules}/http/libs/enums/http-header.enum.ts (100%) create mode 100644 apps/frontend/src/modules/http/libs/exceptions/exceptions.ts create mode 100644 apps/frontend/src/modules/http/libs/exceptions/http-error.exception.ts rename {client/src/libs/helpers/http => apps/frontend/src/modules/http/libs/helpers}/get-stringified-query/get-stringified-query.helper.ts (100%) rename client/src/libs/helpers/http/http.ts => apps/frontend/src/modules/http/libs/helpers/helpers.ts (100%) rename {client/src/packages => apps/frontend/src/modules}/http/libs/types/http-api.type.ts (100%) rename {client/src/packages => apps/frontend/src/modules}/http/libs/types/http-options.type.ts (78%) rename {client/src/packages => apps/frontend/src/modules}/http/libs/types/types.ts (100%) rename {client/src/packages => apps/frontend/src/modules}/storage/libs/types/storage-api.type.ts (100%) rename {client/src/packages => apps/frontend/src/modules}/storage/libs/types/types.ts (100%) rename {client/src/packages => apps/frontend/src/modules}/storage/storage-api.ts (100%) rename {client/src/packages => apps/frontend/src/modules}/storage/storage.ts (100%) rename {client/src/packages => apps/frontend/src/modules}/user/constants/constants.ts (100%) rename {client/src/packages => apps/frontend/src/modules}/user/constants/user.constants.ts (100%) create mode 100644 apps/frontend/src/modules/user/enums/enums.ts rename {client/src/packages => apps/frontend/src/modules}/user/user.ts (64%) create mode 100644 apps/frontend/src/pages/app/app.tsx rename client/src/pages/sign/sign.tsx => apps/frontend/src/pages/auth/auth.tsx (53%) create mode 100644 apps/frontend/src/pages/auth/components/components.ts create mode 100644 apps/frontend/src/pages/auth/components/sign-in-form/libs/common/constants.ts create mode 100644 apps/frontend/src/pages/auth/components/sign-in-form/sign-in-form.tsx rename {client/src/pages/sign/components/login-form => apps/frontend/src/pages/auth/components/sign-in-form}/styles.module.scss (100%) rename {client/src/pages/sign/components/registration-form => apps/frontend/src/pages/auth/components/sign-up-form}/libs/common/constants.ts (73%) create mode 100644 apps/frontend/src/pages/auth/components/sign-up-form/sign-up-form.tsx rename {client/src/pages/sign/components/registration-form => apps/frontend/src/pages/auth/components/sign-up-form}/styles.module.scss (100%) rename {client/src/pages/sign => apps/frontend/src/pages/auth}/styles.module.scss (100%) rename {client => apps/frontend}/src/vite-environment.d.ts (100%) rename {client => apps/frontend}/tsconfig.json (92%) rename {client => apps/frontend}/vite.config.ts (54%) delete mode 100644 client/.env.example delete mode 100644 client/src/assets/css/mixins.scss delete mode 100644 client/src/assets/css/styles.scss delete mode 100644 client/src/libs/components/checkbox/checkbox.tsx delete mode 100644 client/src/libs/components/checkbox/styles.module.scss delete mode 100644 client/src/libs/components/components.ts delete mode 100644 client/src/libs/components/copy-buffer-input/copy-buffer-input.tsx delete mode 100644 client/src/libs/components/copy-buffer-input/styles.module.scss delete mode 100644 client/src/libs/components/header/header.tsx delete mode 100644 client/src/libs/components/header/styles.module.scss delete mode 100644 client/src/libs/components/icon-button/icon-button.tsx delete mode 100644 client/src/libs/components/icon-button/styles.module.scss delete mode 100644 client/src/libs/components/icon/common.ts delete mode 100644 client/src/libs/components/icon/icon.tsx delete mode 100644 client/src/libs/components/message/message.tsx delete mode 100644 client/src/libs/components/message/styles.module.scss delete mode 100644 client/src/libs/components/modal/hooks/hooks.ts delete mode 100644 client/src/libs/components/modal/hooks/use-modal/use-modal.hook.ts delete mode 100644 client/src/libs/components/modal/modal.tsx delete mode 100644 client/src/libs/components/modal/styles.module.scss delete mode 100644 client/src/libs/components/notifications/notifications.tsx delete mode 100644 client/src/libs/components/portal/portal.tsx delete mode 100644 client/src/libs/components/portal/styles.module.scss delete mode 100644 client/src/libs/components/post/post.tsx delete mode 100644 client/src/libs/components/post/styles.module.scss delete mode 100644 client/src/libs/components/private-route/private-route.tsx delete mode 100644 client/src/libs/components/public-route/public-route.tsx delete mode 100644 client/src/libs/components/segment/segment.tsx delete mode 100644 client/src/libs/components/segment/styles.module.scss delete mode 100644 client/src/libs/components/spinner/spinner.tsx delete mode 100644 client/src/libs/components/spinner/styles.module.scss delete mode 100644 client/src/libs/enums/app/app-route.enum.ts delete mode 100644 client/src/libs/enums/app/environment.enum.ts delete mode 100644 client/src/libs/enums/components/icon-color.enum.ts delete mode 100644 client/src/libs/enums/components/icon-name.enum.ts delete mode 100644 client/src/libs/enums/components/icon-size.enum.ts delete mode 100644 client/src/libs/enums/enums.ts delete mode 100644 client/src/libs/enums/exception/exception.ts delete mode 100644 client/src/libs/enums/thread/post-filter-action.enum.ts delete mode 100644 client/src/libs/enums/thread/thread-toolbar-key.enum.ts delete mode 100644 client/src/libs/enums/thread/thread.ts delete mode 100644 client/src/libs/helpers/helpers.ts delete mode 100644 client/src/libs/hooks/use-app-selector/use-app-selector.hook.ts delete mode 100644 client/src/libs/packages/config/libs/types/config-package.type.ts delete mode 100644 client/src/libs/packages/store/libs/types/store-package.type.ts delete mode 100644 client/src/libs/packages/store/middlewares/middlewares.ts delete mode 100644 client/src/libs/packages/store/middlewares/notification-socket/notification-socket.middleware.ts delete mode 100644 client/src/libs/packages/store/store.package.ts delete mode 100644 client/src/libs/types/location.type.ts delete mode 100644 client/src/libs/types/types.ts delete mode 100644 client/src/packages/auth/auth-api.ts delete mode 100644 client/src/packages/auth/libs/enums/enums.ts delete mode 100644 client/src/packages/auth/libs/types/auth-api.type.ts delete mode 100644 client/src/packages/auth/libs/types/types.ts delete mode 100644 client/src/packages/auth/libs/validation-schemas/validation-schemas.ts delete mode 100644 client/src/packages/comment/comment-api.ts delete mode 100644 client/src/packages/comment/comment.ts delete mode 100644 client/src/packages/comment/libs/enums/enums.ts delete mode 100644 client/src/packages/comment/libs/types/comment-api.type.ts delete mode 100644 client/src/packages/comment/libs/types/types.ts delete mode 100644 client/src/packages/http/libs/enums/enums.ts delete mode 100644 client/src/packages/http/libs/exceptions/exceptions.ts delete mode 100644 client/src/packages/image/image-api.ts delete mode 100644 client/src/packages/image/image.ts delete mode 100644 client/src/packages/image/libs/enums/enums.ts delete mode 100644 client/src/packages/image/libs/types/image-api.type.ts delete mode 100644 client/src/packages/image/libs/types/types.ts delete mode 100644 client/src/packages/post/libs/enums/enums.ts delete mode 100644 client/src/packages/post/libs/types/post-api.type.ts delete mode 100644 client/src/packages/post/libs/types/types.ts delete mode 100644 client/src/packages/post/post-api.ts delete mode 100644 client/src/packages/post/post.ts delete mode 100644 client/src/packages/socket/libs/enums/enums.ts delete mode 100644 client/src/packages/socket/libs/types/socket-api.type.ts delete mode 100644 client/src/packages/socket/libs/types/types.ts delete mode 100644 client/src/packages/socket/socket-api.ts delete mode 100644 client/src/packages/socket/socket.ts delete mode 100644 client/src/packages/user/enums/enums.ts delete mode 100644 client/src/packages/user/types/types.ts delete mode 100644 client/src/pages/app/app.tsx delete mode 100644 client/src/pages/not-found/not-found.tsx delete mode 100644 client/src/pages/not-found/styles.module.scss delete mode 100644 client/src/pages/profile/profile.tsx delete mode 100644 client/src/pages/profile/styles.module.scss delete mode 100644 client/src/pages/shared-post/shared-post.tsx delete mode 100644 client/src/pages/sign/components/components.ts delete mode 100644 client/src/pages/sign/components/login-form/libs/common/constants.ts delete mode 100644 client/src/pages/sign/components/login-form/login-form.tsx delete mode 100644 client/src/pages/sign/components/registration-form/registration-form.tsx delete mode 100644 client/src/pages/thread/components/add-comment/add-comment.tsx delete mode 100644 client/src/pages/thread/components/add-comment/libs/constants/constants.ts delete mode 100644 client/src/pages/thread/components/add-comment/styles.module.scss delete mode 100644 client/src/pages/thread/components/add-post/add-post.tsx delete mode 100644 client/src/pages/thread/components/add-post/libs/constants/constants.ts delete mode 100644 client/src/pages/thread/components/add-post/styles.module.scss delete mode 100644 client/src/pages/thread/components/comment/comment.tsx delete mode 100644 client/src/pages/thread/components/comment/styles.module.scss delete mode 100644 client/src/pages/thread/components/components.ts delete mode 100644 client/src/pages/thread/components/expanded-post/expanded-post.tsx delete mode 100644 client/src/pages/thread/components/expanded-post/libs/helpers/get-sorted-comments/get-sorted-comments.helper.ts delete mode 100644 client/src/pages/thread/components/expanded-post/libs/helpers/helpers.ts delete mode 100644 client/src/pages/thread/components/shared-post-link/shared-post-link.tsx delete mode 100644 client/src/pages/thread/components/shared-post-link/styles.module.scss delete mode 100644 client/src/pages/thread/libs/common/constants.ts delete mode 100644 client/src/pages/thread/libs/hooks/use-posts-filter/use-posts-filter.ts delete mode 100644 client/src/pages/thread/styles.module.scss delete mode 100644 client/src/pages/thread/thread.tsx delete mode 100644 client/src/slices/app/actions.ts delete mode 100644 client/src/slices/app/app.ts delete mode 100644 client/src/slices/notifications/actions.ts delete mode 100644 client/src/slices/notifications/common.ts delete mode 100644 client/src/slices/notifications/notifications.ts delete mode 100644 client/src/slices/profile/actions.ts delete mode 100644 client/src/slices/profile/common.ts delete mode 100644 client/src/slices/profile/profile.slice.ts delete mode 100644 client/src/slices/profile/profile.ts delete mode 100644 client/src/slices/thread/actions.ts delete mode 100644 client/src/slices/thread/common.ts delete mode 100644 client/src/slices/thread/thread.slice.ts delete mode 100644 client/src/slices/thread/thread.ts rename packages/shared/src/modules/auth/libs/validation-schemas/{registration.validation-schema.ts => sign-up.validation-schema.ts} (95%) diff --git a/apps/backend/package.json b/apps/backend/package.json index 570ff2e4..4f42d4ab 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -1,5 +1,5 @@ { - "name": "backend", + "name": "@thread-js/backend", "private": true, "engines": { "node": "18.18.x", @@ -26,7 +26,7 @@ "dependencies": { "@fastify/cors": "8.4.2", "@fastify/static": "6.12.0", - "@thread-js/shared": "file:../../packages/shared", + "@thread-js/shared": "*", "axios": "1.6.2", "bcrypt": "5.1.1", "convict": "6.2.4", diff --git a/apps/backend/src/packages/auth/auth.controller.ts b/apps/backend/src/packages/auth/auth.controller.ts index 765ebfe3..d6ab51c9 100644 --- a/apps/backend/src/packages/auth/auth.controller.ts +++ b/apps/backend/src/packages/auth/auth.controller.ts @@ -3,20 +3,19 @@ import { Controller, ControllerAPIHandler, ControllerAPIHandlerOptions, - ControllerAPIHandlerResponse, - ControllerHook + ControllerAPIHandlerResponse } from '~/libs/modules/controller/controller.js'; import { HTTPCode, HTTPMethod } from '~/libs/modules/http/http.js'; import { type ValueOf } from '~/libs/types/types.js'; import { AuthApiPath } from './libs/enums/enums.js'; import { - UserRegisterResponseDto, + UserSignUpResponseDto, type AuthController, type AuthService, - type UserRegisterRequestDto + type UserSignUpRequestDto } from './libs/types/types.js'; -import { registrationValidationSchema } from './libs/validation-schemas/validation-schemas.js'; +import { signUpValidationSchema } from './libs/validation-schemas/validation-schemas.js'; import { LoggerModule } from '~/libs/modules/logger/logger.js'; type Constructor = { @@ -34,9 +33,9 @@ class Auth extends Controller implements AuthController { this.addRoute({ method: HTTPMethod.POST, - url: AuthApiPath.REGISTER, + url: AuthApiPath.SIGN_UP, schema: { - body: registrationValidationSchema + body: signUpValidationSchema }, handler: this.register as ControllerAPIHandler }); @@ -44,9 +43,9 @@ class Auth extends Controller implements AuthController { public register = async ( options: ControllerAPIHandlerOptions<{ - body: UserRegisterRequestDto; + body: UserSignUpRequestDto; }> - ): Promise> => { + ): Promise> => { return { payload: await this.#authService.register(options.body), status: HTTPCode.CREATED diff --git a/apps/backend/src/packages/auth/auth.service.ts b/apps/backend/src/packages/auth/auth.service.ts index 8ed48ee9..30591dea 100644 --- a/apps/backend/src/packages/auth/auth.service.ts +++ b/apps/backend/src/packages/auth/auth.service.ts @@ -1,8 +1,8 @@ import { type UserRepository } from '../user/user.js'; import { - type UserRegisterResponseDto, + type UserSignUpResponseDto, type AuthService, - type UserRegisterRequestDto + type UserSignUpRequestDto } from './libs/types/types.js'; type Constructor = { @@ -17,8 +17,8 @@ class Auth implements AuthService { } public register = async ( - userRequestDto: UserRegisterRequestDto - ): Promise => { + userRequestDto: UserSignUpRequestDto + ): Promise => { return this.#userRepository.create(userRequestDto); }; } diff --git a/apps/backend/src/packages/auth/auth.ts b/apps/backend/src/packages/auth/auth.ts index 068c519d..bb46f7b0 100644 --- a/apps/backend/src/packages/auth/auth.ts +++ b/apps/backend/src/packages/auth/auth.ts @@ -19,6 +19,6 @@ export { encryptSync } from './helpers/helpers.js'; export { AuthApiPath } from './libs/enums/enums.js'; export { type AuthService, - type UserRegisterRequestDto, - type UserRegisterResponseDto + type UserSignUpRequestDto, + type UserSignUpResponseDto } from './libs/types/types.js'; diff --git a/apps/backend/src/packages/auth/libs/types/auth-controller.type.ts b/apps/backend/src/packages/auth/libs/types/auth-controller.type.ts index 1f52b1c5..137c7d6f 100644 --- a/apps/backend/src/packages/auth/libs/types/auth-controller.type.ts +++ b/apps/backend/src/packages/auth/libs/types/auth-controller.type.ts @@ -1,8 +1,8 @@ import { type FastifyReply, type FastifyRequest } from 'fastify'; import { - type UserRegisterResponseDto, - type UserRegisterRequestDto + type UserSignUpResponseDto, + type UserSignUpRequestDto } from './types.js'; import { ControllerAPIHandlerOptions, @@ -12,9 +12,9 @@ import { type AuthController = { register: ( options: ControllerAPIHandlerOptions<{ - body: UserRegisterRequestDto; + body: UserSignUpRequestDto; }> - ) => Promise>; + ) => Promise>; }; export { type AuthController }; diff --git a/apps/backend/src/packages/auth/libs/types/auth-service.type.ts b/apps/backend/src/packages/auth/libs/types/auth-service.type.ts index c1ecb95f..9e4db04b 100644 --- a/apps/backend/src/packages/auth/libs/types/auth-service.type.ts +++ b/apps/backend/src/packages/auth/libs/types/auth-service.type.ts @@ -1,10 +1,10 @@ import { - type UserRegisterRequestDto, - type UserRegisterResponseDto + type UserSignUpRequestDto, + type UserSignUpResponseDto } from './types.js'; type AuthService = { - register(_user: UserRegisterRequestDto): Promise; + register(_user: UserSignUpRequestDto): Promise; }; export { type AuthService }; diff --git a/apps/backend/src/packages/auth/libs/types/types.ts b/apps/backend/src/packages/auth/libs/types/types.ts index a8a171e9..7f0de3ea 100644 --- a/apps/backend/src/packages/auth/libs/types/types.ts +++ b/apps/backend/src/packages/auth/libs/types/types.ts @@ -2,6 +2,6 @@ export { type AuthController } from './auth-controller.type.js'; export { type AuthService } from './auth-service.type.js'; export { type User, - type UserRegisterRequestDto, - type UserRegisterResponseDto + type UserSignUpRequestDto, + type UserSignUpResponseDto } from '@thread-js/shared'; diff --git a/apps/backend/src/packages/auth/libs/validation-schemas/validation-schemas.ts b/apps/backend/src/packages/auth/libs/validation-schemas/validation-schemas.ts index d11ee0e5..4c6d91e2 100644 --- a/apps/backend/src/packages/auth/libs/validation-schemas/validation-schemas.ts +++ b/apps/backend/src/packages/auth/libs/validation-schemas/validation-schemas.ts @@ -1 +1 @@ -export { registration as registrationValidationSchema } from '@thread-js/shared'; +export { signUp as signUpValidationSchema } from '@thread-js/shared'; diff --git a/apps/backend/tests/modules/auth/auth.api.spec.ts b/apps/backend/tests/modules/auth/auth.api.spec.ts index 5536b51b..4e31e8ba 100644 --- a/apps/backend/tests/modules/auth/auth.api.spec.ts +++ b/apps/backend/tests/modules/auth/auth.api.spec.ts @@ -8,8 +8,8 @@ import { HTTPCode, HTTPMethod } from '~/libs/modules/http/http.js'; import { joinPath } from '~/libs/modules/path/path.js'; import { AuthApiPath, - type UserRegisterRequestDto, - type UserRegisterResponseDto + type UserSignUpRequestDto, + type UserSignUpResponseDto } from '~/packages/auth/auth.js'; import { UserPayloadKey, @@ -31,7 +31,7 @@ const registerEndpoint = joinPath([ config.ENV.APP.API_PATH, API_V1_VERSION_PREFIX, APIPath.AUTH, - AuthApiPath.REGISTER + AuthApiPath.SIGN_UP ]); describe(`${authApiPath} routes`, () => { @@ -91,7 +91,7 @@ describe(`${authApiPath} routes`, () => { it(`should return ${HTTPCode.UNPROCESSED_ENTITY} of empty ${UserPayloadKey.EMAIL} validation error`, async () => { const [validTestUser] = TEST_USERS_CREDENTIALS; const { [UserPayloadKey.EMAIL]: _email, ...user } = - validTestUser as UserRegisterRequestDto; + validTestUser as UserSignUpRequestDto; const response = await app.inject().post(registerEndpoint).body(user); @@ -121,7 +121,7 @@ describe(`${authApiPath} routes`, () => { it(`should return ${HTTPCode.UNPROCESSED_ENTITY} of empty ${UserPayloadKey.PASSWORD} validation error`, async () => { const [validTestUser] = TEST_USERS_CREDENTIALS; const { [UserPayloadKey.PASSWORD]: _password, ...user } = - validTestUser as UserRegisterRequestDto; + validTestUser as UserSignUpRequestDto; const response = await app.inject().post(registerEndpoint).body(user); @@ -170,9 +170,7 @@ describe(`${authApiPath} routes`, () => { }); it(`should return ${HTTPCode.CREATED} and create a new user`, async () => { - const [validTestUser] = TEST_USERS_CREDENTIALS as [ - UserRegisterRequestDto - ]; + const [validTestUser] = TEST_USERS_CREDENTIALS as [UserSignUpRequestDto]; const response = await app .inject() @@ -189,7 +187,7 @@ describe(`${authApiPath} routes`, () => { const savedDatabaseUser = await select({ table: DatabaseTableName.USERS, - condition: { id: response.json().id }, + condition: { id: response.json().id }, limit: KNEX_SELECT_ONE_RECORD }); diff --git a/apps/backend/tests/modules/user/libs/constants/test-user-credentials.constant.ts b/apps/backend/tests/modules/user/libs/constants/test-user-credentials.constant.ts index 717a9f1a..02f6c4c9 100644 --- a/apps/backend/tests/modules/user/libs/constants/test-user-credentials.constant.ts +++ b/apps/backend/tests/modules/user/libs/constants/test-user-credentials.constant.ts @@ -1,5 +1,5 @@ import { faker } from '@faker-js/faker'; -import { UserRegisterRequestDto } from '~/packages/auth/auth.js'; +import { UserSignUpRequestDto } from '~/packages/auth/auth.js'; import { UserPayloadKey } from '~/packages/user/user.js'; @@ -7,7 +7,7 @@ const USERS_COUNT = 2; const TEST_USERS_CREDENTIALS = Array.from( { length: USERS_COUNT }, - (): UserRegisterRequestDto => { + (): UserSignUpRequestDto => { return { [UserPayloadKey.USERNAME]: faker.person.firstName(), [UserPayloadKey.EMAIL]: faker.internet.email(), diff --git a/apps/frontend/.env.example b/apps/frontend/.env.example new file mode 100644 index 00000000..a4037cc8 --- /dev/null +++ b/apps/frontend/.env.example @@ -0,0 +1,8 @@ +# +# APPLICATION +# +# default. own preference might be used +VITE_APP_PROXY_SERVER_URL=http://localhost:3001 +VITE_API_PATH=/api/v1 +VITE_APP_PORT=3000 +VITE_APP_HOST=localhost diff --git a/client/.eslintrc.yml b/apps/frontend/.eslintrc.yml similarity index 100% rename from client/.eslintrc.yml rename to apps/frontend/.eslintrc.yml diff --git a/client/.stylelintrc.yml b/apps/frontend/.stylelintrc.yml similarity index 100% rename from client/.stylelintrc.yml rename to apps/frontend/.stylelintrc.yml diff --git a/client/index.html b/apps/frontend/index.html similarity index 100% rename from client/index.html rename to apps/frontend/index.html diff --git a/client/package.json b/apps/frontend/package.json similarity index 92% rename from client/package.json rename to apps/frontend/package.json index 35aa0ba9..57119a1e 100644 --- a/client/package.json +++ b/apps/frontend/package.json @@ -1,5 +1,5 @@ { - "name": "client", + "name": "@thread-js/frontend", "private": true, "engines": { "node": "18.18.x", @@ -21,6 +21,7 @@ "@hookform/error-message": "2.0.1", "@hookform/resolvers": "3.3.2", "@reduxjs/toolkit": "2.0.1", + "@thread-js/shared": "*", "clsx": "2.0.0", "events": "3.3.0", "query-string": "8.1.0", @@ -28,8 +29,8 @@ "react-dom": "18.2.0", "react-hook-form": "7.49.2", "react-infinite-scroll-component": "6.1.0", - "react-redux": "9.0.4", - "react-router-dom": "6.21.0", + "react-redux": "9.1.2", + "react-router-dom": "6.23.1", "react-toastify": "9.1.3", "socket.io-client": "4.7.2" }, diff --git a/client/public/favicon.ico b/apps/frontend/public/favicon.ico similarity index 100% rename from client/public/favicon.ico rename to apps/frontend/public/favicon.ico diff --git a/client/public/manifest.json b/apps/frontend/public/manifest.json similarity index 100% rename from client/public/manifest.json rename to apps/frontend/public/manifest.json diff --git a/client/src/assets/css/common.scss b/apps/frontend/src/assets/css/scaffolding.css similarity index 100% rename from client/src/assets/css/common.scss rename to apps/frontend/src/assets/css/scaffolding.css diff --git a/apps/frontend/src/assets/css/styles.css b/apps/frontend/src/assets/css/styles.css new file mode 100644 index 00000000..01f4eca3 --- /dev/null +++ b/apps/frontend/src/assets/css/styles.css @@ -0,0 +1,2 @@ +@import './scaffolding.css'; +@import './variables.css'; diff --git a/client/src/assets/css/variables.scss b/apps/frontend/src/assets/css/variables.css similarity index 100% rename from client/src/assets/css/variables.scss rename to apps/frontend/src/assets/css/variables.css diff --git a/client/src/index.tsx b/apps/frontend/src/index.tsx similarity index 73% rename from client/src/index.tsx rename to apps/frontend/src/index.tsx index d6bd289b..133eeaeb 100644 --- a/client/src/index.tsx +++ b/apps/frontend/src/index.tsx @@ -1,9 +1,8 @@ -import '~/assets/css/styles.scss'; +import '~/assets/css/styles.css'; import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import { Provider } from 'react-redux'; -import { BrowserRouter as Router } from 'react-router-dom'; import { store } from '~/libs/packages/store/store.js'; import { App } from '~/pages/app/app.js'; @@ -13,9 +12,7 @@ const root = createRoot(document.querySelector('#root') as HTMLElement); root.render( - - - + ); diff --git a/client/src/libs/components/button/button.tsx b/apps/frontend/src/libs/components/button/button.tsx similarity index 70% rename from client/src/libs/components/button/button.tsx rename to apps/frontend/src/libs/components/button/button.tsx index 24d2bc29..d8fbc161 100644 --- a/client/src/libs/components/button/button.tsx +++ b/apps/frontend/src/libs/components/button/button.tsx @@ -1,16 +1,10 @@ /* eslint-disable react/button-has-type */ -import { type SizeProp } from '@fortawesome/fontawesome-svg-core'; import clsx from 'clsx'; import { type ReactNode } from 'react'; -import { - type ButtonColor, - type IconName, - type IconSize -} from '~/libs/enums/enums.js'; +import { type ButtonColor } from '~/libs/enums/enums.js'; import { type ButtonType, type ValueOf } from '~/libs/types/types.js'; -import { Icon } from '../icon/icon.js'; import styles from './styles.module.scss'; type ButtonProperties = { @@ -19,8 +13,6 @@ type ButtonProperties = { color?: ValueOf; onClick?: React.MouseEventHandler; className?: string; - iconName?: ValueOf; - iconSize?: ValueOf; isBasic?: boolean; isFluid?: boolean; isLoading?: boolean; @@ -33,8 +25,6 @@ const Button: React.FC = ({ className, type = 'button', color, - iconName, - iconSize, isBasic = false, isFluid = false, isLoading = false, @@ -42,8 +32,6 @@ const Button: React.FC = ({ isDisabled = false, children }) => { - const hasIcon = Boolean(iconName); - return ( ); diff --git a/client/src/libs/components/button/styles.module.scss b/apps/frontend/src/libs/components/button/styles.module.scss similarity index 100% rename from client/src/libs/components/button/styles.module.scss rename to apps/frontend/src/libs/components/button/styles.module.scss diff --git a/apps/frontend/src/libs/components/components.ts b/apps/frontend/src/libs/components/components.ts new file mode 100644 index 00000000..86a7f82e --- /dev/null +++ b/apps/frontend/src/libs/components/components.ts @@ -0,0 +1,5 @@ +export { Button } from './button/button.js'; +export { Image } from './image/image.js'; +export { Input } from './input/input.js'; +export { RouterProvider } from './router-provider/router-provider.js'; +export { NavLink } from 'react-router-dom'; diff --git a/client/src/libs/components/image/image.tsx b/apps/frontend/src/libs/components/image/image.tsx similarity index 100% rename from client/src/libs/components/image/image.tsx rename to apps/frontend/src/libs/components/image/image.tsx diff --git a/client/src/libs/components/image/styles.module.scss b/apps/frontend/src/libs/components/image/styles.module.scss similarity index 100% rename from client/src/libs/components/image/styles.module.scss rename to apps/frontend/src/libs/components/image/styles.module.scss diff --git a/client/src/libs/components/input/input.tsx b/apps/frontend/src/libs/components/input/input.tsx similarity index 78% rename from client/src/libs/components/input/input.tsx rename to apps/frontend/src/libs/components/input/input.tsx index 28b6c5ba..04981207 100644 --- a/client/src/libs/components/input/input.tsx +++ b/apps/frontend/src/libs/components/input/input.tsx @@ -7,11 +7,9 @@ import { type FieldValues } from 'react-hook-form'; -import { type IconName } from '~/libs/enums/enums.js'; import { useController } from '~/libs/hooks/hooks.js'; import { type ValueOf } from '~/libs/types/types.js'; -import { Icon } from '../icon/icon.js'; import styles from './styles.module.scss'; type InputProperties = { @@ -19,7 +17,6 @@ type InputProperties = { control: Control; errors?: object; disabled?: boolean; - iconName?: ValueOf; placeholder: string; className?: string; type?: 'email' | 'password' | 'submit' | 'text'; @@ -33,7 +30,6 @@ const Input = ({ rows = 0, errors = {}, disabled, - iconName, placeholder, className }: InputProperties): ReactElement => { @@ -43,11 +39,6 @@ const Input = ({ return (
- {iconName && ( - - - - )} {isTextarea ? (