├── .env.example ├── .env.test ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .nvmrc ├── .prettierrc ├── CHANGELOG.md ├── README.md ├── nodemon.json ├── onion.diagram.architecture.svg ├── onion.diagram.database.png ├── onion.diagram.domain.svg ├── onion.diagram.flow.svg ├── onion.diagram.infrastructure.svg ├── onion.diagram.layers.svg ├── onion.diagram.lifecycle.svg ├── onion.diagram.ui.svg ├── ormconfig.sample.js ├── package.json ├── src ├── core │ ├── CoreModuleSymbols.ts │ ├── applicationServices │ │ ├── Authentication │ │ │ ├── AuthenticationService.ts │ │ │ ├── IAuthenticationService.ts │ │ │ └── requests │ │ │ │ ├── AuthenticationRequest.ts │ │ │ │ └── SignUpRequest.ts │ │ ├── Equipment │ │ │ ├── EquipmentService.ts │ │ │ ├── IEquipmentService.ts │ │ │ └── requests │ │ │ │ ├── CreateEquipmentRequest.ts │ │ │ │ └── FetchEquipmentRequest.ts │ │ ├── Portal │ │ │ ├── Warehouse │ │ │ │ ├── IWarehouseService.ts │ │ │ │ └── WarehouseService.ts │ │ │ └── WarehouseItem │ │ │ │ ├── IWarehouseItemService.ts │ │ │ │ ├── WarehouseItemService.ts │ │ │ │ └── requests │ │ │ │ └── AddWarehouseItemRequest.ts │ │ ├── Rate │ │ │ ├── IRateService.ts │ │ │ ├── RateService.ts │ │ │ └── requests │ │ │ │ └── FetchRateRequest.ts │ │ ├── State │ │ │ ├── IStateService.ts │ │ │ ├── StateService.ts │ │ │ └── requests │ │ │ │ └── FetchStateRequest.ts │ │ ├── User │ │ │ ├── IUserEquipmentService.ts │ │ │ ├── IUserService.ts │ │ │ ├── UserEquipmentService.ts │ │ │ ├── UserService.ts │ │ │ └── requests │ │ │ │ ├── CalculateUserEquipmentCostRequest.ts │ │ │ │ ├── FetchUserEquipmentRequest.ts │ │ │ │ ├── FetchUserRequest.ts │ │ │ │ └── RemoveUserReuqest.ts │ │ ├── Warehouse │ │ │ ├── IWarehouseService.ts │ │ │ ├── IWarehouseStateService.ts │ │ │ ├── IWarehouseWarehouseItemService.ts │ │ │ ├── WarehouseService.ts │ │ │ ├── WarehouseStateService.ts │ │ │ ├── WarehouseWarehouseItemService.ts │ │ │ └── requests │ │ │ │ ├── CreateWarehouseRequest.ts │ │ │ │ ├── FetchWarehouseRequest.ts │ │ │ │ ├── FetchWarehouseStateRequest.ts │ │ │ │ └── UpdateWarehouseRequest.ts │ │ ├── WarehouseItem │ │ │ ├── IWarehouseItemEquipmentService.ts │ │ │ ├── IWarehouseItemService.ts │ │ │ ├── IWarehouseItemWarehouseService.ts │ │ │ ├── WarehouseItemEquipmentService.ts │ │ │ ├── WarehouseItemService.ts │ │ │ ├── WarehouseItemWarehouseService.ts │ │ │ └── requests │ │ │ │ ├── CreateWarehouseItemRequest.ts │ │ │ │ ├── FetchWarehouseItemEquipmentRequest.ts │ │ │ │ ├── FetchWarehouseItemRequest.ts │ │ │ │ ├── FetchWarehouseItemWarehouseRequest.ts │ │ │ │ ├── FetchWarehouseItemsRequest.ts │ │ │ │ └── UpdateWarehouseItemRequest.ts │ │ └── common │ │ │ ├── Equipment │ │ │ └── interactors │ │ │ │ ├── CalculateEquipmentCostInteractor.ts │ │ │ │ └── requests │ │ │ │ └── CalculateEquipmentCostInteractorRequest.ts │ │ │ └── IInteractor.ts │ ├── common │ │ ├── errors │ │ │ ├── BaseError.ts │ │ │ ├── CoreError.ts │ │ │ └── CoreErrors.ts │ │ └── mapper │ │ │ └── IMapping.ts │ ├── domain │ │ ├── Authentication │ │ │ └── Authentication.ts │ │ ├── Equipment │ │ │ ├── Equipment.ts │ │ │ └── EquipmentCost.ts │ │ ├── Rate │ │ │ └── Rate.ts │ │ ├── Role │ │ │ └── Role.ts │ │ ├── State │ │ │ └── State.ts │ │ ├── User │ │ │ ├── User.ts │ │ │ └── UserRole.ts │ │ └── Warehouse │ │ │ ├── Warehouse.ts │ │ │ └── WarehouseItem.ts │ └── domainServices │ │ ├── Equipment │ │ ├── IEquipmentRepository.ts │ │ ├── IEquipmentUnitOfWork.ts │ │ └── request │ │ │ ├── AddEquipmentRepositoryRequest.ts │ │ │ ├── AddEquipmentUnitOfWorkRepositoryRequest.ts │ │ │ └── FindEquipmentRepositoryRequest.ts │ │ ├── Portal │ │ ├── Warehouse │ │ │ └── IWarehouseRepository.ts │ │ └── WarehouseItem │ │ │ ├── IWarehouseItemRepository.ts │ │ │ └── requests │ │ │ └── AddWarehouseItemRepositoryRequest.ts │ │ ├── Rate │ │ ├── IRateRepository.ts │ │ └── request │ │ │ └── GetRateRepositoryRequest.ts │ │ ├── Role │ │ ├── IRoleRepository.ts │ │ └── request │ │ │ ├── FindRoleByNameRepositoryRequest.ts │ │ │ └── FindRoleRepositoryRequest.ts │ │ ├── State │ │ ├── IStateRepository.ts │ │ └── request │ │ │ └── GetStateRepositoryRequest.ts │ │ ├── User │ │ ├── IUserEquipmentRepository.ts │ │ ├── IUserRepository.ts │ │ ├── IUserUnitOfWork.ts │ │ └── request │ │ │ ├── AddUserRepositoryRequest.ts │ │ │ ├── AddUserUnitOfWorkRepositoryRequest.ts │ │ │ ├── DeleteUserRepositoryRequest.ts │ │ │ ├── DeleteUserUnitOfWorkRepositoryRequest.ts │ │ │ ├── FindUserByEmailRepositoryRequest.ts │ │ │ ├── FindUserEquipmentRepositoryRequest.ts │ │ │ ├── FindUserRepositoryRequest.ts │ │ │ └── GetUserEquipmentRepositoryRequest.ts │ │ ├── Warehouse │ │ ├── IWarehouseRepository.ts │ │ ├── IWarehouseStateRepository.ts │ │ ├── IWarehouseWarehouseItemRepository.ts │ │ └── request │ │ │ ├── CreateWarehouseRepositoryRequest.ts │ │ │ ├── GetWarehouseRepositoryRequest.ts │ │ │ ├── GetWarehouseStateRepositoryRequest.ts │ │ │ └── UpdateWarehouseRepositoryRequest.ts │ │ └── WarehouseItem │ │ ├── IWarehouseItemEquipmentRepository.ts │ │ ├── IWarehouseItemRepository.ts │ │ ├── IWarehouseItemWarehouseRepository.ts │ │ └── requests │ │ ├── CreateWarehouseItemRepositoryRequest.ts │ │ ├── GetWarehouseItemEquipmentRepositoryRequest.ts │ │ ├── GetWarehouseItemRepositoryRequest.ts │ │ ├── GetWarehouseItemWarehouseRepositoryRequest.ts │ │ ├── GetWarehouseItemsRepositoryRequest.ts │ │ └── UpdateWarehouseItemRepositoryRequest.ts ├── dependency │ ├── Administration │ │ ├── Rate │ │ │ └── RateModule.ts │ │ ├── Role │ │ │ └── RoleModule.ts │ │ ├── State │ │ │ └── StateModule.ts │ │ ├── User │ │ │ └── UserModule.ts │ │ ├── Warehouse │ │ │ └── WarehouseModule.ts │ │ ├── WarehouseItem │ │ │ └── WarehouseItemModule.ts │ │ └── common │ │ │ └── AdministrationModule.ts │ ├── AppContainer.ts │ ├── BaseContainer.ts │ ├── BaseModule.ts │ ├── Portal │ │ ├── Equipment │ │ │ └── EquipmentModule.ts │ │ ├── User │ │ │ └── UserModule.ts │ │ ├── Warehouse │ │ │ └── WarehouseModule.ts │ │ ├── WarehouseItem │ │ │ └── WarehouseItemModule.ts │ │ └── common │ │ │ └── PortalModule.ts │ ├── common │ │ ├── ApplicationModule.ts │ │ └── CommonModule.ts │ └── shared │ │ ├── Authentication │ │ └── AuthenticationModule.ts │ │ ├── Equipment │ │ └── EquipmentModule.ts │ │ ├── User │ │ └── UserModule.ts │ │ ├── Warehouse │ │ └── WarehouseModule.ts │ │ └── common │ │ └── SharedModule.ts ├── index.ts ├── infrastructure │ ├── InfrastructureModuleSymbols.ts │ ├── common │ │ ├── errors │ │ │ └── InfrastructureErrors.ts │ │ └── mapper │ │ │ └── .gitkeep │ └── database │ │ ├── cli │ │ └── dbReload.ts │ │ ├── entities │ │ ├── Equipment.ts │ │ ├── Rate.ts │ │ ├── Role.ts │ │ ├── State.ts │ │ ├── User.ts │ │ ├── Warehouse.ts │ │ └── WarehouseItem.ts │ │ ├── enum │ │ └── UserRole.ts │ │ ├── fixtures │ │ ├── factories │ │ │ ├── EquipmentFactory.ts │ │ │ ├── RateFactory.ts │ │ │ ├── RoleFactory.ts │ │ │ ├── StateFactory.ts │ │ │ ├── UserFactory.ts │ │ │ ├── WarehouseFactory.ts │ │ │ └── WarehouseItemFactory.ts │ │ └── seeds │ │ │ ├── RateSeed.ts │ │ │ ├── StateSeed.ts │ │ │ ├── UserSeed.ts │ │ │ └── WarehouseSeed.ts │ │ ├── mappings │ │ ├── DBMapper.ts │ │ ├── Equipment │ │ │ └── EquipmentEntityToEquipmentDomain.ts │ │ ├── Rate │ │ │ └── RateEntityToRateDomain.ts │ │ ├── Role │ │ │ └── RoleEntityToRoleDomain.ts │ │ ├── State │ │ │ └── StateEntityToStateDomain.ts │ │ ├── User │ │ │ └── UserEntityToUserDomain.ts │ │ └── Warehouse │ │ │ ├── WarehouseEntityToWarehouseDomain.ts │ │ │ └── WarehouseItemEntityToWarehouseItemDomain.ts │ │ ├── migrations │ │ ├── 1580081950192-create_user.ts │ │ ├── 1580148565494-create_role.ts │ │ ├── 1580567781829-create_equipment.ts │ │ ├── 1611436598116-create_state.ts │ │ ├── 1611436650648-create_rate.ts │ │ ├── 1611439711157-create_state_rates_rate.ts │ │ ├── 1611439711158-create_equipment_state_rate.ts │ │ ├── 1611439891485-update_role_enum_capitalize.ts │ │ ├── 1613939591337-create_warehouse.ts │ │ ├── 1613939666376-create_warehouse_item.ts │ │ ├── 1613940493612-remove_equipment_state_rate.ts │ │ ├── 1615066557385-add_equipment_dimensions.ts │ │ ├── 1615066763427-add_warehouse_dimensions_costs.ts │ │ └── 1615067499391-add_warehouse_properties_availability_capacity.ts │ │ ├── orm │ │ ├── IOrm.ts │ │ └── OnionOrm.ts │ │ └── repository │ │ ├── Equipment │ │ ├── EquipmentRepository.ts │ │ └── EquipmentUnitOfWork.ts │ │ ├── Portal │ │ ├── Warehouse │ │ │ └── WarehouseRepository.ts │ │ └── WarehouseItem │ │ │ └── WarehouseItemRepository.ts │ │ ├── Rate │ │ └── RateRepository.ts │ │ ├── Role │ │ └── RoleRepository.ts │ │ ├── State │ │ └── StateRepository.ts │ │ ├── User │ │ ├── UserEquipmentRepository.ts │ │ ├── UserRepository.ts │ │ └── UserUnitOfWork.ts │ │ ├── Warehouse │ │ ├── WarehouseRepository.ts │ │ ├── WarehouseStateRepository.ts │ │ └── WarehouseWarehouseItemRepository.ts │ │ ├── WarehouseItem │ │ ├── WarehouseItemEquipmentRepository.ts │ │ ├── WarehouseItemRepository.ts │ │ └── WarehouseItemWarehouseRepository.ts │ │ └── common │ │ ├── IRepository.ts │ │ ├── Query.ts │ │ ├── Repository.ts │ │ ├── UnitOfWork.ts │ │ └── UpdateQueryData.ts └── ui │ ├── Administration │ ├── Equipment │ │ └── graphql │ │ │ ├── EquipmentMutation.ts │ │ │ ├── EquipmentQuery.ts │ │ │ ├── EquipmentSubQuery.ts │ │ │ ├── gql │ │ │ └── Equipment.graphql │ │ │ └── inputs │ │ │ └── CreateEquipmentInput.ts │ ├── Rate │ │ └── graphql │ │ │ ├── RateQuery.ts │ │ │ └── gql │ │ │ └── Rate.graphql │ ├── State │ │ └── graphql │ │ │ ├── StateQuery.ts │ │ │ └── gql │ │ │ └── State.graphql │ ├── User │ │ └── graphql │ │ │ ├── UserMutation.ts │ │ │ ├── UserQuery.ts │ │ │ ├── UserSubQuery.ts │ │ │ ├── gql │ │ │ └── User.graphql │ │ │ └── inputs │ │ │ └── RemoveUserInput.ts │ ├── Warehouse │ │ └── graphql │ │ │ ├── WarehouseMutation.ts │ │ │ ├── WarehouseQuery.ts │ │ │ ├── WarehouseSubQuery.ts │ │ │ ├── gql │ │ │ └── Warehouse.graphql │ │ │ └── inputs │ │ │ ├── CreateWarehouseInput.ts │ │ │ ├── GetWarehouseInput.ts │ │ │ └── UpdateWarehouseInput.ts │ ├── WarehouseItem │ │ └── graphql │ │ │ ├── WarehouseItemMutation.ts │ │ │ ├── WarehouseItemQuery.ts │ │ │ ├── WarehouseItemSubQuery.ts │ │ │ ├── gql │ │ │ └── WarehouseItem.graphql │ │ │ └── inputs │ │ │ ├── CreateWarehouseItemInput.ts │ │ │ ├── GetWarehouseItemInput.ts │ │ │ └── UpdateWarehouseItemInput.ts │ └── common │ │ └── graphql │ │ ├── AdministrationMutation.ts │ │ ├── AdministrationQuery.ts │ │ └── AdministrationSubQuery.ts │ ├── Portal │ ├── Authentication │ │ └── rest │ │ │ └── v1 │ │ │ ├── AuthenticationController.ts │ │ │ └── requests │ │ │ ├── AuthenticationRequestBody.ts │ │ │ └── SignupRequestBody.ts │ ├── Equipment │ │ ├── graphql │ │ │ ├── EquipmentQueries.ts │ │ │ ├── gql │ │ │ │ └── Equipment.graphql │ │ │ └── inputs │ │ │ │ └── CalculateEquipmentCostInput.ts │ │ └── rest │ │ │ └── v1 │ │ │ ├── EquipmentController.ts │ │ │ └── requests │ │ │ └── CreateEquipmentRequestBody.ts │ ├── User │ │ ├── graphql │ │ │ ├── UserQuery.ts │ │ │ ├── gql │ │ │ │ └── User.graphql │ │ │ └── inputs │ │ │ │ └── .gitkeep │ │ └── rest │ │ │ └── v1 │ │ │ ├── UserController.ts │ │ │ └── requests │ │ │ └── DeleteUserRequestBody.ts │ ├── Warehouse │ │ ├── WarehouseQuery.ts │ │ └── graphql │ │ │ └── gql │ │ │ └── Warehouse.graphql │ ├── WarehouseItem │ │ └── graphql │ │ │ ├── WarehouseItemMutation.ts │ │ │ ├── gql │ │ │ └── WarehouseItem.graphql │ │ │ └── inputs │ │ │ └── AddWarehouseItemInput.ts │ └── common │ │ └── graphql │ │ ├── PortalMutation.ts │ │ ├── PortalQuery.ts │ │ └── PortalSubQuery.ts │ ├── UiModuleSymbols.ts │ ├── common │ ├── config │ │ ├── application │ │ │ ├── apollo │ │ │ │ ├── ApolloApplication.ts │ │ │ │ ├── ApolloConfig.ts │ │ │ │ ├── ApolloContext.ts │ │ │ │ ├── auth │ │ │ │ │ ├── GraphQLJWTAuthenticationHandler.ts │ │ │ │ │ └── types │ │ │ │ │ │ └── GraphQLTokenPayload.ts │ │ │ │ ├── common │ │ │ │ │ ├── IApolloContext.ts │ │ │ │ │ └── IResolver.ts │ │ │ │ ├── consts │ │ │ │ │ └── schemaDirectives.ts │ │ │ │ ├── directives │ │ │ │ │ ├── BaseDirective.ts │ │ │ │ │ └── IsAuthenticatedDirective.ts │ │ │ │ ├── gql │ │ │ │ │ ├── Directives.graphql │ │ │ │ │ ├── Node.graphql │ │ │ │ │ ├── Role.graphql │ │ │ │ │ └── schema.graphql │ │ │ │ ├── plugins │ │ │ │ │ └── RequestDidStartPlugin.ts │ │ │ │ ├── schema │ │ │ │ │ ├── RootMutation.ts │ │ │ │ │ ├── RootQuery.ts │ │ │ │ │ ├── RootResolver.ts │ │ │ │ │ └── RootSubQuery.ts │ │ │ │ └── types │ │ │ │ │ └── Context.ts │ │ │ ├── common │ │ │ │ ├── BaseApplication.ts │ │ │ │ ├── IApplication.ts │ │ │ │ ├── IConfig.ts │ │ │ │ └── auth │ │ │ │ │ ├── IAuthenticationHandler.ts │ │ │ │ │ ├── models │ │ │ │ │ └── Authentication.ts │ │ │ │ │ └── utils │ │ │ │ │ └── JWTTokenUtil.ts │ │ │ └── express │ │ │ │ ├── ExpressApplication.ts │ │ │ │ ├── auth │ │ │ │ ├── JWTAuthenticationHandler.ts │ │ │ │ ├── middlewares │ │ │ │ │ ├── ApplicationAuthProvider.ts │ │ │ │ │ └── IsAuthenticated.ts │ │ │ │ ├── models │ │ │ │ │ └── Principal.ts │ │ │ │ ├── types │ │ │ │ │ └── TokenPayload.ts │ │ │ │ └── utils │ │ │ │ │ └── getHttpContext.ts │ │ │ │ └── utils │ │ │ │ └── unless.ts │ │ ├── consts │ │ │ └── variables.ts │ │ ├── errors │ │ │ ├── UserInterfaceError.ts │ │ │ ├── handlers │ │ │ │ └── errorHandler.ts │ │ │ └── models │ │ │ │ └── ErrorResponse.ts │ │ ├── logger │ │ │ ├── BaseLogger.ts │ │ │ ├── ILogger.ts │ │ │ └── WinstonLogger.ts │ │ └── swagger.json │ ├── mappings │ │ ├── UIMapper.ts │ │ └── User │ │ │ └── UserDomainToUserUI.ts │ └── models │ │ └── User.ts │ ├── index.ts │ └── shared │ ├── Authentication │ └── graphql │ │ ├── AuthenticationMutation.ts │ │ ├── gql │ │ └── Authentication.graphql │ │ └── inputs │ │ └── AuthenticateInput.ts │ └── common │ └── graphql │ ├── SharedMutation.ts │ ├── SharedQuery.ts │ └── SharedSubQuery.ts ├── stryker.conf.js ├── test ├── .mocharc.json ├── config │ ├── db │ │ ├── RollbackException.ts │ │ └── TransactionCreator.ts │ ├── helpers │ │ ├── clearTestDB.ts │ │ ├── getCurrentConnection.ts │ │ ├── getPostgresConnection.ts │ │ ├── inTransaction.ts │ │ ├── prepareAuthenticationToken.ts │ │ ├── prepareTestApp.ts │ │ ├── prepareTestDB.ts │ │ └── prepareTestTransaction.ts │ ├── mocks │ │ └── mockRepositoryConnectionName.ts │ ├── seeds │ │ ├── AuthenticationSeed.ts │ │ └── UserSeed.ts │ └── types │ │ └── RunFunction.ts └── ui │ └── routes │ └── v1 │ ├── Authentication │ └── Authentication.spec.ts │ ├── Equipment │ └── Equipment.spec.ts │ └── User │ └── User.spec.ts ├── tsconfig.base.json ├── tsconfig.json └── yarn.lock /.env.example: -------------------------------------------------------------------------------- 1 | APP_TOKEN_SECRET=abcd 2 | APP_TOKEN_LIFE=24h 3 | APOLLO_BASE_PATH=/graphql 4 | NODE_ENV=development 5 | SWAGGER_BASE_PATH=/api-docs 6 | SWAGGER_HOST=localhost:3000 7 | LOG_LEVEL=debug 8 | ORM_CONNECTION=default 9 | -------------------------------------------------------------------------------- /.env.test: -------------------------------------------------------------------------------- 1 | APP_TOKEN_SECRET=abcd 2 | APP_TOKEN_LIFE=2h 3 | NODE_ENV=test 4 | LOG_LEVEL=debug 5 | ORM_CONNECTION=onion_test 6 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | src/infrastructure/database/migrations 2 | stryker.conf.js 3 | diagram.svg 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | src/@types/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | # intellij 64 | .idea 65 | *.iml 66 | 67 | # dist 68 | dist 69 | 70 | ormconfig.js 71 | 72 | # stryker temp files 73 | .stryker-tmp 74 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v12.4.0 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "trailingComma": "es5", 5 | "printWidth": 80, 6 | } 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### RELEASE v1.1.0 2 | 3 | Release which includes following features: 4 | 5 | 1. Introduced Unit Of Work Pattern 6 | 2. Maintenance related patches and bugfixes 7 | 8 | ### RELEASE v1.0.0 9 | 10 | Release which includes following features: 11 | 12 | 1. Multiple environment setup 13 | 2. DB Agnostic setup, supports multiple datasource 14 | 3. Infrastructure -> Domain Mapping -> UI Mapping 15 | 4. Migrations, Fixtures, Seeds 16 | 5. Multiple API versions support ( REST implementation ) 17 | 6. Global Error Handling 18 | 7. Test Parallelization 19 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": ["**/*.test.ts", "**/*.spec.ts", ".git", "node_modules"], 3 | "watch": ["src"], 4 | "exec": "yarn start", 5 | "ext": "ts" 6 | } 7 | -------------------------------------------------------------------------------- /onion.diagram.database.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Melzar/onion-architecture-boilerplate/846d39a18a53e18739504979427ee87e41a705d3/onion.diagram.database.png -------------------------------------------------------------------------------- /ormconfig.sample.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { 3 | name: 'default', 4 | type: 'postgres', 5 | url: '', 6 | host: 'localhost', 7 | port: 5433, 8 | username: 'postgres', 9 | password: 'root', 10 | database: 'onion_dev', 11 | logging: true, 12 | migrationsRun: true, 13 | entities: [`${__dirname}/src/infrastructure/database/entities/**/*.ts`], 14 | migrations: [`${__dirname}/src/infrastructure/database/migrations/**/*.ts`], 15 | subscribers: [ 16 | `${__dirname}/src/infrastructure/database/subscribers/**/*.ts`, 17 | ], 18 | seeds: ['src/infrastructure/database/fixtures/seeds/*.ts'], 19 | factories: ['src/infrastructure/database/fixtures/factories/*.ts'], 20 | cli: { 21 | entitiesDir: 'src/infrastructure/database/entities', 22 | migrationsDir: 'src/infrastructure/database/migrations', 23 | subscribersDir: 'src/infrastructure/database/subscribers', 24 | }, 25 | }, 26 | { 27 | name: 'onion_test', 28 | type: 'postgres', 29 | host: 'localhost', 30 | port: 5433, 31 | username: 'postgres', 32 | password: 'root', 33 | database: 'onion_test', 34 | logging: false, 35 | entities: [`${__dirname}/src/infrastructure/database/entities/**/*.ts`], 36 | migrations: [`${__dirname}/src/infrastructure/database/migrations/**/*.ts`], 37 | }, 38 | ]; 39 | -------------------------------------------------------------------------------- /src/core/applicationServices/Authentication/IAuthenticationService.ts: -------------------------------------------------------------------------------- 1 | import { AuthenticationRequest } from 'core/applicationServices/Authentication/requests/AuthenticationRequest'; 2 | import { User } from 'core/domain/User/User'; 3 | import { SignUpRequest } from 'core/applicationServices/Authentication/requests/SignUpRequest'; 4 | 5 | export interface IAuthenticationService { 6 | signUp(request: SignUpRequest): Promise; 7 | verifyCredentials(request: AuthenticationRequest): Promise; 8 | } 9 | -------------------------------------------------------------------------------- /src/core/applicationServices/Authentication/requests/AuthenticationRequest.ts: -------------------------------------------------------------------------------- 1 | export class AuthenticationRequest { 2 | constructor( 3 | public readonly email: string, 4 | public readonly password: string 5 | ) {} 6 | } 7 | -------------------------------------------------------------------------------- /src/core/applicationServices/Authentication/requests/SignUpRequest.ts: -------------------------------------------------------------------------------- 1 | export class SignUpRequest { 2 | constructor( 3 | public readonly firstName: string, 4 | public readonly email: string, 5 | public readonly lastName: string, 6 | public readonly password: string, 7 | public readonly age: number 8 | ) {} 9 | } 10 | -------------------------------------------------------------------------------- /src/core/applicationServices/Equipment/IEquipmentService.ts: -------------------------------------------------------------------------------- 1 | import { CreateEquipmentRequest } from 'core/applicationServices/Equipment/requests/CreateEquipmentRequest'; 2 | import { Equipment } from 'core/domain/Equipment/Equipment'; 3 | import { FetchEquipmentRequest } from 'core/applicationServices/Equipment/requests/FetchEquipmentRequest'; 4 | 5 | export interface IEquipmentService { 6 | createEquipment(request: CreateEquipmentRequest): Promise; 7 | fetchEquipment(request: FetchEquipmentRequest): Promise; 8 | fetchAllEquipment(): Promise; 9 | } 10 | -------------------------------------------------------------------------------- /src/core/applicationServices/Equipment/requests/CreateEquipmentRequest.ts: -------------------------------------------------------------------------------- 1 | export class CreateEquipmentRequest { 2 | constructor( 3 | public readonly name: string, 4 | public readonly width: number, 5 | public readonly height: number, 6 | public readonly depth: number, 7 | public readonly userId: number 8 | ) {} 9 | } 10 | -------------------------------------------------------------------------------- /src/core/applicationServices/Equipment/requests/FetchEquipmentRequest.ts: -------------------------------------------------------------------------------- 1 | export class FetchEquipmentRequest { 2 | constructor(public readonly id: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/applicationServices/Portal/Warehouse/IWarehouseService.ts: -------------------------------------------------------------------------------- 1 | import { Warehouse } from 'core/domain/Warehouse/Warehouse'; 2 | 3 | export interface IWarehouseService { 4 | fetchAvailableWarehouses(): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /src/core/applicationServices/Portal/Warehouse/WarehouseService.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { DOMAIN_REPOSITORY_IDENTIFIERS } from 'core/CoreModuleSymbols'; 4 | import { IWarehouseService } from 'core/applicationServices/Portal/Warehouse/IWarehouseService'; 5 | import { IWarehouseRepository } from 'core/domainServices/Portal/Warehouse/IWarehouseRepository'; 6 | import { Warehouse } from 'core/domain/Warehouse/Warehouse'; 7 | 8 | @injectable() 9 | export class WarehouseService implements IWarehouseService { 10 | constructor( 11 | @inject(DOMAIN_REPOSITORY_IDENTIFIERS.PORTAL_WAREHOUSE_REPOSITORY) 12 | private readonly warehouseRepository: IWarehouseRepository 13 | ) {} 14 | 15 | fetchAvailableWarehouses(): Promise { 16 | return this.warehouseRepository.getAvailableWarehouses(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/core/applicationServices/Portal/WarehouseItem/IWarehouseItemService.ts: -------------------------------------------------------------------------------- 1 | import { WarehouseItem } from 'core/domain/Warehouse/WarehouseItem'; 2 | import { AddWarehouseItemRequest } from 'core/applicationServices/Portal/WarehouseItem/requests/AddWarehouseItemRequest'; 3 | 4 | export interface IWarehouseItemService { 5 | addWarehouseItem(request: AddWarehouseItemRequest): Promise; 6 | } 7 | -------------------------------------------------------------------------------- /src/core/applicationServices/Portal/WarehouseItem/requests/AddWarehouseItemRequest.ts: -------------------------------------------------------------------------------- 1 | export class AddWarehouseItemRequest { 2 | constructor( 3 | public readonly equipmentID: number, 4 | public readonly warehouseID: number, 5 | public readonly name?: string 6 | ) {} 7 | } 8 | -------------------------------------------------------------------------------- /src/core/applicationServices/Rate/IRateService.ts: -------------------------------------------------------------------------------- 1 | import { Rate } from 'core/domain/Rate/Rate'; 2 | import { FetchRateRequest } from 'core/applicationServices/Rate/requests/FetchRateRequest'; 3 | 4 | export interface IRateService { 5 | fetchRate(request: FetchRateRequest): Promise; 6 | fetchRates(): Promise; 7 | } 8 | -------------------------------------------------------------------------------- /src/core/applicationServices/Rate/RateService.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IRateRepository } from 'core/domainServices/Rate/IRateRepository'; 4 | import { IRateService } from 'core/applicationServices/Rate/IRateService'; 5 | import { FetchRateRequest } from 'core/applicationServices/Rate/requests/FetchRateRequest'; 6 | import { GetRateRepositoryRequest } from 'core/domainServices/Rate/request/GetRateRepositoryRequest'; 7 | import { Rate } from 'core/domain/Rate/Rate'; 8 | import { DOMAIN_REPOSITORY_IDENTIFIERS } from 'core/CoreModuleSymbols'; 9 | 10 | @injectable() 11 | export class RateService implements IRateService { 12 | constructor( 13 | @inject(DOMAIN_REPOSITORY_IDENTIFIERS.RATE_REPOSITORY) 14 | private readonly rateRepository: IRateRepository 15 | ) {} 16 | 17 | fetchRate({ id }: FetchRateRequest): Promise { 18 | return this.rateRepository.getRate(new GetRateRepositoryRequest(id)); 19 | } 20 | 21 | fetchRates(): Promise { 22 | return this.rateRepository.getRates(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/core/applicationServices/Rate/requests/FetchRateRequest.ts: -------------------------------------------------------------------------------- 1 | export class FetchRateRequest { 2 | constructor(public readonly id: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/applicationServices/State/IStateService.ts: -------------------------------------------------------------------------------- 1 | import { State } from 'core/domain/State/State'; 2 | import { FetchStateRequest } from 'core/applicationServices/State/requests/FetchStateRequest'; 3 | 4 | export interface IStateService { 5 | fetchState(request: FetchStateRequest): Promise; 6 | fetchStates(): Promise; 7 | } 8 | -------------------------------------------------------------------------------- /src/core/applicationServices/State/StateService.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IStateService } from 'core/applicationServices/State/IStateService'; 4 | import { IStateRepository } from 'core/domainServices/State/IStateRepository'; 5 | import { FetchStateRequest } from 'core/applicationServices/State/requests/FetchStateRequest'; 6 | import { GetStateRepositoryRequest } from 'core/domainServices/State/request/GetStateRepositoryRequest'; 7 | import { State } from 'core/domain/State/State'; 8 | import { DOMAIN_REPOSITORY_IDENTIFIERS } from 'core/CoreModuleSymbols'; 9 | 10 | @injectable() 11 | export class StateService implements IStateService { 12 | constructor( 13 | @inject(DOMAIN_REPOSITORY_IDENTIFIERS.STATE_REPOSITORY) 14 | private readonly stateRepository: IStateRepository 15 | ) {} 16 | 17 | fetchState({ id }: FetchStateRequest): Promise { 18 | return this.stateRepository.getState(new GetStateRepositoryRequest(id)); 19 | } 20 | 21 | fetchStates(): Promise { 22 | return this.stateRepository.getStates(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/core/applicationServices/State/requests/FetchStateRequest.ts: -------------------------------------------------------------------------------- 1 | export class FetchStateRequest { 2 | constructor(public readonly id: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/applicationServices/User/IUserEquipmentService.ts: -------------------------------------------------------------------------------- 1 | import { Equipment } from 'core/domain/Equipment/Equipment'; 2 | import { FetchUserEquipmentRequest } from 'core/applicationServices/User/requests/FetchUserEquipmentRequest'; 3 | import { CalculateUserEquipmentCostRequest } from 'core/applicationServices/User/requests/CalculateUserEquipmentCostRequest'; 4 | import { EquipmentCost } from 'core/domain/Equipment/EquipmentCost'; 5 | 6 | export interface IUserEquipmentService { 7 | fetchEquipment(request: FetchUserEquipmentRequest): Promise; 8 | calculateEquipmentCost( 9 | request: CalculateUserEquipmentCostRequest 10 | ): Promise; 11 | } 12 | -------------------------------------------------------------------------------- /src/core/applicationServices/User/IUserService.ts: -------------------------------------------------------------------------------- 1 | import { RemoveUserRequest } from 'core/applicationServices/User/requests/RemoveUserReuqest'; 2 | import { User } from 'core/domain/User/User'; 3 | import { FetchUserRequest } from 'core/applicationServices/User/requests/FetchUserRequest'; 4 | 5 | export interface IUserService { 6 | fetchUser(request: FetchUserRequest): Promise; 7 | fetchUsers(): Promise; 8 | removeUser(request: RemoveUserRequest): Promise; 9 | } 10 | -------------------------------------------------------------------------------- /src/core/applicationServices/User/UserService.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { 4 | DOMAIN_REPOSITORY_IDENTIFIERS, 5 | DOMAIN_UNIT_OF_WORK_IDENTIFIERS, 6 | } from 'core/CoreModuleSymbols'; 7 | 8 | import { IUserService } from 'core/applicationServices/User/IUserService'; 9 | import { IUserUnitOfWork } from 'core/domainServices/User/IUserUnitOfWork'; 10 | import { IUserRepository } from 'core/domainServices/User/IUserRepository'; 11 | 12 | import { RemoveUserRequest } from 'core/applicationServices/User/requests/RemoveUserReuqest'; 13 | import { DeleteUserUnitOfWorkRepositoryRequest } from 'core/domainServices/User/request/DeleteUserUnitOfWorkRepositoryRequest'; 14 | import { FetchUserRequest } from 'core/applicationServices/User/requests/FetchUserRequest'; 15 | import { FindUserRepositoryRequest } from 'core/domainServices/User/request/FindUserRepositoryRequest'; 16 | import { User } from 'core/domain/User/User'; 17 | 18 | @injectable() 19 | export class UserService implements IUserService { 20 | constructor( 21 | @inject(DOMAIN_UNIT_OF_WORK_IDENTIFIERS.USER_UNIT_OF_WORK) 22 | private readonly userUnitOfWork: IUserUnitOfWork, 23 | @inject(DOMAIN_REPOSITORY_IDENTIFIERS.USER_REPOSITORY) 24 | private readonly userRepository: IUserRepository 25 | ) {} 26 | 27 | removeUser({ id }: RemoveUserRequest): Promise { 28 | return this.userUnitOfWork.deleteUser( 29 | new DeleteUserUnitOfWorkRepositoryRequest(id) 30 | ); 31 | } 32 | 33 | fetchUser({ id }: FetchUserRequest): Promise { 34 | return this.userRepository.findUser(new FindUserRepositoryRequest(id)); 35 | } 36 | 37 | fetchUsers(): Promise { 38 | return this.userRepository.getUsers(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/core/applicationServices/User/requests/CalculateUserEquipmentCostRequest.ts: -------------------------------------------------------------------------------- 1 | export class CalculateUserEquipmentCostRequest { 2 | constructor( 3 | public readonly equipmentId: number, 4 | public readonly warehouseId: number, 5 | public readonly userId: number 6 | ) {} 7 | } 8 | -------------------------------------------------------------------------------- /src/core/applicationServices/User/requests/FetchUserEquipmentRequest.ts: -------------------------------------------------------------------------------- 1 | export class FetchUserEquipmentRequest { 2 | constructor(public readonly userId: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/applicationServices/User/requests/FetchUserRequest.ts: -------------------------------------------------------------------------------- 1 | export class FetchUserRequest { 2 | constructor(public readonly id: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/applicationServices/User/requests/RemoveUserReuqest.ts: -------------------------------------------------------------------------------- 1 | export class RemoveUserRequest { 2 | constructor(public readonly id: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/applicationServices/Warehouse/IWarehouseService.ts: -------------------------------------------------------------------------------- 1 | import { FetchWarehouseRequest } from 'core/applicationServices/Warehouse/requests/FetchWarehouseRequest'; 2 | import { CreateWarehouseRequest } from 'core/applicationServices/Warehouse/requests/CreateWarehouseRequest'; 3 | import { UpdateWarehouseRequest } from 'core/applicationServices/Warehouse/requests/UpdateWarehouseRequest'; 4 | import { Warehouse } from 'core/domain/Warehouse/Warehouse'; 5 | 6 | export interface IWarehouseService { 7 | fetchWarehouse: (request: FetchWarehouseRequest) => Promise; 8 | fetchWarehouses: () => Promise; 9 | createWarehouse: (request: CreateWarehouseRequest) => Promise; 10 | updateWarehouse: (request: UpdateWarehouseRequest) => Promise; 11 | } 12 | -------------------------------------------------------------------------------- /src/core/applicationServices/Warehouse/IWarehouseStateService.ts: -------------------------------------------------------------------------------- 1 | import { State } from 'core/domain/State/State'; 2 | import { FetchWarehouseStateRequest } from 'core/applicationServices/Warehouse/requests/FetchWarehouseStateRequest'; 3 | 4 | export interface IWarehouseStateService { 5 | fetchState: (request: FetchWarehouseStateRequest) => Promise; 6 | } 7 | -------------------------------------------------------------------------------- /src/core/applicationServices/Warehouse/IWarehouseWarehouseItemService.ts: -------------------------------------------------------------------------------- 1 | import { WarehouseItem } from 'core/domain/Warehouse/WarehouseItem'; 2 | import { FetchWarehouseItemsRequest } from 'core/applicationServices/WarehouseItem/requests/FetchWarehouseItemsRequest'; 3 | 4 | export interface IWarehouseWarehouseItemService { 5 | fetchWarehouseItems: ( 6 | request: FetchWarehouseItemsRequest 7 | ) => Promise; 8 | } 9 | -------------------------------------------------------------------------------- /src/core/applicationServices/Warehouse/WarehouseStateService.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { State } from 'core/domain/State/State'; 4 | import { DOMAIN_REPOSITORY_IDENTIFIERS } from 'core/CoreModuleSymbols'; 5 | import { IWarehouseStateService } from 'core/applicationServices/Warehouse/IWarehouseStateService'; 6 | import { IWarehouseStateRepository } from 'core/domainServices/Warehouse/IWarehouseStateRepository'; 7 | import { FetchWarehouseStateRequest } from 'core/applicationServices/Warehouse/requests/FetchWarehouseStateRequest'; 8 | import { GetWarehouseStateRepositoryRequest } from 'core/domainServices/Warehouse/request/GetWarehouseStateRepositoryRequest'; 9 | 10 | @injectable() 11 | export class WarehouseStateService implements IWarehouseStateService { 12 | constructor( 13 | @inject(DOMAIN_REPOSITORY_IDENTIFIERS.WAREHOUSE_STATE_REPOSITORY) 14 | private readonly warehouseStateRepository: IWarehouseStateRepository 15 | ) {} 16 | 17 | fetchState({ warehouseId }: FetchWarehouseStateRequest): Promise { 18 | return this.warehouseStateRepository.getState( 19 | new GetWarehouseStateRepositoryRequest(warehouseId) 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/core/applicationServices/Warehouse/WarehouseWarehouseItemService.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IWarehouseWarehouseItemService } from 'core/applicationServices/Warehouse/IWarehouseWarehouseItemService'; 4 | import { FetchWarehouseItemsRequest } from 'core/applicationServices/WarehouseItem/requests/FetchWarehouseItemsRequest'; 5 | import { IWarehouseWarehouseItemRepository } from 'core/domainServices/Warehouse/IWarehouseWarehouseItemRepository'; 6 | import { GetWarehouseItemsRepositoryRequest } from 'core/domainServices/WarehouseItem/requests/GetWarehouseItemsRepositoryRequest'; 7 | import { DOMAIN_REPOSITORY_IDENTIFIERS } from 'core/CoreModuleSymbols'; 8 | import { WarehouseItem } from 'core/domain/Warehouse/WarehouseItem'; 9 | 10 | @injectable() 11 | export class WarehouseWarehouseItemService 12 | implements IWarehouseWarehouseItemService { 13 | constructor( 14 | @inject(DOMAIN_REPOSITORY_IDENTIFIERS.WAREHOUSE_WAREHOUSE_ITEM_REPOSITORY) 15 | private readonly warehouseWarehouseItemRepository: IWarehouseWarehouseItemRepository 16 | ) {} 17 | 18 | fetchWarehouseItems({ 19 | warehouseId, 20 | }: FetchWarehouseItemsRequest): Promise { 21 | return this.warehouseWarehouseItemRepository.getWarehouseItems( 22 | new GetWarehouseItemsRepositoryRequest(warehouseId) 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/core/applicationServices/Warehouse/requests/CreateWarehouseRequest.ts: -------------------------------------------------------------------------------- 1 | export class CreateWarehouseRequest { 2 | constructor(public readonly name: string, public readonly stateID?: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/applicationServices/Warehouse/requests/FetchWarehouseRequest.ts: -------------------------------------------------------------------------------- 1 | export class FetchWarehouseRequest { 2 | constructor(public readonly id: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/applicationServices/Warehouse/requests/FetchWarehouseStateRequest.ts: -------------------------------------------------------------------------------- 1 | export class FetchWarehouseStateRequest { 2 | constructor(public readonly warehouseId: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/applicationServices/Warehouse/requests/UpdateWarehouseRequest.ts: -------------------------------------------------------------------------------- 1 | export class UpdateWarehouseRequest { 2 | constructor( 3 | public readonly warehouseID: number, 4 | public readonly stateID?: number, 5 | public readonly name?: string 6 | ) {} 7 | } 8 | -------------------------------------------------------------------------------- /src/core/applicationServices/WarehouseItem/IWarehouseItemEquipmentService.ts: -------------------------------------------------------------------------------- 1 | import { Equipment } from 'core/domain/Equipment/Equipment'; 2 | import { FetchWarehouseItemEquipmentRequest } from 'core/applicationServices/WarehouseItem/requests/FetchWarehouseItemEquipmentRequest'; 3 | 4 | export interface IWarehouseItemEquipmentService { 5 | fetchEquipment( 6 | request: FetchWarehouseItemEquipmentRequest 7 | ): Promise; 8 | } 9 | -------------------------------------------------------------------------------- /src/core/applicationServices/WarehouseItem/IWarehouseItemService.ts: -------------------------------------------------------------------------------- 1 | import { WarehouseItem } from 'core/domain/Warehouse/WarehouseItem'; 2 | import { FetchWarehouseItemRequest } from 'core/applicationServices/WarehouseItem/requests/FetchWarehouseItemRequest'; 3 | import { CreateWarehouseItemRequest } from 'core/applicationServices/WarehouseItem/requests/CreateWarehouseItemRequest'; 4 | import { UpdateWarehouseItemRequest } from 'core/applicationServices/WarehouseItem/requests/UpdateWarehouseItemRequest'; 5 | 6 | export interface IWarehouseItemService { 7 | fetchWarehouseItem: ( 8 | request: FetchWarehouseItemRequest 9 | ) => Promise; 10 | fetchWarehouseItems: () => Promise; 11 | createWarehouseItem: ( 12 | request: CreateWarehouseItemRequest 13 | ) => Promise; 14 | updateWarehouseItem: ( 15 | request: UpdateWarehouseItemRequest 16 | ) => Promise; 17 | } 18 | -------------------------------------------------------------------------------- /src/core/applicationServices/WarehouseItem/IWarehouseItemWarehouseService.ts: -------------------------------------------------------------------------------- 1 | import { Warehouse } from 'core/domain/Warehouse/Warehouse'; 2 | import { FetchWarehouseItemWarehouseRequest } from 'core/applicationServices/WarehouseItem/requests/FetchWarehouseItemWarehouseRequest'; 3 | 4 | export interface IWarehouseItemWarehouseService { 5 | fetchWarehouse( 6 | request: FetchWarehouseItemWarehouseRequest 7 | ): Promise; 8 | } 9 | -------------------------------------------------------------------------------- /src/core/applicationServices/WarehouseItem/WarehouseItemEquipmentService.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { DOMAIN_REPOSITORY_IDENTIFIERS } from 'core/CoreModuleSymbols'; 4 | import { IWarehouseItemEquipmentService } from 'core/applicationServices/WarehouseItem/IWarehouseItemEquipmentService'; 5 | import { IWarehouseItemEquipmentRepository } from 'core/domainServices/WarehouseItem/IWarehouseItemEquipmentRepository'; 6 | import { Equipment } from 'core/domain/Equipment/Equipment'; 7 | import { FetchWarehouseItemEquipmentRequest } from 'core/applicationServices/WarehouseItem/requests/FetchWarehouseItemEquipmentRequest'; 8 | import { GetWarehouseItemEquipmentRepositoryRequest } from 'core/domainServices/WarehouseItem/requests/GetWarehouseItemEquipmentRepositoryRequest'; 9 | 10 | @injectable() 11 | export class WarehouseItemEquipmentService 12 | implements IWarehouseItemEquipmentService { 13 | constructor( 14 | @inject(DOMAIN_REPOSITORY_IDENTIFIERS.WAREHOUSE_ITEM_EQUIPMENT_REPOSITORY) 15 | private readonly warehouseItemEquipmentRepository: IWarehouseItemEquipmentRepository 16 | ) {} 17 | 18 | fetchEquipment({ 19 | warehouseItemId, 20 | }: FetchWarehouseItemEquipmentRequest): Promise { 21 | return this.warehouseItemEquipmentRepository.getEquipment( 22 | new GetWarehouseItemEquipmentRepositoryRequest(warehouseItemId) 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/core/applicationServices/WarehouseItem/WarehouseItemWarehouseService.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { DOMAIN_REPOSITORY_IDENTIFIERS } from 'core/CoreModuleSymbols'; 4 | import { IWarehouseItemWarehouseService } from 'core/applicationServices/WarehouseItem/IWarehouseItemWarehouseService'; 5 | import { IWarehouseItemWarehouseRepository } from 'core/domainServices/WarehouseItem/IWarehouseItemWarehouseRepository'; 6 | import { Warehouse } from 'core/domain/Warehouse/Warehouse'; 7 | import { FetchWarehouseItemWarehouseRequest } from 'core/applicationServices/WarehouseItem/requests/FetchWarehouseItemWarehouseRequest'; 8 | import { GetWarehouseItemWarehouseRepositoryRequest } from 'core/domainServices/WarehouseItem/requests/GetWarehouseItemWarehouseRepositoryRequest'; 9 | 10 | @injectable() 11 | export class WarehouseItemWarehouseService 12 | implements IWarehouseItemWarehouseService { 13 | constructor( 14 | @inject(DOMAIN_REPOSITORY_IDENTIFIERS.WAREHOUSE_ITEM_WAREHOUSE_REPOSITORY) 15 | private readonly warehouseItemWarehouseRepository: IWarehouseItemWarehouseRepository 16 | ) {} 17 | 18 | fetchWarehouse({ 19 | warehouseItemId, 20 | }: FetchWarehouseItemWarehouseRequest): Promise { 21 | return this.warehouseItemWarehouseRepository.getWarehouse( 22 | new GetWarehouseItemWarehouseRepositoryRequest(warehouseItemId) 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/core/applicationServices/WarehouseItem/requests/CreateWarehouseItemRequest.ts: -------------------------------------------------------------------------------- 1 | export class CreateWarehouseItemRequest { 2 | constructor( 3 | public readonly name: string, 4 | public readonly warehouseID: number, 5 | public readonly equipmentID: number, 6 | public readonly cost?: number 7 | ) {} 8 | } 9 | -------------------------------------------------------------------------------- /src/core/applicationServices/WarehouseItem/requests/FetchWarehouseItemEquipmentRequest.ts: -------------------------------------------------------------------------------- 1 | export class FetchWarehouseItemEquipmentRequest { 2 | constructor(public readonly warehouseItemId: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/applicationServices/WarehouseItem/requests/FetchWarehouseItemRequest.ts: -------------------------------------------------------------------------------- 1 | export class FetchWarehouseItemRequest { 2 | constructor(public readonly id: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/applicationServices/WarehouseItem/requests/FetchWarehouseItemWarehouseRequest.ts: -------------------------------------------------------------------------------- 1 | export class FetchWarehouseItemWarehouseRequest { 2 | constructor(public readonly warehouseItemId: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/applicationServices/WarehouseItem/requests/FetchWarehouseItemsRequest.ts: -------------------------------------------------------------------------------- 1 | export class FetchWarehouseItemsRequest { 2 | constructor(public readonly warehouseId: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/applicationServices/WarehouseItem/requests/UpdateWarehouseItemRequest.ts: -------------------------------------------------------------------------------- 1 | export class UpdateWarehouseItemRequest { 2 | constructor( 3 | public readonly id: number, 4 | public readonly name?: string, 5 | public readonly cost?: number, 6 | public readonly warehouseID?: number, 7 | public readonly equipmentID?: number 8 | ) {} 9 | } 10 | -------------------------------------------------------------------------------- /src/core/applicationServices/common/Equipment/interactors/requests/CalculateEquipmentCostInteractorRequest.ts: -------------------------------------------------------------------------------- 1 | export class CalculateEquipmentCostInteractorRequest { 2 | constructor( 3 | public readonly warehouseId: number, 4 | public readonly equipmentId: number 5 | ) {} 6 | } 7 | -------------------------------------------------------------------------------- /src/core/applicationServices/common/IInteractor.ts: -------------------------------------------------------------------------------- 1 | export interface IInteractor { 2 | execute(...args: A[]): Promise | R; 3 | } 4 | -------------------------------------------------------------------------------- /src/core/common/errors/BaseError.ts: -------------------------------------------------------------------------------- 1 | export class BaseError implements Error { 2 | constructor( 3 | public readonly code?: string, 4 | public readonly message: string = '', 5 | public readonly name: string = '' 6 | ) {} 7 | } 8 | -------------------------------------------------------------------------------- /src/core/common/errors/CoreError.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'core/common/errors/BaseError'; 2 | 3 | export class CoreError extends BaseError {} 4 | -------------------------------------------------------------------------------- /src/core/common/errors/CoreErrors.ts: -------------------------------------------------------------------------------- 1 | export enum CoreErrors {} 2 | -------------------------------------------------------------------------------- /src/core/common/mapper/IMapping.ts: -------------------------------------------------------------------------------- 1 | import { Mapper } from '@wufe/mapper'; 2 | 3 | export interface IMapping { 4 | configureMapping(mapper: Mapper): void; 5 | } 6 | -------------------------------------------------------------------------------- /src/core/domain/Authentication/Authentication.ts: -------------------------------------------------------------------------------- 1 | export class Authentication { 2 | constructor(public readonly token: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domain/Equipment/Equipment.ts: -------------------------------------------------------------------------------- 1 | export class Equipment { 2 | constructor( 3 | public readonly id: number, 4 | public readonly width: number, 5 | public readonly height: number, 6 | public readonly depth: number, 7 | public readonly name: string 8 | ) {} 9 | } 10 | -------------------------------------------------------------------------------- /src/core/domain/Equipment/EquipmentCost.ts: -------------------------------------------------------------------------------- 1 | export class EquipmentCost { 2 | constructor(public readonly cost: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domain/Rate/Rate.ts: -------------------------------------------------------------------------------- 1 | export class Rate { 2 | constructor(public readonly id: number, public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domain/Role/Role.ts: -------------------------------------------------------------------------------- 1 | export class Role { 2 | constructor(public readonly id: string, public readonly name: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domain/State/State.ts: -------------------------------------------------------------------------------- 1 | import { Rate } from 'core/domain/Rate/Rate'; 2 | import { Warehouse } from 'core/domain/Warehouse/Warehouse'; 3 | 4 | export class State { 5 | constructor( 6 | public readonly id: number, 7 | public readonly name: string, 8 | public readonly rates: Rate[], 9 | public readonly warehouses: Warehouse[] 10 | ) {} 11 | } 12 | -------------------------------------------------------------------------------- /src/core/domain/User/User.ts: -------------------------------------------------------------------------------- 1 | export class User { 2 | constructor( 3 | public readonly id: number, 4 | public readonly firstName: string, 5 | public readonly email: string, 6 | public readonly role: string, 7 | public readonly lastName: string, 8 | public readonly password: string, 9 | public readonly age: number 10 | ) {} 11 | } 12 | -------------------------------------------------------------------------------- /src/core/domain/User/UserRole.ts: -------------------------------------------------------------------------------- 1 | export enum USER_ROLE { 2 | ADMIN = 'ADMIN', 3 | MEMBER = 'MEMBER', 4 | } 5 | -------------------------------------------------------------------------------- /src/core/domain/Warehouse/Warehouse.ts: -------------------------------------------------------------------------------- 1 | import { State } from 'core/domain/State/State'; 2 | import { WarehouseItem } from 'core/domain/Warehouse/WarehouseItem'; 3 | 4 | export class Warehouse { 5 | constructor( 6 | public readonly id: number, 7 | public readonly widthCost: number, 8 | public readonly heightCost: number, 9 | public readonly depthCost: number, 10 | public readonly capacityWidth: number, 11 | public readonly capacityHeight: number, 12 | public readonly capacityDepth: number, 13 | public readonly capacityWidthLoad: number, 14 | public readonly capacityHeightLoad: number, 15 | public readonly capacityDepthLoad: number, 16 | public readonly available: boolean, 17 | public readonly name: string, 18 | public readonly state: State, 19 | public readonly warehouseItems: WarehouseItem[] 20 | ) {} 21 | } 22 | -------------------------------------------------------------------------------- /src/core/domain/Warehouse/WarehouseItem.ts: -------------------------------------------------------------------------------- 1 | import { Equipment } from 'core/domain/Equipment/Equipment'; 2 | import { Warehouse } from 'core/domain/Warehouse/Warehouse'; 3 | 4 | export class WarehouseItem { 5 | constructor( 6 | public readonly id: number, 7 | public readonly name: string, 8 | public readonly cost: number, 9 | public readonly warehouse: Warehouse, 10 | public readonly equipment: Equipment 11 | ) {} 12 | } 13 | -------------------------------------------------------------------------------- /src/core/domainServices/Equipment/IEquipmentRepository.ts: -------------------------------------------------------------------------------- 1 | import { Equipment } from 'core/domain/Equipment/Equipment'; 2 | import { FindEquipmentRepositoryRequest } from 'core/domainServices/Equipment/request/FindEquipmentRepositoryRequest'; 3 | import { AddEquipmentRepositoryRequest } from 'core/domainServices/Equipment/request/AddEquipmentRepositoryRequest'; 4 | 5 | export interface IEquipmentRepository { 6 | addEquipment(request: AddEquipmentRepositoryRequest): Promise; 7 | getEquipment(): Promise; 8 | findEquipment(request: FindEquipmentRepositoryRequest): Promise; 9 | } 10 | -------------------------------------------------------------------------------- /src/core/domainServices/Equipment/IEquipmentUnitOfWork.ts: -------------------------------------------------------------------------------- 1 | import { AddEquipmentUnitOfWorkRepositoryRequest } from 'core/domainServices/Equipment/request/AddEquipmentUnitOfWorkRepositoryRequest'; 2 | import { Equipment } from 'core/domain/Equipment/Equipment'; 3 | 4 | export interface IEquipmentUnitOfWork { 5 | addEquipment( 6 | request: AddEquipmentUnitOfWorkRepositoryRequest 7 | ): Promise; 8 | } 9 | -------------------------------------------------------------------------------- /src/core/domainServices/Equipment/request/AddEquipmentRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class AddEquipmentRepositoryRequest { 2 | constructor( 3 | public readonly name: string, 4 | public readonly width: number, 5 | public readonly height: number, 6 | public readonly depth: number, 7 | public readonly userId: number 8 | ) {} 9 | } 10 | -------------------------------------------------------------------------------- /src/core/domainServices/Equipment/request/AddEquipmentUnitOfWorkRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class AddEquipmentUnitOfWorkRepositoryRequest { 2 | constructor( 3 | public readonly name: string, 4 | public readonly width: number, 5 | public readonly height: number, 6 | public readonly depth: number, 7 | public readonly userId: number 8 | ) {} 9 | } 10 | -------------------------------------------------------------------------------- /src/core/domainServices/Equipment/request/FindEquipmentRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class FindEquipmentRepositoryRequest { 2 | constructor(public readonly id: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domainServices/Portal/Warehouse/IWarehouseRepository.ts: -------------------------------------------------------------------------------- 1 | import { Warehouse } from 'core/domain/Warehouse/Warehouse'; 2 | 3 | export interface IWarehouseRepository { 4 | getAvailableWarehouses(): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /src/core/domainServices/Portal/WarehouseItem/IWarehouseItemRepository.ts: -------------------------------------------------------------------------------- 1 | import { WarehouseItem } from 'core/domain/Warehouse/WarehouseItem'; 2 | import { AddWarehouseItemRepositoryRequest } from 'core/domainServices/Portal/WarehouseItem/requests/AddWarehouseItemRepositoryRequest'; 3 | 4 | export interface IWarehouseItemRepository { 5 | addWarehouseItem( 6 | request: AddWarehouseItemRepositoryRequest 7 | ): Promise; 8 | } 9 | -------------------------------------------------------------------------------- /src/core/domainServices/Portal/WarehouseItem/requests/AddWarehouseItemRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class AddWarehouseItemRepositoryRequest { 2 | constructor( 3 | public readonly equipmentID: number, 4 | public readonly warehouseID: number, 5 | public readonly cost: number, 6 | public readonly name?: string 7 | ) {} 8 | } 9 | -------------------------------------------------------------------------------- /src/core/domainServices/Rate/IRateRepository.ts: -------------------------------------------------------------------------------- 1 | import { GetRateRepositoryRequest } from 'core/domainServices/Rate/request/GetRateRepositoryRequest'; 2 | import { Rate } from 'core/domain/Rate/Rate'; 3 | 4 | export interface IRateRepository { 5 | getRate(request: GetRateRepositoryRequest): Promise; 6 | getRates(): Promise; 7 | } 8 | -------------------------------------------------------------------------------- /src/core/domainServices/Rate/request/GetRateRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class GetRateRepositoryRequest { 2 | constructor(public readonly id: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domainServices/Role/IRoleRepository.ts: -------------------------------------------------------------------------------- 1 | import { Role } from 'core/domain/Role/Role'; 2 | import { FindRoleRepositoryRequest } from 'core/domainServices/Role/request/FindRoleRepositoryRequest'; 3 | import { FindRoleByNameRepositoryRequest } from 'core/domainServices/Role/request/FindRoleByNameRepositoryRequest'; 4 | 5 | export interface IRoleRepository { 6 | findRole(request: FindRoleRepositoryRequest): Promise; 7 | findRoleByName(request: FindRoleByNameRepositoryRequest): Promise; 8 | } 9 | -------------------------------------------------------------------------------- /src/core/domainServices/Role/request/FindRoleByNameRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class FindRoleByNameRepositoryRequest { 2 | constructor(public readonly name: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domainServices/Role/request/FindRoleRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class FindRoleRepositoryRequest { 2 | constructor(public readonly id: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domainServices/State/IStateRepository.ts: -------------------------------------------------------------------------------- 1 | import { GetStateRepositoryRequest } from 'core/domainServices/State/request/GetStateRepositoryRequest'; 2 | import { State } from 'core/domain/State/State'; 3 | 4 | export interface IStateRepository { 5 | getState(request: GetStateRepositoryRequest): Promise; 6 | getStates(): Promise; 7 | } 8 | -------------------------------------------------------------------------------- /src/core/domainServices/State/request/GetStateRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class GetStateRepositoryRequest { 2 | constructor(public readonly id: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domainServices/User/IUserEquipmentRepository.ts: -------------------------------------------------------------------------------- 1 | import { GetUserEquipmentRepositoryRequest } from 'core/domainServices/User/request/GetUserEquipmentRepositoryRequest'; 2 | import { FindUserEquipmentRepositoryRequest } from 'core/domainServices/User/request/FindUserEquipmentRepositoryRequest'; 3 | import { Equipment } from 'core/domain/Equipment/Equipment'; 4 | 5 | export interface IUserEquipmentRepository { 6 | getEquipment(request: GetUserEquipmentRepositoryRequest): Promise; 7 | findEquipment( 8 | request: FindUserEquipmentRepositoryRequest 9 | ): Promise; 10 | } 11 | -------------------------------------------------------------------------------- /src/core/domainServices/User/IUserRepository.ts: -------------------------------------------------------------------------------- 1 | import { User } from 'core/domain/User/User'; 2 | import { FindUserByEmailRepositoryRequest } from 'core/domainServices/User/request/FindUserByEmailRepositoryRequest'; 3 | import { FindUserRepositoryRequest } from 'core/domainServices/User/request/FindUserRepositoryRequest'; 4 | import { AddUserRepositoryRequest } from 'core/domainServices/User/request/AddUserRepositoryRequest'; 5 | 6 | export interface IUserRepository { 7 | addUser(request: AddUserRepositoryRequest): Promise; 8 | findUser(request: FindUserRepositoryRequest): Promise; 9 | findUserByEmail(request: FindUserByEmailRepositoryRequest): Promise; 10 | getUsers(): Promise; 11 | } 12 | -------------------------------------------------------------------------------- /src/core/domainServices/User/IUserUnitOfWork.ts: -------------------------------------------------------------------------------- 1 | import { User } from 'core/domain/User/User'; 2 | import { AddUserUnitOfWorkRepositoryRequest } from 'core/domainServices/User/request/AddUserUnitOfWorkRepositoryRequest'; 3 | import { DeleteUserUnitOfWorkRepositoryRequest } from 'core/domainServices/User/request/DeleteUserUnitOfWorkRepositoryRequest'; 4 | 5 | export interface IUserUnitOfWork { 6 | addUser(request: AddUserUnitOfWorkRepositoryRequest): Promise; 7 | deleteUser(request: DeleteUserUnitOfWorkRepositoryRequest): Promise; 8 | } 9 | -------------------------------------------------------------------------------- /src/core/domainServices/User/request/AddUserRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class AddUserRepositoryRequest { 2 | constructor( 3 | public readonly firstName: string, 4 | public readonly email: string, 5 | public readonly lastName: string, 6 | public readonly password: string, 7 | public readonly age: number, 8 | public readonly roleId: number 9 | ) {} 10 | } 11 | -------------------------------------------------------------------------------- /src/core/domainServices/User/request/AddUserUnitOfWorkRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class AddUserUnitOfWorkRepositoryRequest { 2 | constructor( 3 | public readonly firstName: string, 4 | public readonly email: string, 5 | public readonly lastName: string, 6 | public readonly password: string, 7 | public readonly age: number 8 | ) {} 9 | } 10 | -------------------------------------------------------------------------------- /src/core/domainServices/User/request/DeleteUserRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class DeleteUserRepositoryRequest { 2 | constructor(public readonly id: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domainServices/User/request/DeleteUserUnitOfWorkRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class DeleteUserUnitOfWorkRepositoryRequest { 2 | constructor(public readonly id: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domainServices/User/request/FindUserByEmailRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class FindUserByEmailRepositoryRequest { 2 | constructor(public readonly email: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domainServices/User/request/FindUserEquipmentRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class FindUserEquipmentRepositoryRequest { 2 | constructor(public readonly userId: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domainServices/User/request/FindUserRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class FindUserRepositoryRequest { 2 | constructor(public readonly id: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domainServices/User/request/GetUserEquipmentRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class GetUserEquipmentRepositoryRequest { 2 | constructor( 3 | public readonly userId: number, 4 | public readonly equipmentId: number 5 | ) {} 6 | } 7 | -------------------------------------------------------------------------------- /src/core/domainServices/Warehouse/IWarehouseRepository.ts: -------------------------------------------------------------------------------- 1 | import { Warehouse } from 'core/domain/Warehouse/Warehouse'; 2 | import { GetWarehouseRepositoryRequest } from 'core/domainServices/Warehouse/request/GetWarehouseRepositoryRequest'; 3 | import { CreateWarehouseRepositoryRequest } from 'core/domainServices/Warehouse/request/CreateWarehouseRepositoryRequest'; 4 | import { UpdateWarehouseRepositoryRequest } from 'core/domainServices/Warehouse/request/UpdateWarehouseRepositoryRequest'; 5 | 6 | export interface IWarehouseRepository { 7 | getWarehouse(request: GetWarehouseRepositoryRequest): Promise; 8 | getWarehouses(): Promise; 9 | createWarehouse( 10 | request: CreateWarehouseRepositoryRequest 11 | ): Promise; 12 | updateWarehouse( 13 | request: UpdateWarehouseRepositoryRequest 14 | ): Promise; 15 | } 16 | -------------------------------------------------------------------------------- /src/core/domainServices/Warehouse/IWarehouseStateRepository.ts: -------------------------------------------------------------------------------- 1 | import { State } from 'core/domain/State/State'; 2 | import { GetWarehouseStateRepositoryRequest } from 'core/domainServices/Warehouse/request/GetWarehouseStateRepositoryRequest'; 3 | 4 | export interface IWarehouseStateRepository { 5 | getState: (request: GetWarehouseStateRepositoryRequest) => Promise; 6 | } 7 | -------------------------------------------------------------------------------- /src/core/domainServices/Warehouse/IWarehouseWarehouseItemRepository.ts: -------------------------------------------------------------------------------- 1 | import { WarehouseItem } from 'core/domain/Warehouse/WarehouseItem'; 2 | import { GetWarehouseItemsRepositoryRequest } from 'core/domainServices/WarehouseItem/requests/GetWarehouseItemsRepositoryRequest'; 3 | 4 | export interface IWarehouseWarehouseItemRepository { 5 | getWarehouseItems: ( 6 | request: GetWarehouseItemsRepositoryRequest 7 | ) => Promise; 8 | } 9 | -------------------------------------------------------------------------------- /src/core/domainServices/Warehouse/request/CreateWarehouseRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class CreateWarehouseRepositoryRequest { 2 | constructor(public readonly name: string, public readonly stateID?: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domainServices/Warehouse/request/GetWarehouseRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class GetWarehouseRepositoryRequest { 2 | constructor(public readonly id: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domainServices/Warehouse/request/GetWarehouseStateRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class GetWarehouseStateRepositoryRequest { 2 | constructor(public readonly warehouseId: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domainServices/Warehouse/request/UpdateWarehouseRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class UpdateWarehouseRepositoryRequest { 2 | constructor( 3 | public readonly warehouseID: number, 4 | public readonly stateID?: number, 5 | public readonly name?: string 6 | ) {} 7 | } 8 | -------------------------------------------------------------------------------- /src/core/domainServices/WarehouseItem/IWarehouseItemEquipmentRepository.ts: -------------------------------------------------------------------------------- 1 | import { GetWarehouseItemEquipmentRepositoryRequest } from 'core/domainServices/WarehouseItem/requests/GetWarehouseItemEquipmentRepositoryRequest'; 2 | import { Equipment } from 'core/domain/Equipment/Equipment'; 3 | 4 | export interface IWarehouseItemEquipmentRepository { 5 | getEquipment( 6 | request: GetWarehouseItemEquipmentRepositoryRequest 7 | ): Promise; 8 | } 9 | -------------------------------------------------------------------------------- /src/core/domainServices/WarehouseItem/IWarehouseItemRepository.ts: -------------------------------------------------------------------------------- 1 | import { WarehouseItem } from 'core/domain/Warehouse/WarehouseItem'; 2 | import { GetWarehouseItemRepositoryRequest } from 'core/domainServices/WarehouseItem/requests/GetWarehouseItemRepositoryRequest'; 3 | import { CreateWarehouseItemRepositoryRequest } from 'core/domainServices/WarehouseItem/requests/CreateWarehouseItemRepositoryRequest'; 4 | import { UpdateWarehouseItemRepositoryRequest } from 'core/domainServices/WarehouseItem/requests/UpdateWarehouseItemRepositoryRequest'; 5 | 6 | export interface IWarehouseItemRepository { 7 | getWarehouseItem( 8 | request: GetWarehouseItemRepositoryRequest 9 | ): Promise; 10 | getWarehouseItems(): Promise; 11 | createWarehouseItem( 12 | request: CreateWarehouseItemRepositoryRequest 13 | ): Promise; 14 | updateWarehouseItem( 15 | request: UpdateWarehouseItemRepositoryRequest 16 | ): Promise; 17 | } 18 | -------------------------------------------------------------------------------- /src/core/domainServices/WarehouseItem/IWarehouseItemWarehouseRepository.ts: -------------------------------------------------------------------------------- 1 | import { Warehouse } from 'core/domain/Warehouse/Warehouse'; 2 | import { GetWarehouseItemWarehouseRepositoryRequest } from 'core/domainServices/WarehouseItem/requests/GetWarehouseItemWarehouseRepositoryRequest'; 3 | 4 | export interface IWarehouseItemWarehouseRepository { 5 | getWarehouse( 6 | request: GetWarehouseItemWarehouseRepositoryRequest 7 | ): Promise; 8 | } 9 | -------------------------------------------------------------------------------- /src/core/domainServices/WarehouseItem/requests/CreateWarehouseItemRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class CreateWarehouseItemRepositoryRequest { 2 | constructor( 3 | public readonly name: string, 4 | public readonly cost: number, 5 | public readonly warehouseID: number, 6 | public readonly equipmentID: number 7 | ) {} 8 | } 9 | -------------------------------------------------------------------------------- /src/core/domainServices/WarehouseItem/requests/GetWarehouseItemEquipmentRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class GetWarehouseItemEquipmentRepositoryRequest { 2 | constructor(public readonly warehouseItemID: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domainServices/WarehouseItem/requests/GetWarehouseItemRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class GetWarehouseItemRepositoryRequest { 2 | constructor(public readonly id: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domainServices/WarehouseItem/requests/GetWarehouseItemWarehouseRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class GetWarehouseItemWarehouseRepositoryRequest { 2 | constructor(public readonly warehouseItemId: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domainServices/WarehouseItem/requests/GetWarehouseItemsRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class GetWarehouseItemsRepositoryRequest { 2 | constructor(public readonly warehouseId: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/core/domainServices/WarehouseItem/requests/UpdateWarehouseItemRepositoryRequest.ts: -------------------------------------------------------------------------------- 1 | export class UpdateWarehouseItemRepositoryRequest { 2 | constructor( 3 | public readonly id: number, 4 | public readonly name?: string, 5 | public readonly cost?: number, 6 | public readonly warehouseID?: number, 7 | public readonly equipmentID?: number 8 | ) {} 9 | } 10 | -------------------------------------------------------------------------------- /src/dependency/Administration/Rate/RateModule.ts: -------------------------------------------------------------------------------- 1 | import { interfaces } from 'inversify'; 2 | 3 | import { BaseModule } from 'dependency/BaseModule'; 4 | import { RateRepository } from 'infrastructure/database/repository/Rate/RateRepository'; 5 | import { 6 | DOMAIN_APPLICATION_SERVICE_IDENTIFIERS, 7 | DOMAIN_REPOSITORY_IDENTIFIERS, 8 | } from 'core/CoreModuleSymbols'; 9 | import { IRateRepository } from 'core/domainServices/Rate/IRateRepository'; 10 | import { RateService } from 'core/applicationServices/Rate/RateService'; 11 | import { IRateService } from 'core/applicationServices/Rate/IRateService'; 12 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 13 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 14 | import { RateQuery } from 'ui/Administration/Rate/graphql/RateQuery'; 15 | 16 | export class RateModule extends BaseModule { 17 | constructor() { 18 | super((bind: interfaces.Bind): void => { 19 | this.init(bind); 20 | }); 21 | } 22 | 23 | init(bind: interfaces.Bind): void { 24 | this.provideRateRepository(bind); 25 | 26 | this.provideRateService(bind); 27 | 28 | this.provideRateQuery(bind); 29 | } 30 | 31 | private provideRateRepository(bind: interfaces.Bind): void { 32 | bind(DOMAIN_REPOSITORY_IDENTIFIERS.RATE_REPOSITORY).to( 33 | RateRepository 34 | ); 35 | } 36 | 37 | private provideRateService(bind: interfaces.Bind): void { 38 | bind(DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.RATE_SERVICE).to( 39 | RateService 40 | ); 41 | } 42 | 43 | private provideRateQuery(bind: interfaces.Bind): void { 44 | bind(UI_SCHEMA_IDENTIFIERS.RATE_QUERIES).to(RateQuery); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/dependency/Administration/Role/RoleModule.ts: -------------------------------------------------------------------------------- 1 | import { interfaces } from 'inversify'; 2 | 3 | import { BaseModule } from 'dependency/BaseModule'; 4 | import { RoleRepository } from 'infrastructure/database/repository/Role/RoleRepository'; 5 | import { IRoleRepository } from 'core/domainServices/Role/IRoleRepository'; 6 | import { DOMAIN_REPOSITORY_IDENTIFIERS } from 'core/CoreModuleSymbols'; 7 | 8 | export class RoleModule extends BaseModule { 9 | constructor() { 10 | super((bind: interfaces.Bind): void => { 11 | this.init(bind); 12 | }); 13 | } 14 | 15 | init(bind: interfaces.Bind): void { 16 | this.provideRoleRepository(bind); 17 | } 18 | 19 | private provideRoleRepository(bind: interfaces.Bind): void { 20 | bind(DOMAIN_REPOSITORY_IDENTIFIERS.ROLE_REPOSITORY).to( 21 | RoleRepository 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/dependency/Administration/State/StateModule.ts: -------------------------------------------------------------------------------- 1 | import { interfaces } from 'inversify'; 2 | 3 | import { BaseModule } from 'dependency/BaseModule'; 4 | import { StateRepository } from 'infrastructure/database/repository/State/StateRepository'; 5 | import { 6 | DOMAIN_APPLICATION_SERVICE_IDENTIFIERS, 7 | DOMAIN_REPOSITORY_IDENTIFIERS, 8 | } from 'core/CoreModuleSymbols'; 9 | import { IStateRepository } from 'core/domainServices/State/IStateRepository'; 10 | import { StateService } from 'core/applicationServices/State/StateService'; 11 | import { IStateService } from 'core/applicationServices/State/IStateService'; 12 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 13 | import { StateQuery } from 'ui/Administration/State/graphql/StateQuery'; 14 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 15 | 16 | export class StateModule extends BaseModule { 17 | constructor() { 18 | super((bind: interfaces.Bind): void => { 19 | this.init(bind); 20 | }); 21 | } 22 | 23 | init(bind: interfaces.Bind): void { 24 | this.provideStateRepository(bind); 25 | 26 | this.provideStateService(bind); 27 | 28 | this.provideStateQuery(bind); 29 | } 30 | 31 | private provideStateRepository(bind: interfaces.Bind): void { 32 | bind(DOMAIN_REPOSITORY_IDENTIFIERS.STATE_REPOSITORY).to( 33 | StateRepository 34 | ); 35 | } 36 | 37 | private provideStateService(bind: interfaces.Bind): void { 38 | bind( 39 | DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.STATE_SERVICE 40 | ).to(StateService); 41 | } 42 | 43 | private provideStateQuery(bind: interfaces.Bind): void { 44 | bind(UI_SCHEMA_IDENTIFIERS.STATE_QUERIES).to(StateQuery); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/dependency/Administration/User/UserModule.ts: -------------------------------------------------------------------------------- 1 | import { interfaces } from 'inversify'; 2 | 3 | import { BaseModule } from 'dependency/BaseModule'; 4 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { UserQuery } from 'ui/Administration/User/graphql/UserQuery'; 7 | import { UserMutation } from 'ui/Administration/User/graphql/UserMutation'; 8 | import { UserSubQuery } from 'ui/Administration/User/graphql/UserSubQuery'; 9 | 10 | export class UserModule extends BaseModule { 11 | constructor() { 12 | super((bind: interfaces.Bind): void => { 13 | this.init(bind); 14 | }); 15 | } 16 | 17 | public init(bind: interfaces.Bind): void { 18 | this.provideUserQuery(bind); 19 | this.provideUserMutation(bind); 20 | this.provideUserSubquery(bind); 21 | } 22 | 23 | private provideUserQuery(bind: interfaces.Bind): void { 24 | bind(UI_SCHEMA_IDENTIFIERS.ADMINISTRATION_USER_QUERIES).to( 25 | UserQuery 26 | ); 27 | } 28 | 29 | private provideUserMutation(bind: interfaces.Bind): void { 30 | bind(UI_SCHEMA_IDENTIFIERS.ADMINISTRATION_USER_MUTATIONS).to( 31 | UserMutation 32 | ); 33 | } 34 | 35 | private provideUserSubquery(bind: interfaces.Bind): void { 36 | bind(UI_SCHEMA_IDENTIFIERS.ADMINISTRATION_USER_SUBQUERIES).to( 37 | UserSubQuery 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/dependency/Administration/common/AdministrationModule.ts: -------------------------------------------------------------------------------- 1 | import { interfaces } from 'inversify'; 2 | 3 | import { BaseModule } from 'dependency/BaseModule'; 4 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 5 | import { AdministrationQuery } from 'ui/Administration/common/graphql/AdministrationQuery'; 6 | import { AdministrationMutation } from 'ui/Administration/common/graphql/AdministrationMutation'; 7 | import { AdministrationSubQuery } from 'ui/Administration/common/graphql/AdministrationSubQuery'; 8 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 9 | 10 | export class AdministrationModule extends BaseModule { 11 | constructor() { 12 | super((bind: interfaces.Bind): void => { 13 | this.init(bind); 14 | }); 15 | } 16 | 17 | init(bind: interfaces.Bind): void { 18 | this.provideAdministrationQuery(bind); 19 | this.provideAdministrationMutation(bind); 20 | this.provideAdministrationSubQuery(bind); 21 | } 22 | 23 | private provideAdministrationQuery(bind: interfaces.Bind): void { 24 | bind(UI_SCHEMA_IDENTIFIERS.ADMINISTRATION_QUERIES).to( 25 | AdministrationQuery 26 | ); 27 | } 28 | 29 | private provideAdministrationMutation(bind: interfaces.Bind): void { 30 | bind(UI_SCHEMA_IDENTIFIERS.ADMINISTRATION_MUTATIONS).to( 31 | AdministrationMutation 32 | ); 33 | } 34 | 35 | private provideAdministrationSubQuery(bind: interfaces.Bind): void { 36 | bind(UI_SCHEMA_IDENTIFIERS.ADMINISTRATION_SUBQUERIES).to( 37 | AdministrationSubQuery 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/dependency/BaseContainer.ts: -------------------------------------------------------------------------------- 1 | import { Container } from 'inversify'; 2 | 3 | export abstract class BaseContainer extends Container { 4 | public abstract init(): void; 5 | } 6 | -------------------------------------------------------------------------------- /src/dependency/BaseModule.ts: -------------------------------------------------------------------------------- 1 | import { ContainerModule, interfaces } from 'inversify'; 2 | 3 | export abstract class BaseModule extends ContainerModule { 4 | public abstract init(bind: interfaces.Bind): void; 5 | } 6 | -------------------------------------------------------------------------------- /src/dependency/Portal/Equipment/EquipmentModule.ts: -------------------------------------------------------------------------------- 1 | import { interfaces } from 'inversify'; 2 | 3 | import { BaseModule } from 'dependency/BaseModule'; 4 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 5 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 6 | import { EquipmentQuery } from 'ui/Portal/Equipment/graphql/EquipmentQueries'; 7 | import { IUserEquipmentService } from 'core/applicationServices/User/IUserEquipmentService'; 8 | import { 9 | DOMAIN_APPLICATION_SERVICE_IDENTIFIERS, 10 | DOMAIN_REPOSITORY_IDENTIFIERS, 11 | } from 'core/CoreModuleSymbols'; 12 | import { UserEquipmentService } from 'core/applicationServices/User/UserEquipmentService'; 13 | import { UserEquipmentRepository } from 'infrastructure/database/repository/User/UserEquipmentRepository'; 14 | import { IUserEquipmentRepository } from 'core/domainServices/User/IUserEquipmentRepository'; 15 | 16 | export class EquipmentModule extends BaseModule { 17 | constructor() { 18 | super((bind: interfaces.Bind): void => { 19 | this.init(bind); 20 | }); 21 | } 22 | 23 | public init(bind: interfaces.Bind): void { 24 | this.provideUserEquipmentRepository(bind); 25 | this.provideUserEquipmentService(bind); 26 | 27 | this.provideEquipmentQuery(bind); 28 | } 29 | 30 | private provideUserEquipmentRepository(bind: interfaces.Bind): void { 31 | bind( 32 | DOMAIN_REPOSITORY_IDENTIFIERS.USER_EQUIPMENT_REPOSITORY 33 | ).to(UserEquipmentRepository); 34 | } 35 | 36 | private provideUserEquipmentService(bind: interfaces.Bind): void { 37 | bind( 38 | DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.USER_EQUIPMENT_SERVICE 39 | ).to(UserEquipmentService); 40 | } 41 | 42 | private provideEquipmentQuery(bind: interfaces.Bind): void { 43 | bind(UI_SCHEMA_IDENTIFIERS.PORTAL_EQUIPMENT_QUERIES).to( 44 | EquipmentQuery 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/dependency/Portal/User/UserModule.ts: -------------------------------------------------------------------------------- 1 | import { interfaces } from 'inversify'; 2 | 3 | import { BaseModule } from 'dependency/BaseModule'; 4 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 5 | import { UserQuery } from 'ui/Portal/User/graphql/UserQuery'; 6 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 7 | 8 | export class UserModule extends BaseModule { 9 | constructor() { 10 | super((bind: interfaces.Bind): void => { 11 | this.init(bind); 12 | }); 13 | } 14 | 15 | public init(bind: interfaces.Bind): void { 16 | this.provideUserQuery(bind); 17 | } 18 | 19 | private provideUserQuery(bind: interfaces.Bind): void { 20 | bind(UI_SCHEMA_IDENTIFIERS.PORTAL_USER_QUERIES).to(UserQuery); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/dependency/Portal/Warehouse/WarehouseModule.ts: -------------------------------------------------------------------------------- 1 | import { interfaces } from 'inversify'; 2 | 3 | import { IWarehouseRepository } from 'core/domainServices/Portal/Warehouse/IWarehouseRepository'; 4 | import { IWarehouseService } from 'core/applicationServices/Portal/Warehouse/IWarehouseService'; 5 | import { WarehouseService } from 'core/applicationServices/Portal/Warehouse/WarehouseService'; 6 | import { BaseModule } from 'dependency/BaseModule'; 7 | import { 8 | DOMAIN_APPLICATION_SERVICE_IDENTIFIERS, 9 | DOMAIN_REPOSITORY_IDENTIFIERS, 10 | } from 'core/CoreModuleSymbols'; 11 | import { WarehouseRepository } from 'infrastructure/database/repository/Portal/Warehouse/WarehouseRepository'; 12 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 13 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 14 | import { WarehouseQuery } from 'ui/Portal/Warehouse/WarehouseQuery'; 15 | 16 | export class WarehouseModule extends BaseModule { 17 | constructor() { 18 | super((bind: interfaces.Bind): void => { 19 | this.init(bind); 20 | }); 21 | } 22 | 23 | public init(bind: interfaces.Bind): void { 24 | this.provideWarehouseRepository(bind); 25 | 26 | this.provideWarehouseService(bind); 27 | 28 | this.provideWarehouseQuery(bind); 29 | } 30 | 31 | private provideWarehouseRepository(bind: interfaces.Bind): void { 32 | bind( 33 | DOMAIN_REPOSITORY_IDENTIFIERS.PORTAL_WAREHOUSE_REPOSITORY 34 | ).to(WarehouseRepository); 35 | } 36 | 37 | private provideWarehouseService(bind: interfaces.Bind): void { 38 | bind( 39 | DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.PORTAL_WAREHOUSE_SERVICE 40 | ).to(WarehouseService); 41 | } 42 | 43 | private provideWarehouseQuery(bind: interfaces.Bind): void { 44 | bind(UI_SCHEMA_IDENTIFIERS.PORTAL_WAREHOUSE_QUERIES).to( 45 | WarehouseQuery 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/dependency/Portal/WarehouseItem/WarehouseItemModule.ts: -------------------------------------------------------------------------------- 1 | import { interfaces } from 'inversify'; 2 | 3 | import { BaseModule } from 'dependency/BaseModule'; 4 | import { 5 | DOMAIN_APPLICATION_SERVICE_IDENTIFIERS, 6 | DOMAIN_REPOSITORY_IDENTIFIERS, 7 | } from 'core/CoreModuleSymbols'; 8 | import { WarehouseItemRepository } from 'infrastructure/database/repository/Portal/WarehouseItem/WarehouseItemRepository'; 9 | import { IWarehouseItemRepository } from 'core/domainServices/Portal/WarehouseItem/IWarehouseItemRepository'; 10 | import { IWarehouseItemService } from 'core/applicationServices/Portal/WarehouseItem/IWarehouseItemService'; 11 | import { WarehouseItemService } from 'core/applicationServices/Portal/WarehouseItem/WarehouseItemService'; 12 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 13 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 14 | import { WarehouseItemMutation } from 'ui/Portal/WarehouseItem/graphql/WarehouseItemMutation'; 15 | 16 | export class WarehouseItemModule extends BaseModule { 17 | constructor() { 18 | super((bind: interfaces.Bind): void => { 19 | this.init(bind); 20 | }); 21 | } 22 | 23 | public init(bind: interfaces.Bind): void { 24 | this.provideWarehouseItemRepository(bind); 25 | 26 | this.provideWarehouseItemService(bind); 27 | 28 | this.provideWarehouseItemMutation(bind); 29 | } 30 | 31 | private provideWarehouseItemRepository(bind: interfaces.Bind) { 32 | bind( 33 | DOMAIN_REPOSITORY_IDENTIFIERS.PORTAL_WAREHOUSE_ITEM_REPOSITORY 34 | ).to(WarehouseItemRepository); 35 | } 36 | 37 | private provideWarehouseItemService(bind: interfaces.Bind) { 38 | bind( 39 | DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.PORTAL_WAREHOUSE_ITEM_SERVICE 40 | ).to(WarehouseItemService); 41 | } 42 | 43 | private provideWarehouseItemMutation(bind: interfaces.Bind): void { 44 | bind(UI_SCHEMA_IDENTIFIERS.PORTAL_WAREHOUSE_ITEM_MUTATIONS).to( 45 | WarehouseItemMutation 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/dependency/Portal/common/PortalModule.ts: -------------------------------------------------------------------------------- 1 | import { interfaces } from 'inversify'; 2 | 3 | import { BaseModule } from 'dependency/BaseModule'; 4 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 5 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 6 | import { PortalQuery } from 'ui/Portal/common/graphql/PortalQuery'; 7 | import { PortalMutation } from 'ui/Portal/common/graphql/PortalMutation'; 8 | import { PortalSubQuery } from 'ui/Portal/common/graphql/PortalSubQuery'; 9 | 10 | export class PortalModule extends BaseModule { 11 | constructor() { 12 | super((bind: interfaces.Bind): void => { 13 | this.init(bind); 14 | }); 15 | } 16 | 17 | init(bind: interfaces.Bind): void { 18 | this.providePortalQuery(bind); 19 | this.providePortalMutation(bind); 20 | this.providePortalSubQuery(bind); 21 | } 22 | 23 | private providePortalQuery(bind: interfaces.Bind): void { 24 | bind(UI_SCHEMA_IDENTIFIERS.PORTAL_QUERIES).to(PortalQuery); 25 | } 26 | 27 | private providePortalMutation(bind: interfaces.Bind): void { 28 | bind(UI_SCHEMA_IDENTIFIERS.PORTAL_MUTATIONS).to(PortalMutation); 29 | } 30 | 31 | private providePortalSubQuery(bind: interfaces.Bind): void { 32 | bind(UI_SCHEMA_IDENTIFIERS.PORTAL_SUBQUERIES).to(PortalSubQuery); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/dependency/common/CommonModule.ts: -------------------------------------------------------------------------------- 1 | import { interfaces } from 'inversify'; 2 | 3 | import { BaseModule } from 'dependency/BaseModule'; 4 | import { DBMapper } from 'infrastructure/database/mappings/DBMapper'; 5 | 6 | import { 7 | DATABASE_IDENTIFIERS, 8 | INFRASTRUCTURE_IDENTIFIERS, 9 | } from 'infrastructure/InfrastructureModuleSymbols'; 10 | import { IOrm } from 'infrastructure/database/orm/IOrm'; 11 | import { OnionOrm } from 'infrastructure/database/orm/OnionOrm'; 12 | 13 | import { UIMapper } from 'ui/common/mappings/UIMapper'; 14 | import { UI_IDENTIFIERS } from 'ui/UiModuleSymbols'; 15 | 16 | export class CommonModule extends BaseModule { 17 | constructor() { 18 | super((bind: interfaces.Bind): void => { 19 | this.init(bind); 20 | }); 21 | } 22 | 23 | public init(bind: interfaces.Bind): void { 24 | this.provideOrm(bind); 25 | 26 | this.provideDBMapper(bind); 27 | this.provideUIMapper(bind); 28 | } 29 | 30 | private provideUIMapper(bind: interfaces.Bind): void { 31 | bind(UI_IDENTIFIERS.UI_MAPPER).to(UIMapper); 32 | } 33 | 34 | private provideDBMapper(bind: interfaces.Bind): void { 35 | bind(INFRASTRUCTURE_IDENTIFIERS.DB_MAPPER).to(DBMapper); 36 | } 37 | 38 | private provideOrm(bind: interfaces.Bind): void { 39 | bind(DATABASE_IDENTIFIERS.ORM).to(OnionOrm); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/dependency/shared/Authentication/AuthenticationModule.ts: -------------------------------------------------------------------------------- 1 | import { interfaces } from 'inversify'; 2 | 3 | import { BaseModule } from 'dependency/BaseModule'; 4 | 5 | import { IAuthenticationService } from 'core/applicationServices/Authentication/IAuthenticationService'; 6 | import { AuthenticationService } from 'core/applicationServices/Authentication/AuthenticationService'; 7 | 8 | import { DOMAIN_APPLICATION_SERVICE_IDENTIFIERS } from 'core/CoreModuleSymbols'; 9 | 10 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 11 | import { AuthenticationMutation } from 'ui/shared/Authentication/graphql/AuthenticationMutation'; 12 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 13 | 14 | export class AuthenticationModule extends BaseModule { 15 | constructor() { 16 | super((bind: interfaces.Bind): void => { 17 | this.init(bind); 18 | }); 19 | } 20 | 21 | public init(bind: interfaces.Bind): void { 22 | this.provideAuthenticationService(bind); 23 | 24 | this.provideAuthenticationMutation(bind); 25 | } 26 | 27 | private provideAuthenticationService(bind: interfaces.Bind): void { 28 | bind( 29 | DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.AUTHENTICATION_SERVICE 30 | ).to(AuthenticationService); 31 | } 32 | 33 | private provideAuthenticationMutation(bind: interfaces.Bind): void { 34 | bind(UI_SCHEMA_IDENTIFIERS.AUTHENTICATION_MUTATIONS).to( 35 | AuthenticationMutation 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/dependency/shared/User/UserModule.ts: -------------------------------------------------------------------------------- 1 | import { interfaces } from 'inversify'; 2 | 3 | import { BaseModule } from 'dependency/BaseModule'; 4 | import { IUserService } from 'core/applicationServices/User/IUserService'; 5 | import { UserService } from 'core/applicationServices/User/UserService'; 6 | import { IUserRepository } from 'core/domainServices/User/IUserRepository'; 7 | 8 | import { 9 | DOMAIN_APPLICATION_SERVICE_IDENTIFIERS, 10 | DOMAIN_REPOSITORY_IDENTIFIERS, 11 | DOMAIN_UNIT_OF_WORK_IDENTIFIERS, 12 | } from 'core/CoreModuleSymbols'; 13 | 14 | import { UserRepository } from 'infrastructure/database/repository/User/UserRepository'; 15 | import { UserUnitOfWork } from 'infrastructure/database/repository/User/UserUnitOfWork'; 16 | import { IUserUnitOfWork } from 'core/domainServices/User/IUserUnitOfWork'; 17 | 18 | export class UserModule extends BaseModule { 19 | constructor() { 20 | super((bind: interfaces.Bind): void => { 21 | this.init(bind); 22 | }); 23 | } 24 | 25 | public init(bind: interfaces.Bind): void { 26 | this.provideUserRepository(bind); 27 | this.provideUserUnitOfWork(bind); 28 | 29 | this.provideUserService(bind); 30 | } 31 | 32 | private provideUserRepository(bind: interfaces.Bind): void { 33 | bind(DOMAIN_REPOSITORY_IDENTIFIERS.USER_REPOSITORY).to( 34 | UserRepository 35 | ); 36 | } 37 | 38 | private provideUserUnitOfWork(bind: interfaces.Bind): void { 39 | bind(DOMAIN_UNIT_OF_WORK_IDENTIFIERS.USER_UNIT_OF_WORK).to( 40 | UserUnitOfWork 41 | ); 42 | } 43 | 44 | private provideUserService(bind: interfaces.Bind): void { 45 | bind(DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.USER_SERVICE).to( 46 | UserService 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/dependency/shared/Warehouse/WarehouseModule.ts: -------------------------------------------------------------------------------- 1 | import { interfaces } from 'inversify'; 2 | 3 | import { BaseModule } from 'dependency/BaseModule'; 4 | 5 | // TODO Remove it if not used in future 6 | export class WarehouseModule extends BaseModule { 7 | constructor() { 8 | super((bind: interfaces.Bind): void => { 9 | this.init(bind); 10 | }); 11 | } 12 | 13 | // eslint-disable-next-line @typescript-eslint/no-empty-function,no-unused-vars 14 | public init(bind: interfaces.Bind): void {} 15 | } 16 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | 3 | import { InversifyExpressServer } from 'inversify-express-utils'; 4 | 5 | import { AppContainer } from 'dependency/AppContainer'; 6 | 7 | import { ExpressApplication } from 'ui/common/config/application/express/ExpressApplication'; 8 | import { ApolloApplication } from 'ui/common/config/application/apollo/ApolloApplication'; 9 | import { UI_APPLICATION_IDENTIFIERS } from 'ui/UiModuleSymbols'; 10 | import { DATABASE_IDENTIFIERS } from 'infrastructure/InfrastructureModuleSymbols'; 11 | import { PORT } from 'ui/common/config/consts/variables'; 12 | import { IOrm } from 'infrastructure/database/orm/IOrm'; 13 | 14 | (async () => { 15 | const appContainer = new AppContainer(); 16 | appContainer.init(); 17 | appContainer 18 | .get(UI_APPLICATION_IDENTIFIERS.EXPRESS_APPLICATION) 19 | .initialize(); 20 | appContainer 21 | .get(UI_APPLICATION_IDENTIFIERS.APOLLO_APPLICATION) 22 | .initialize(); 23 | await appContainer.get(DATABASE_IDENTIFIERS.ORM).initialize(); 24 | appContainer 25 | .get( 26 | UI_APPLICATION_IDENTIFIERS.INVERSIFY_APPLICATION 27 | ) 28 | .build() 29 | // eslint-disable-next-line no-console 30 | .listen(PORT, () => console.log(`Server listening on ${PORT}`)); 31 | })(); 32 | -------------------------------------------------------------------------------- /src/infrastructure/InfrastructureModuleSymbols.ts: -------------------------------------------------------------------------------- 1 | export const INFRASTRUCTURE_IDENTIFIERS = { 2 | DB_MAPPER: Symbol.for('DBMapper'), 3 | }; 4 | 5 | export const DATABASE_IDENTIFIERS = { 6 | ORM: Symbol.for('Orm'), 7 | }; 8 | 9 | export const DATABASE_MAPPING_IDENTIFIERS = { 10 | EQUIPMENT_ENTITY: Symbol.for('EquipmentEntity'), 11 | EQUIPMENT_STATE_RATE_ENTITY: Symbol.for('EquipmentStateRate'), 12 | ROLE_ENTITY: Symbol.for('RoleEntity'), 13 | USER_ENTITY: Symbol.for('UserEntity'), 14 | RATE_ENTITY: Symbol.for('StateEntity'), 15 | STATE_ENTITY: Symbol.for('StateEntity'), 16 | WAREHOUSE_ENTITY: Symbol.for('WarehouseEntity'), 17 | WAREHOUSE_ITEM_ENTITY: Symbol.for('WarehouseItemEntity'), 18 | }; 19 | -------------------------------------------------------------------------------- /src/infrastructure/common/errors/InfrastructureErrors.ts: -------------------------------------------------------------------------------- 1 | export enum InfrastructureErrors { 2 | USER_NOT_FOUND, 3 | ROLE_NOT_FOUND, 4 | EQUIPMENT_NOT_FOUND, 5 | RATE_NOT_FOUND, 6 | STATE_NOT_FOUND, 7 | WAREHOUSE_NOT_FOUND, 8 | WAREHOUSE_ITEM_NOT_FOUND, 9 | } 10 | -------------------------------------------------------------------------------- /src/infrastructure/common/mapper/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Melzar/onion-architecture-boilerplate/846d39a18a53e18739504979427ee87e41a705d3/src/infrastructure/common/mapper/.gitkeep -------------------------------------------------------------------------------- /src/infrastructure/database/cli/dbReload.ts: -------------------------------------------------------------------------------- 1 | import { join } from 'path'; 2 | 3 | import * as yargs from 'yargs'; 4 | 5 | import { Connection, createConnection, ConnectionOptions } from 'typeorm'; 6 | 7 | const { 8 | type, 9 | host, 10 | port, 11 | username, 12 | password, 13 | database, 14 | logging, 15 | migrations, 16 | // eslint-disable-next-line import/no-dynamic-require, @typescript-eslint/no-var-requires 17 | } = require(join(process.cwd(), 'ormconfig.js'))[0]; 18 | 19 | yargs 20 | .command({ 21 | command: 'reload', 22 | describe: 'Reload Database', 23 | handler: () => { 24 | try { 25 | const connectionOptions: ConnectionOptions = { 26 | database, 27 | host, 28 | logging, 29 | migrations, 30 | password, 31 | port, 32 | type, 33 | username, 34 | }; 35 | createConnection(connectionOptions).then( 36 | async (connection: Connection) => { 37 | await connection.dropDatabase(); 38 | await connection.runMigrations(); 39 | process.exit(0); 40 | } 41 | ); 42 | } catch (error) { 43 | // eslint-disable-next-line no-console 44 | console.error('Error when reloading database', error); 45 | process.exit(1); 46 | } 47 | }, 48 | }) 49 | .parse(); 50 | -------------------------------------------------------------------------------- /src/infrastructure/database/entities/Equipment.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Column, 3 | Entity, 4 | ManyToOne, 5 | OneToOne, 6 | PrimaryGeneratedColumn, 7 | } from 'typeorm'; 8 | 9 | import { User } from 'infrastructure/database/entities/User'; 10 | import { WarehouseItem } from 'infrastructure/database/entities/WarehouseItem'; 11 | 12 | @Entity() 13 | export class Equipment { 14 | @PrimaryGeneratedColumn() 15 | id!: number; 16 | 17 | @Column() 18 | name!: string; 19 | 20 | @Column() 21 | width!: number; 22 | 23 | @Column() 24 | height!: number; 25 | 26 | @Column() 27 | depth!: number; 28 | 29 | @ManyToOne( 30 | () => User, 31 | user => user.equipment 32 | ) 33 | user!: User; 34 | 35 | @OneToOne( 36 | () => WarehouseItem, 37 | warehouseItem => warehouseItem.equipment 38 | ) 39 | warehouseItem!: WarehouseItem; 40 | } 41 | -------------------------------------------------------------------------------- /src/infrastructure/database/entities/Rate.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, ManyToMany, PrimaryGeneratedColumn } from 'typeorm'; 2 | 3 | import { State } from 'infrastructure/database/entities/State'; 4 | 5 | @Entity() 6 | export class Rate { 7 | @PrimaryGeneratedColumn() 8 | id!: number; 9 | 10 | @Column({ type: 'decimal', precision: 3, scale: 1 }) 11 | value!: number; 12 | 13 | @ManyToMany( 14 | () => State, 15 | state => state.rates 16 | ) 17 | states!: State[]; 18 | } 19 | -------------------------------------------------------------------------------- /src/infrastructure/database/entities/Role.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm'; 2 | 3 | import { User } from 'infrastructure/database/entities/User'; 4 | import { USER_ROLE } from 'infrastructure/database/enum/UserRole'; 5 | 6 | @Entity() 7 | export class Role { 8 | @PrimaryGeneratedColumn() 9 | id!: number; 10 | 11 | @Column({ 12 | default: USER_ROLE.MEMBER, 13 | enum: USER_ROLE, 14 | nullable: false, 15 | type: 'enum', 16 | }) 17 | name!: string; 18 | 19 | @OneToMany( 20 | () => User, 21 | user => user.role 22 | ) 23 | user!: User; 24 | } 25 | -------------------------------------------------------------------------------- /src/infrastructure/database/entities/State.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Column, 3 | Entity, 4 | ManyToMany, 5 | OneToMany, 6 | PrimaryGeneratedColumn, 7 | JoinTable, 8 | } from 'typeorm'; 9 | 10 | import { Rate } from 'infrastructure/database/entities/Rate'; 11 | import { Warehouse } from 'infrastructure/database/entities/Warehouse'; 12 | 13 | @Entity() 14 | export class State { 15 | @PrimaryGeneratedColumn() 16 | id!: number; 17 | 18 | @Column() 19 | name!: string; 20 | 21 | @ManyToMany( 22 | () => Rate, 23 | rate => rate.states 24 | ) 25 | @JoinTable() 26 | rates!: Rate[]; 27 | 28 | @OneToMany( 29 | () => Warehouse, 30 | warehouse => warehouse.state 31 | ) 32 | warehouses!: Warehouse[]; 33 | } 34 | -------------------------------------------------------------------------------- /src/infrastructure/database/entities/User.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Entity, 3 | PrimaryGeneratedColumn, 4 | Column, 5 | ManyToOne, 6 | OneToMany, 7 | } from 'typeorm'; 8 | 9 | import { Role } from 'infrastructure/database/entities/Role'; 10 | import { Equipment } from 'infrastructure/database/entities/Equipment'; 11 | 12 | @Entity() 13 | export class User { 14 | @PrimaryGeneratedColumn() 15 | id!: number; 16 | 17 | @Column() 18 | firstName!: string; 19 | 20 | @Column() 21 | lastName!: string; 22 | 23 | @Column() 24 | age!: number; 25 | 26 | @Column() 27 | email!: string; 28 | 29 | @Column() 30 | password!: string; 31 | 32 | @ManyToOne( 33 | () => Role, 34 | role => role.user 35 | ) 36 | role!: Role; 37 | 38 | @OneToMany( 39 | () => Equipment, 40 | equipment => equipment.user 41 | ) 42 | equipment!: Equipment; 43 | } 44 | -------------------------------------------------------------------------------- /src/infrastructure/database/entities/Warehouse.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Column, 3 | Entity, 4 | ManyToOne, 5 | OneToMany, 6 | PrimaryGeneratedColumn, 7 | } from 'typeorm'; 8 | 9 | import { State } from 'infrastructure/database/entities/State'; 10 | import { WarehouseItem } from 'infrastructure/database/entities/WarehouseItem'; 11 | 12 | @Entity() 13 | export class Warehouse { 14 | @PrimaryGeneratedColumn() 15 | id!: number; 16 | 17 | @Column() 18 | name!: string; 19 | 20 | @Column({ type: 'decimal', precision: 10, scale: 2, default: 0 }) 21 | widthCost!: number; 22 | 23 | @Column({ type: 'decimal', precision: 10, scale: 2, default: 0 }) 24 | heightCost!: number; 25 | 26 | @Column({ type: 'decimal', precision: 10, scale: 2, default: 0 }) 27 | depthCost!: number; 28 | 29 | @Column({ default: false }) 30 | available!: boolean; 31 | 32 | @Column() 33 | capacityWidth!: number; 34 | 35 | @Column() 36 | capacityHeight!: number; 37 | 38 | @Column() 39 | capacityDepth!: number; 40 | 41 | @Column({ default: 0 }) 42 | capacityWidthLoad!: number; 43 | 44 | @Column({ default: 0 }) 45 | capacityHeightLoad!: number; 46 | 47 | @Column({ default: 0 }) 48 | capacityDepthLoad!: number; 49 | 50 | @OneToMany( 51 | () => WarehouseItem, 52 | warehouseItem => warehouseItem.warehouse 53 | ) 54 | warehouseItems!: WarehouseItem[]; 55 | 56 | @ManyToOne( 57 | () => State, 58 | state => state.warehouses 59 | ) 60 | state!: State; 61 | } 62 | -------------------------------------------------------------------------------- /src/infrastructure/database/entities/WarehouseItem.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Column, 3 | Entity, 4 | JoinColumn, 5 | ManyToOne, 6 | OneToOne, 7 | PrimaryGeneratedColumn, 8 | } from 'typeorm'; 9 | 10 | import { Equipment } from 'infrastructure/database/entities/Equipment'; 11 | import { Warehouse } from 'infrastructure/database/entities/Warehouse'; 12 | 13 | @Entity() 14 | export class WarehouseItem { 15 | @PrimaryGeneratedColumn() 16 | id!: number; 17 | 18 | @Column() 19 | name!: string; 20 | 21 | @Column({ type: 'decimal', precision: 15, scale: 2 }) 22 | cost!: number; 23 | 24 | @ManyToOne( 25 | () => Warehouse, 26 | warehouse => warehouse.warehouseItems 27 | ) 28 | warehouse!: Warehouse; 29 | 30 | @OneToOne(() => Equipment) 31 | @JoinColumn() 32 | equipment!: Equipment; 33 | } 34 | -------------------------------------------------------------------------------- /src/infrastructure/database/enum/UserRole.ts: -------------------------------------------------------------------------------- 1 | export enum USER_ROLE { 2 | ADMIN = 'ADMIN', 3 | MEMBER = 'MEMBER', 4 | } 5 | -------------------------------------------------------------------------------- /src/infrastructure/database/fixtures/factories/EquipmentFactory.ts: -------------------------------------------------------------------------------- 1 | import { define } from 'typeorm-seeding'; 2 | import * as Faker from 'faker'; 3 | 4 | import { Equipment } from 'infrastructure/database/entities/Equipment'; 5 | 6 | const RANDOM_NUMBER_SIZE = 100; 7 | const RANDOM_DIMENSIONS_SIZE = 1000; 8 | 9 | define(Equipment, (faker: typeof Faker) => { 10 | const counter = faker.random.number(RANDOM_NUMBER_SIZE); 11 | const equipment = new Equipment(); 12 | 13 | equipment.name = `onion_equipment_${counter}`; 14 | equipment.width = faker.random.number(RANDOM_DIMENSIONS_SIZE); 15 | equipment.height = faker.random.number(RANDOM_DIMENSIONS_SIZE); 16 | equipment.depth = faker.random.number(RANDOM_DIMENSIONS_SIZE); 17 | 18 | return equipment; 19 | }); 20 | -------------------------------------------------------------------------------- /src/infrastructure/database/fixtures/factories/RateFactory.ts: -------------------------------------------------------------------------------- 1 | import { define } from 'typeorm-seeding'; 2 | 3 | import Faker from 'faker'; 4 | 5 | import { Rate } from 'infrastructure/database/entities/Rate'; 6 | 7 | define(Rate, (faker: typeof Faker) => { 8 | const state = new Rate(); 9 | 10 | state.value = faker.random.number({ min: 0, max: 10, precision: 5 }); 11 | 12 | return state; 13 | }); 14 | -------------------------------------------------------------------------------- /src/infrastructure/database/fixtures/factories/RoleFactory.ts: -------------------------------------------------------------------------------- 1 | import { define } from 'typeorm-seeding'; 2 | import * as Faker from 'faker'; 3 | 4 | import { Role } from 'infrastructure/database/entities/Role'; 5 | import { USER_ROLE } from 'infrastructure/database/enum/UserRole'; 6 | 7 | define(Role, (faker: typeof Faker) => { 8 | const role = new Role(); 9 | 10 | role.name = faker.random.arrayElement([USER_ROLE.ADMIN, USER_ROLE.MEMBER]); 11 | 12 | return role; 13 | }); 14 | -------------------------------------------------------------------------------- /src/infrastructure/database/fixtures/factories/StateFactory.ts: -------------------------------------------------------------------------------- 1 | import { define } from 'typeorm-seeding'; 2 | 3 | import Faker from 'faker'; 4 | 5 | import { State } from 'infrastructure/database/entities/State'; 6 | 7 | define(State, (faker: typeof Faker) => { 8 | const state = new State(); 9 | 10 | state.name = faker.address.state(); 11 | 12 | return state; 13 | }); 14 | -------------------------------------------------------------------------------- /src/infrastructure/database/fixtures/factories/UserFactory.ts: -------------------------------------------------------------------------------- 1 | import { define } from 'typeorm-seeding'; 2 | import { hashSync } from 'bcrypt'; 3 | import * as Faker from 'faker'; 4 | 5 | import { User } from 'infrastructure/database/entities/User'; 6 | 7 | const SALT = 10; 8 | const RANDOM_NUMBER_SIZE = 100; 9 | 10 | define(User, (faker: typeof Faker) => { 11 | const counter = faker.random.number(RANDOM_NUMBER_SIZE); 12 | const user = new User(); 13 | 14 | user.email = `onion_user_${counter}@example.com`; 15 | user.lastName = faker.name.lastName(counter); 16 | user.firstName = faker.name.firstName(); 17 | user.age = faker.random.number(100); 18 | user.password = hashSync('onion_test_123', SALT); 19 | 20 | return user; 21 | }); 22 | -------------------------------------------------------------------------------- /src/infrastructure/database/fixtures/factories/WarehouseFactory.ts: -------------------------------------------------------------------------------- 1 | import { define } from 'typeorm-seeding'; 2 | import Faker from 'faker'; 3 | 4 | import { Warehouse } from 'infrastructure/database/entities/Warehouse'; 5 | 6 | const RANDOM_NUMBER_SIZE = 100; 7 | const RANDOM_DIMENSIONS_SIZE = 1000000; 8 | const RANDOM_COST = { 9 | min: 1, 10 | max: 1000, 11 | precision: 0.01, 12 | }; 13 | 14 | define(Warehouse, (faker: typeof Faker) => { 15 | const counter = faker.random.number(RANDOM_NUMBER_SIZE); 16 | const warehouse = new Warehouse(); 17 | 18 | warehouse.name = `Joe & Son Storage Facility ${counter}`; 19 | warehouse.capacityWidth = faker.random.number(RANDOM_DIMENSIONS_SIZE); 20 | warehouse.capacityDepth = faker.random.number(RANDOM_DIMENSIONS_SIZE); 21 | warehouse.capacityHeight = faker.random.number(RANDOM_DIMENSIONS_SIZE); 22 | warehouse.capacityWidthLoad = faker.random.number(RANDOM_DIMENSIONS_SIZE); 23 | warehouse.capacityHeightLoad = faker.random.number(RANDOM_DIMENSIONS_SIZE); 24 | warehouse.capacityDepthLoad = faker.random.number(RANDOM_DIMENSIONS_SIZE); 25 | warehouse.widthCost = faker.random.number(RANDOM_COST); 26 | warehouse.depthCost = faker.random.number(RANDOM_COST); 27 | warehouse.heightCost = faker.random.number(RANDOM_COST); 28 | 29 | return warehouse; 30 | }); 31 | -------------------------------------------------------------------------------- /src/infrastructure/database/fixtures/factories/WarehouseItemFactory.ts: -------------------------------------------------------------------------------- 1 | import { define } from 'typeorm-seeding'; 2 | import Faker from 'faker'; 3 | 4 | import { WarehouseItem } from 'infrastructure/database/entities/WarehouseItem'; 5 | 6 | const RANDOM_NUMBER_SIZE = 100; 7 | 8 | define(WarehouseItem, (faker: typeof Faker) => { 9 | const counter = faker.random.number(RANDOM_NUMBER_SIZE); 10 | const warehouseItem = new WarehouseItem(); 11 | 12 | warehouseItem.name = `Secret Case ${counter}`; 13 | 14 | return warehouseItem; 15 | }); 16 | -------------------------------------------------------------------------------- /src/infrastructure/database/fixtures/seeds/RateSeed.ts: -------------------------------------------------------------------------------- 1 | import { Factory, Seeder, times } from 'typeorm-seeding'; 2 | 3 | import { Rate } from 'infrastructure/database/entities/Rate'; 4 | 5 | export class RateSeed implements Seeder { 6 | async run(factory: Factory): Promise { 7 | await this.prepareRateSeeds(factory); 8 | } 9 | 10 | private async prepareRateSeeds(factory: Factory): Promise { 11 | await times(5, async () => { 12 | await factory(Rate)().create(); 13 | }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/infrastructure/database/fixtures/seeds/StateSeed.ts: -------------------------------------------------------------------------------- 1 | import { Factory, Seeder, times } from 'typeorm-seeding'; 2 | 3 | import { State } from 'infrastructure/database/entities/State'; 4 | 5 | export class StateSeed implements Seeder { 6 | async run(factory: Factory): Promise { 7 | await this.prepareStateSeeds(factory); 8 | } 9 | 10 | private async prepareStateSeeds(factory: Factory): Promise { 11 | await times(5, async () => { 12 | await factory(State)().create(); 13 | }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/infrastructure/database/fixtures/seeds/WarehouseSeed.ts: -------------------------------------------------------------------------------- 1 | import { Factory, Seeder, times } from 'typeorm-seeding'; 2 | 3 | import { Warehouse } from 'infrastructure/database/entities/Warehouse'; 4 | 5 | export class WarehouseSeed implements Seeder { 6 | async run(factory: Factory): Promise { 7 | await this.prepareWarehouseSeeds(factory); 8 | } 9 | 10 | private async prepareWarehouseSeeds(factory: Factory): Promise { 11 | await times(5, async () => { 12 | await factory(Warehouse)().create(); 13 | }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/infrastructure/database/mappings/DBMapper.ts: -------------------------------------------------------------------------------- 1 | import { Mapper } from '@wufe/mapper'; 2 | import { injectable } from 'inversify'; 3 | 4 | import { UserEntityToUserDomain } from 'infrastructure/database/mappings/User/UserEntityToUserDomain'; 5 | import { EquipmentEntityToEquipmentDomain } from 'infrastructure/database/mappings/Equipment/EquipmentEntityToEquipmentDomain'; 6 | import { RoleEntityToRoleDomain } from 'infrastructure/database/mappings/Role/RoleEntityToRoleDomain'; 7 | import { RateEntityToRateDomain } from 'infrastructure/database/mappings/Rate/RateEntityToRateDomain'; 8 | import { StateEntityToStateDomain } from 'infrastructure/database/mappings/State/StateEntityToStateDomain'; 9 | import { WarehouseEntityToWarehouseDomain } from 'infrastructure/database/mappings/Warehouse/WarehouseEntityToWarehouseDomain'; 10 | import { WarehouseItemEntityToWarehouseItemDomain } from 'infrastructure/database/mappings/Warehouse/WarehouseItemEntityToWarehouseItemDomain'; 11 | 12 | @injectable() 13 | export class DBMapper { 14 | public readonly mapper: Mapper; 15 | 16 | constructor() { 17 | this.mapper = new Mapper().withConfiguration(configuration => 18 | configuration 19 | .shouldIgnoreSourcePropertiesIfNotInDestination(true) 20 | .shouldAutomaticallyMapArrays(true) 21 | ); 22 | 23 | this.initialize(); 24 | } 25 | 26 | private initialize(): void { 27 | UserEntityToUserDomain().configureMapping(this.mapper); 28 | EquipmentEntityToEquipmentDomain().configureMapping(this.mapper); 29 | RoleEntityToRoleDomain().configureMapping(this.mapper); 30 | RateEntityToRateDomain().configureMapping(this.mapper); 31 | StateEntityToStateDomain().configureMapping(this.mapper); 32 | WarehouseEntityToWarehouseDomain().configureMapping(this.mapper); 33 | WarehouseItemEntityToWarehouseItemDomain().configureMapping(this.mapper); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/infrastructure/database/mappings/Equipment/EquipmentEntityToEquipmentDomain.ts: -------------------------------------------------------------------------------- 1 | import { Mapper } from '@wufe/mapper'; 2 | 3 | import { IMapping } from 'core/common/mapper/IMapping'; 4 | import { DOMAIN_MAPPING_IDENTIFIERS } from 'core/CoreModuleSymbols'; 5 | import { Equipment } from 'core/domain/Equipment/Equipment'; 6 | 7 | import { DATABASE_MAPPING_IDENTIFIERS } from 'infrastructure/InfrastructureModuleSymbols'; 8 | import { Equipment as EquipmentEntity } from 'infrastructure/database/entities/Equipment'; 9 | 10 | export const EquipmentEntityToEquipmentDomain = (): IMapping => ({ 11 | configureMapping(mapper: Mapper): void { 12 | mapper.createMap( 13 | { 14 | destination: DOMAIN_MAPPING_IDENTIFIERS.EQUIPMENT_DOMAIN, 15 | source: DATABASE_MAPPING_IDENTIFIERS.EQUIPMENT_ENTITY, 16 | }, 17 | Equipment 18 | ); 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /src/infrastructure/database/mappings/Rate/RateEntityToRateDomain.ts: -------------------------------------------------------------------------------- 1 | import { Mapper } from '@wufe/mapper'; 2 | 3 | import { IMapping } from 'core/common/mapper/IMapping'; 4 | import { Rate } from 'core/domain/Rate/Rate'; 5 | import { DOMAIN_MAPPING_IDENTIFIERS } from 'core/CoreModuleSymbols'; 6 | import { DATABASE_MAPPING_IDENTIFIERS } from 'infrastructure/InfrastructureModuleSymbols'; 7 | import { Rate as RateEntity } from 'infrastructure/database/entities/Rate'; 8 | 9 | export const RateEntityToRateDomain = (): IMapping => ({ 10 | configureMapping(mapper: Mapper): void { 11 | mapper.createMap( 12 | { 13 | destination: DOMAIN_MAPPING_IDENTIFIERS.RATE_DOMAIN, 14 | source: DATABASE_MAPPING_IDENTIFIERS.RATE_ENTITY, 15 | }, 16 | Rate 17 | ); 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /src/infrastructure/database/mappings/Role/RoleEntityToRoleDomain.ts: -------------------------------------------------------------------------------- 1 | import { Mapper } from '@wufe/mapper'; 2 | 3 | import { IMapping } from 'core/common/mapper/IMapping'; 4 | import { Role } from 'core/domain/Role/Role'; 5 | import { DOMAIN_MAPPING_IDENTIFIERS } from 'core/CoreModuleSymbols'; 6 | import { DATABASE_MAPPING_IDENTIFIERS } from 'infrastructure/InfrastructureModuleSymbols'; 7 | import { Role as RoleEntity } from 'infrastructure/database/entities/Role'; 8 | 9 | export const RoleEntityToRoleDomain = (): IMapping => ({ 10 | configureMapping(mapper: Mapper): void { 11 | mapper.createMap( 12 | { 13 | destination: DOMAIN_MAPPING_IDENTIFIERS.ROLE_DOMAIN, 14 | source: DATABASE_MAPPING_IDENTIFIERS.ROLE_ENTITY, 15 | }, 16 | Role 17 | ); 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /src/infrastructure/database/mappings/State/StateEntityToStateDomain.ts: -------------------------------------------------------------------------------- 1 | import { Mapper } from '@wufe/mapper'; 2 | 3 | import { IMapping } from 'core/common/mapper/IMapping'; 4 | import { State } from 'core/domain/State/State'; 5 | import { DOMAIN_MAPPING_IDENTIFIERS } from 'core/CoreModuleSymbols'; 6 | import { DATABASE_MAPPING_IDENTIFIERS } from 'infrastructure/InfrastructureModuleSymbols'; 7 | import { State as StateEntity } from 'infrastructure/database/entities/State'; 8 | 9 | export const StateEntityToStateDomain = (): IMapping => ({ 10 | configureMapping(mapper: Mapper): void { 11 | mapper.createMap( 12 | { 13 | destination: DOMAIN_MAPPING_IDENTIFIERS.STATE_DOMAIN, 14 | source: DATABASE_MAPPING_IDENTIFIERS.STATE_ENTITY, 15 | }, 16 | State 17 | ); 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /src/infrastructure/database/mappings/User/UserEntityToUserDomain.ts: -------------------------------------------------------------------------------- 1 | import { Mapper } from '@wufe/mapper'; 2 | 3 | import { IMapping } from 'core/common/mapper/IMapping'; 4 | 5 | import { DOMAIN_MAPPING_IDENTIFIERS } from 'core/CoreModuleSymbols'; 6 | 7 | import { User } from 'core/domain/User/User'; 8 | import { User as UserEntity } from 'infrastructure/database/entities/User'; 9 | 10 | import { DATABASE_MAPPING_IDENTIFIERS } from 'infrastructure/InfrastructureModuleSymbols'; 11 | 12 | export const UserEntityToUserDomain = (): IMapping => ({ 13 | configureMapping(mapper: Mapper): void { 14 | mapper 15 | .createMap( 16 | { 17 | destination: DOMAIN_MAPPING_IDENTIFIERS.USER_DOMAIN, 18 | source: DATABASE_MAPPING_IDENTIFIERS.USER_ENTITY, 19 | }, 20 | User 21 | ) 22 | .forMember('role', opt => opt.mapFrom(src => src.role.name)); 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /src/infrastructure/database/mappings/Warehouse/WarehouseEntityToWarehouseDomain.ts: -------------------------------------------------------------------------------- 1 | import { Mapper } from '@wufe/mapper'; 2 | 3 | import { IMapping } from 'core/common/mapper/IMapping'; 4 | import { DOMAIN_MAPPING_IDENTIFIERS } from 'core/CoreModuleSymbols'; 5 | import { DATABASE_MAPPING_IDENTIFIERS } from 'infrastructure/InfrastructureModuleSymbols'; 6 | import { Warehouse as WarehouseEntity } from 'infrastructure/database/entities/Warehouse'; 7 | import { Warehouse } from 'core/domain/Warehouse/Warehouse'; 8 | 9 | export const WarehouseEntityToWarehouseDomain = (): IMapping => ({ 10 | configureMapping(mapper: Mapper): void { 11 | mapper.createMap( 12 | { 13 | source: DATABASE_MAPPING_IDENTIFIERS.WAREHOUSE_ENTITY, 14 | destination: DOMAIN_MAPPING_IDENTIFIERS.WAREHOUSE_DOMAIN, 15 | }, 16 | Warehouse 17 | ); 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /src/infrastructure/database/mappings/Warehouse/WarehouseItemEntityToWarehouseItemDomain.ts: -------------------------------------------------------------------------------- 1 | import { Mapper } from '@wufe/mapper'; 2 | 3 | import { IMapping } from 'core/common/mapper/IMapping'; 4 | import { DOMAIN_MAPPING_IDENTIFIERS } from 'core/CoreModuleSymbols'; 5 | import { DATABASE_MAPPING_IDENTIFIERS } from 'infrastructure/InfrastructureModuleSymbols'; 6 | import { WarehouseItem as WarehouseItemEntity } from 'infrastructure/database/entities/WarehouseItem'; 7 | import { WarehouseItem } from 'core/domain/Warehouse/WarehouseItem'; 8 | 9 | export const WarehouseItemEntityToWarehouseItemDomain = (): IMapping => ({ 10 | configureMapping(mapper: Mapper): void { 11 | mapper.createMap( 12 | { 13 | source: DATABASE_MAPPING_IDENTIFIERS.WAREHOUSE_ITEM_ENTITY, 14 | destination: DOMAIN_MAPPING_IDENTIFIERS.WAREHOUSE_ITEM_DOMAIN, 15 | }, 16 | WarehouseItem 17 | ); 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /src/infrastructure/database/migrations/1580081950192-create_user.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner } from 'typeorm'; 2 | 3 | export class createUser1580081950192 implements MigrationInterface { 4 | 5 | public async up(queryRunner: QueryRunner): Promise { 6 | await queryRunner.query('CREATE TABLE "user" ("id" SERIAL NOT NULL, "firstName" character varying NOT NULL, "lastName" character varying NOT NULL, "age" integer NOT NULL, "email" character varying NOT NULL, "password" character varying NOT NULL, CONSTRAINT "PK_cace4a159ff9f2512dd42373760" PRIMARY KEY ("id"))'); 7 | } 8 | 9 | public async down(queryRunner: QueryRunner): Promise { 10 | await queryRunner.query('DROP TABLE "user"'); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/infrastructure/database/migrations/1580148565494-create_role.ts: -------------------------------------------------------------------------------- 1 | import {MigrationInterface, QueryRunner} from "typeorm"; 2 | 3 | export class createRole1580148565494 implements MigrationInterface { 4 | 5 | public async up(queryRunner: QueryRunner): Promise { 6 | await queryRunner.query(`CREATE TYPE "role_name_enum" AS ENUM('admin', 'member')`); 7 | await queryRunner.query(`CREATE TABLE "role" ("id" SERIAL NOT NULL, "name" "role_name_enum" NOT NULL DEFAULT 'member', CONSTRAINT "PK_b36bcfe02fc8de3c57a8b2391c2" PRIMARY KEY ("id"))`); 8 | await queryRunner.query(`ALTER TABLE "user" ADD "roleId" integer`); 9 | await queryRunner.query(`ALTER TABLE "user" ADD CONSTRAINT "FK_c28e52f758e7bbc53828db92194" FOREIGN KEY ("roleId") REFERENCES "role"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); 10 | } 11 | 12 | public async down(queryRunner: QueryRunner): Promise { 13 | await queryRunner.query(`ALTER TABLE "user" DROP CONSTRAINT "FK_c28e52f758e7bbc53828db92194"`); 14 | await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "roleId"`); 15 | await queryRunner.query(`DROP TABLE "role"`); 16 | await queryRunner.query(`DROP TYPE "role_name_enum"`); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/infrastructure/database/migrations/1580567781829-create_equipment.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner } from 'typeorm'; 2 | 3 | export class createEquipment1580567781829 implements MigrationInterface { 4 | 5 | public async up(queryRunner: QueryRunner): Promise { 6 | await queryRunner.query( 7 | `CREATE TABLE "equipment" ("id" SERIAL NOT NULL, "name" character varying NOT NULL, "userId" integer, CONSTRAINT "PK_0722e1b9d6eb19f5874c1678740" PRIMARY KEY ("id"))`, 8 | undefined 9 | ); 10 | await queryRunner.query( 11 | `ALTER TABLE "equipment" ADD CONSTRAINT "FK_520c92e8181b4020f047e20e7c3" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, 12 | undefined 13 | ); 14 | } 15 | 16 | public async down(queryRunner: QueryRunner): Promise { 17 | await queryRunner.query( 18 | `ALTER TABLE "equipment" DROP CONSTRAINT "FK_520c92e8181b4020f047e20e7c3"`, 19 | undefined 20 | ); 21 | await queryRunner.query(`DROP TABLE "equipment"`, undefined); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/infrastructure/database/migrations/1611436598116-create_state.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner } from 'typeorm'; 2 | 3 | export class createState1611436598116 implements MigrationInterface { 4 | public async up(queryRunner: QueryRunner): Promise { 5 | await queryRunner.query( 6 | `CREATE TABLE "state" ("id" SERIAL NOT NULL, "name" character varying NOT NULL, CONSTRAINT "PK_549ffd046ebab1336c3a8030a12" PRIMARY KEY ("id"))` 7 | ); 8 | } 9 | 10 | public async down(queryRunner: QueryRunner): Promise { 11 | await queryRunner.query(`DROP TABLE "state"`); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/infrastructure/database/migrations/1611436650648-create_rate.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner } from 'typeorm'; 2 | 3 | export class createRate1611436650648 implements MigrationInterface { 4 | public async up(queryRunner: QueryRunner): Promise { 5 | await queryRunner.query( 6 | `CREATE TABLE "rate" ("id" SERIAL NOT NULL, "value" numeric(3,1) NOT NULL, CONSTRAINT "PK_2618d0d38af322d152ccc328f33" PRIMARY KEY ("id"))` 7 | ); 8 | } 9 | 10 | public async down(queryRunner: QueryRunner): Promise { 11 | await queryRunner.query(`DROP TABLE "rate"`); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/infrastructure/database/migrations/1611439711157-create_state_rates_rate.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner } from 'typeorm'; 2 | 3 | export class createStateRatesRate1611487349958 implements MigrationInterface { 4 | public async up(queryRunner: QueryRunner): Promise { 5 | await queryRunner.query( 6 | `CREATE TABLE "state_rates_rate" ("stateId" integer NOT NULL, "rateId" integer NOT NULL, CONSTRAINT "PK_1235b8c6cd27b19ab43b2bf64ee" PRIMARY KEY ("stateId", "rateId"))` 7 | ); 8 | await queryRunner.query( 9 | `CREATE INDEX "IDX_29847b774096ece14e79dc6d8c" ON "state_rates_rate" ("stateId") ` 10 | ); 11 | await queryRunner.query( 12 | `CREATE INDEX "IDX_5a281a1ad4fd97934063da48c0" ON "state_rates_rate" ("rateId") ` 13 | ); 14 | await queryRunner.query( 15 | `ALTER TABLE "state_rates_rate" ADD CONSTRAINT "FK_29847b774096ece14e79dc6d8c7" FOREIGN KEY ("stateId") REFERENCES "state"("id") ON DELETE CASCADE ON UPDATE NO ACTION` 16 | ); 17 | await queryRunner.query( 18 | `ALTER TABLE "state_rates_rate" ADD CONSTRAINT "FK_5a281a1ad4fd97934063da48c0d" FOREIGN KEY ("rateId") REFERENCES "rate"("id") ON DELETE CASCADE ON UPDATE NO ACTION` 19 | ); 20 | } 21 | 22 | public async down(queryRunner: QueryRunner): Promise { 23 | await queryRunner.query( 24 | `ALTER TABLE "state_rates_rate" DROP CONSTRAINT "FK_5a281a1ad4fd97934063da48c0d"` 25 | ); 26 | await queryRunner.query( 27 | `ALTER TABLE "state_rates_rate" DROP CONSTRAINT "FK_29847b774096ece14e79dc6d8c7"` 28 | ); 29 | await queryRunner.query(`DROP INDEX "IDX_5a281a1ad4fd97934063da48c0"`); 30 | await queryRunner.query(`DROP INDEX "IDX_29847b774096ece14e79dc6d8c"`); 31 | await queryRunner.query(`DROP TABLE "state_rates_rate"`); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/infrastructure/database/migrations/1611439711158-create_equipment_state_rate.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner } from 'typeorm'; 2 | 3 | export class createEquipmentStateRate1611439711158 4 | implements MigrationInterface { 5 | public async up(queryRunner: QueryRunner): Promise { 6 | await queryRunner.query( 7 | `CREATE TABLE "equipment_state_rate" ("stateId" integer NOT NULL, "equipmentId" integer NOT NULL, "rateId" integer NOT NULL, CONSTRAINT "PK_dab17f51a838eb9bb10c0604c29" PRIMARY KEY ("stateId", "equipmentId", "rateId"))` 8 | ); 9 | await queryRunner.query( 10 | `ALTER TABLE "equipment_state_rate" ADD CONSTRAINT "FK_8b120a96a437cbe83b5aed17c71" FOREIGN KEY ("stateId") REFERENCES "state"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` 11 | ); 12 | await queryRunner.query( 13 | `ALTER TABLE "equipment_state_rate" ADD CONSTRAINT "FK_3a17f1311eb3963a16a6b170245" FOREIGN KEY ("equipmentId") REFERENCES "equipment"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` 14 | ); 15 | await queryRunner.query( 16 | `ALTER TABLE "equipment_state_rate" ADD CONSTRAINT "FK_8c0672ca02121391adae5eaf432" FOREIGN KEY ("rateId") REFERENCES "rate"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` 17 | ); 18 | } 19 | 20 | public async down(queryRunner: QueryRunner): Promise { 21 | await queryRunner.query( 22 | `ALTER TABLE "equipment_state_rate" DROP CONSTRAINT "FK_8c0672ca02121391adae5eaf432"` 23 | ); 24 | await queryRunner.query( 25 | `ALTER TABLE "equipment_state_rate" DROP CONSTRAINT "FK_3a17f1311eb3963a16a6b170245"` 26 | ); 27 | await queryRunner.query( 28 | `ALTER TABLE "equipment_state_rate" DROP CONSTRAINT "FK_8b120a96a437cbe83b5aed17c71"` 29 | ); 30 | await queryRunner.query(`DROP TABLE "equipment_state_rate"`); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/infrastructure/database/migrations/1613939591337-create_warehouse.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner } from 'typeorm'; 2 | 3 | export class createWarehouse1613939591337 implements MigrationInterface { 4 | public async up(queryRunner: QueryRunner): Promise { 5 | await queryRunner.query( 6 | `CREATE TABLE "warehouse" ("id" SERIAL NOT NULL, "name" character varying NOT NULL, "stateId" integer, CONSTRAINT "PK_965abf9f99ae8c5983ae74ebde8" PRIMARY KEY ("id"))` 7 | ); 8 | await queryRunner.query( 9 | `ALTER TABLE "warehouse" ADD CONSTRAINT "FK_23423cf338d68b4927704b6be0e" FOREIGN KEY ("stateId") REFERENCES "state"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` 10 | ); 11 | } 12 | 13 | public async down(queryRunner: QueryRunner): Promise { 14 | await queryRunner.query( 15 | `ALTER TABLE "warehouse" DROP CONSTRAINT "FK_23423cf338d68b4927704b6be0e"` 16 | ); 17 | await queryRunner.query(`DROP TABLE "warehouse"`); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/infrastructure/database/migrations/1613939666376-create_warehouse_item.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner } from 'typeorm'; 2 | 3 | export class createWarehouseItem1613939666376 implements MigrationInterface { 4 | public async up(queryRunner: QueryRunner): Promise { 5 | await queryRunner.query( 6 | `CREATE TABLE "warehouse_item" ("id" SERIAL NOT NULL, "name" character varying NOT NULL, "cost" numeric(15,2) NOT NULL, "warehouseId" integer, "equipmentId" integer, CONSTRAINT "REL_b80de85d800854755dcae18a8d" UNIQUE ("equipmentId"), CONSTRAINT "PK_9db3c002318afa54d84094100b5" PRIMARY KEY ("id"))` 7 | ); 8 | await queryRunner.query( 9 | `ALTER TABLE "warehouse_item" ADD CONSTRAINT "FK_d09a54d4ec841657b62ccbb4776" FOREIGN KEY ("warehouseId") REFERENCES "warehouse"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` 10 | ); 11 | await queryRunner.query( 12 | `ALTER TABLE "warehouse_item" ADD CONSTRAINT "FK_b80de85d800854755dcae18a8d1" FOREIGN KEY ("equipmentId") REFERENCES "equipment"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` 13 | ); 14 | } 15 | 16 | public async down(queryRunner: QueryRunner): Promise { 17 | await queryRunner.query( 18 | `ALTER TABLE "warehouse_item" DROP CONSTRAINT "FK_b80de85d800854755dcae18a8d1"` 19 | ); 20 | await queryRunner.query( 21 | `ALTER TABLE "warehouse_item" DROP CONSTRAINT "FK_d09a54d4ec841657b62ccbb4776"` 22 | ); 23 | await queryRunner.query(`DROP TABLE "warehouse_item"`); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/infrastructure/database/migrations/1613940493612-remove_equipment_state_rate.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner } from 'typeorm'; 2 | 3 | export class removeEquipmentStateRate1613940493612 4 | implements MigrationInterface { 5 | public async up(queryRunner: QueryRunner): Promise { 6 | await queryRunner.query( 7 | `ALTER TABLE "equipment_state_rate" DROP CONSTRAINT "FK_8c0672ca02121391adae5eaf432"` 8 | ); 9 | await queryRunner.query( 10 | `ALTER TABLE "equipment_state_rate" DROP CONSTRAINT "FK_3a17f1311eb3963a16a6b170245"` 11 | ); 12 | await queryRunner.query( 13 | `ALTER TABLE "equipment_state_rate" DROP CONSTRAINT "FK_8b120a96a437cbe83b5aed17c71"` 14 | ); 15 | await queryRunner.query(`DROP TABLE "equipment_state_rate"`); 16 | } 17 | 18 | public async down(queryRunner: QueryRunner): Promise { 19 | await queryRunner.query( 20 | `CREATE TABLE "equipment_state_rate" ("stateId" integer NOT NULL, "equipmentId" integer NOT NULL, "rateId" integer NOT NULL, CONSTRAINT "PK_dab17f51a838eb9bb10c0604c29" PRIMARY KEY ("stateId", "equipmentId", "rateId"))` 21 | ); 22 | await queryRunner.query( 23 | `ALTER TABLE "equipment_state_rate" ADD CONSTRAINT "FK_8b120a96a437cbe83b5aed17c71" FOREIGN KEY ("stateId") REFERENCES "state"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` 24 | ); 25 | await queryRunner.query( 26 | `ALTER TABLE "equipment_state_rate" ADD CONSTRAINT "FK_3a17f1311eb3963a16a6b170245" FOREIGN KEY ("equipmentId") REFERENCES "equipment"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` 27 | ); 28 | await queryRunner.query( 29 | `ALTER TABLE "equipment_state_rate" ADD CONSTRAINT "FK_8c0672ca02121391adae5eaf432" FOREIGN KEY ("rateId") REFERENCES "rate"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/infrastructure/database/migrations/1615066557385-add_equipment_dimensions.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner } from 'typeorm'; 2 | 3 | export class addEquipmentDimensions1615066557385 implements MigrationInterface { 4 | public async up(queryRunner: QueryRunner): Promise { 5 | await queryRunner.query( 6 | `ALTER TABLE "equipment" ADD "width" integer NOT NULL` 7 | ); 8 | await queryRunner.query( 9 | `ALTER TABLE "equipment" ADD "height" integer NOT NULL` 10 | ); 11 | await queryRunner.query( 12 | `ALTER TABLE "equipment" ADD "depth" integer NOT NULL` 13 | ); 14 | } 15 | 16 | public async down(queryRunner: QueryRunner): Promise { 17 | await queryRunner.query(`ALTER TABLE "equipment" DROP COLUMN "depth"`); 18 | await queryRunner.query(`ALTER TABLE "equipment" DROP COLUMN "height"`); 19 | await queryRunner.query(`ALTER TABLE "equipment" DROP COLUMN "width"`); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/infrastructure/database/migrations/1615066763427-add_warehouse_dimensions_costs.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner } from 'typeorm'; 2 | 3 | export class addWarehouseDimensionsCosts1615066763427 4 | implements MigrationInterface { 5 | public async up(queryRunner: QueryRunner): Promise { 6 | await queryRunner.query( 7 | `ALTER TABLE "warehouse" ADD "widthCost" numeric(10,2) NOT NULL DEFAULT '0'` 8 | ); 9 | await queryRunner.query( 10 | `ALTER TABLE "warehouse" ADD "heightCost" numeric(10,2) NOT NULL DEFAULT '0'` 11 | ); 12 | await queryRunner.query( 13 | `ALTER TABLE "warehouse" ADD "depthCost" numeric(10,2) NOT NULL DEFAULT '0'` 14 | ); 15 | } 16 | 17 | public async down(queryRunner: QueryRunner): Promise { 18 | await queryRunner.query(`ALTER TABLE "warehouse" DROP COLUMN "depthCost"`); 19 | await queryRunner.query(`ALTER TABLE "warehouse" DROP COLUMN "heightCost"`); 20 | await queryRunner.query(`ALTER TABLE "warehouse" DROP COLUMN "widthCost"`); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/infrastructure/database/migrations/1615067499391-add_warehouse_properties_availability_capacity.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner } from 'typeorm'; 2 | 3 | export class addWarehousePropertiesAvailabilityCapacity1615067499391 4 | implements MigrationInterface { 5 | public async up(queryRunner: QueryRunner): Promise { 6 | await queryRunner.query( 7 | `ALTER TABLE "warehouse" ADD "available" boolean NOT NULL DEFAULT false` 8 | ); 9 | await queryRunner.query( 10 | `ALTER TABLE "warehouse" ADD "capacityWidth" integer NOT NULL` 11 | ); 12 | await queryRunner.query( 13 | `ALTER TABLE "warehouse" ADD "capacityHeight" integer NOT NULL` 14 | ); 15 | await queryRunner.query( 16 | `ALTER TABLE "warehouse" ADD "capacityDepth" integer NOT NULL` 17 | ); 18 | await queryRunner.query( 19 | `ALTER TABLE "warehouse" ADD "capacityWidthLoad" integer NOT NULL DEFAULT '0'` 20 | ); 21 | await queryRunner.query( 22 | `ALTER TABLE "warehouse" ADD "capacityHeightLoad" integer NOT NULL DEFAULT '0'` 23 | ); 24 | await queryRunner.query( 25 | `ALTER TABLE "warehouse" ADD "capacityDepthLoad" integer NOT NULL DEFAULT '0'` 26 | ); 27 | } 28 | 29 | public async down(queryRunner: QueryRunner): Promise { 30 | await queryRunner.query( 31 | `ALTER TABLE "warehouse" DROP COLUMN "capacityDepthLoad"` 32 | ); 33 | await queryRunner.query( 34 | `ALTER TABLE "warehouse" DROP COLUMN "capacityHeightLoad"` 35 | ); 36 | await queryRunner.query( 37 | `ALTER TABLE "warehouse" DROP COLUMN "capacityWidthLoad"` 38 | ); 39 | await queryRunner.query( 40 | `ALTER TABLE "warehouse" DROP COLUMN "capacityDepth"` 41 | ); 42 | await queryRunner.query( 43 | `ALTER TABLE "warehouse" DROP COLUMN "capacityHeight"` 44 | ); 45 | await queryRunner.query( 46 | `ALTER TABLE "warehouse" DROP COLUMN "capacityWidth"` 47 | ); 48 | await queryRunner.query(`ALTER TABLE "warehouse" DROP COLUMN "available"`); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/infrastructure/database/orm/IOrm.ts: -------------------------------------------------------------------------------- 1 | export interface IOrm { 2 | initialize(): Promise; 3 | } 4 | -------------------------------------------------------------------------------- /src/infrastructure/database/orm/OnionOrm.ts: -------------------------------------------------------------------------------- 1 | import { injectable } from 'inversify'; 2 | import { createConnection } from 'typeorm'; 3 | 4 | import { 5 | initializeTransactionalContext, 6 | patchTypeORMRepositoryWithBaseRepository, 7 | } from 'typeorm-transactional-cls-hooked'; 8 | 9 | import { IOrm } from 'infrastructure/database/orm/IOrm'; 10 | 11 | @injectable() 12 | export class OnionOrm implements IOrm { 13 | public async initialize(): Promise { 14 | await createConnection(process.env.ORM_CONNECTION || ''); 15 | 16 | initializeTransactionalContext(); 17 | patchTypeORMRepositoryWithBaseRepository(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/infrastructure/database/repository/Equipment/EquipmentUnitOfWork.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { DOMAIN_REPOSITORY_IDENTIFIERS } from 'core/CoreModuleSymbols'; 4 | 5 | import { IEquipmentRepository } from 'core/domainServices/Equipment/IEquipmentRepository'; 6 | import { IUserRepository } from 'core/domainServices/User/IUserRepository'; 7 | import { IEquipmentUnitOfWork } from 'core/domainServices/Equipment/IEquipmentUnitOfWork'; 8 | 9 | import { AddEquipmentRepositoryRequest } from 'core/domainServices/Equipment/request/AddEquipmentRepositoryRequest'; 10 | import { AddEquipmentUnitOfWorkRepositoryRequest } from 'core/domainServices/Equipment/request/AddEquipmentUnitOfWorkRepositoryRequest'; 11 | import { FindUserRepositoryRequest } from 'core/domainServices/User/request/FindUserRepositoryRequest'; 12 | import { Equipment } from 'core/domain/Equipment/Equipment'; 13 | 14 | import { UnitOfWork } from 'infrastructure/database/repository/common/UnitOfWork'; 15 | 16 | @injectable() 17 | export class EquipmentUnitOfWork extends UnitOfWork 18 | implements IEquipmentUnitOfWork { 19 | constructor( 20 | @inject(DOMAIN_REPOSITORY_IDENTIFIERS.EQUIPMENT_REPOSITORY) 21 | private readonly equipmentRepository: IEquipmentRepository, 22 | @inject(DOMAIN_REPOSITORY_IDENTIFIERS.USER_REPOSITORY) 23 | private readonly userRepository: IUserRepository 24 | ) { 25 | super(); 26 | } 27 | 28 | async addEquipment({ 29 | userId, 30 | name, 31 | width, 32 | height, 33 | depth, 34 | }: AddEquipmentUnitOfWorkRepositoryRequest): Promise { 35 | const { id } = await this.userRepository.findUser( 36 | new FindUserRepositoryRequest(userId) 37 | ); 38 | 39 | return this.equipmentRepository.addEquipment( 40 | new AddEquipmentRepositoryRequest(name, width, height, depth, id) 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/infrastructure/database/repository/Portal/Warehouse/WarehouseRepository.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | import { EntityRepository } from 'typeorm'; 3 | 4 | import { Warehouse as WarehouseEntity } from 'infrastructure/database/entities/Warehouse'; 5 | import { Repository } from 'infrastructure/database/repository/common/Repository'; 6 | import { 7 | DATABASE_MAPPING_IDENTIFIERS, 8 | INFRASTRUCTURE_IDENTIFIERS, 9 | } from 'infrastructure/InfrastructureModuleSymbols'; 10 | import { DBMapper } from 'infrastructure/database/mappings/DBMapper'; 11 | import { IWarehouseRepository } from 'core/domainServices/Portal/Warehouse/IWarehouseRepository'; 12 | import { Warehouse } from 'core/domain/Warehouse/Warehouse'; 13 | import { DOMAIN_MAPPING_IDENTIFIERS } from 'core/CoreModuleSymbols'; 14 | 15 | @injectable() 16 | @EntityRepository(WarehouseEntity) 17 | export class WarehouseRepository extends Repository 18 | implements IWarehouseRepository { 19 | constructor( 20 | @inject(INFRASTRUCTURE_IDENTIFIERS.DB_MAPPER) 21 | private readonly dbMapper: DBMapper 22 | ) { 23 | super(WarehouseEntity); 24 | } 25 | 26 | async getAvailableWarehouses(): Promise { 27 | const warehouses = await this.findAll(); // TODO add query statement to fetch only warehouses which capacity is below 100% 28 | 29 | return this.dbMapper.mapper.map( 30 | { 31 | destination: DOMAIN_MAPPING_IDENTIFIERS.WAREHOUSE_DOMAIN, 32 | source: DATABASE_MAPPING_IDENTIFIERS.WAREHOUSE_ENTITY, 33 | }, 34 | warehouses 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/infrastructure/database/repository/Warehouse/WarehouseWarehouseItemRepository.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | import { EntityRepository } from 'typeorm'; 3 | 4 | import { WarehouseItem as WarehouseItemEntity } from 'infrastructure/database/entities/WarehouseItem'; 5 | import { Repository } from 'infrastructure/database/repository/common/Repository'; 6 | import { 7 | DATABASE_MAPPING_IDENTIFIERS, 8 | INFRASTRUCTURE_IDENTIFIERS, 9 | } from 'infrastructure/InfrastructureModuleSymbols'; 10 | import { DBMapper } from 'infrastructure/database/mappings/DBMapper'; 11 | import { IWarehouseWarehouseItemRepository } from 'core/domainServices/Warehouse/IWarehouseWarehouseItemRepository'; 12 | import { GetWarehouseItemsRepositoryRequest } from 'core/domainServices/WarehouseItem/requests/GetWarehouseItemsRepositoryRequest'; 13 | import { WarehouseItem } from 'core/domain/Warehouse/WarehouseItem'; 14 | import { DOMAIN_MAPPING_IDENTIFIERS } from 'core/CoreModuleSymbols'; 15 | 16 | @injectable() 17 | @EntityRepository(WarehouseItemEntity) 18 | export class WarehouseWarehouseItemRepository 19 | extends Repository 20 | implements IWarehouseWarehouseItemRepository { 21 | constructor( 22 | @inject(INFRASTRUCTURE_IDENTIFIERS.DB_MAPPER) 23 | private readonly dbMapper: DBMapper 24 | ) { 25 | super(WarehouseItemEntity); 26 | } 27 | 28 | async getWarehouseItems({ 29 | warehouseId, 30 | }: GetWarehouseItemsRepositoryRequest): Promise { 31 | const warehouseItems = await this.findBy({ 32 | warehouse: { id: warehouseId }, 33 | }); 34 | 35 | return this.dbMapper.mapper.map( 36 | { 37 | destination: DOMAIN_MAPPING_IDENTIFIERS.WAREHOUSE_ITEM_DOMAIN, 38 | source: DATABASE_MAPPING_IDENTIFIERS.WAREHOUSE_ITEM_ENTITY, 39 | }, 40 | warehouseItems 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/infrastructure/database/repository/common/IRepository.ts: -------------------------------------------------------------------------------- 1 | import { Query } from 'infrastructure/database/repository/common/Query'; 2 | 3 | export interface IRepository { 4 | custom(): R; 5 | delete( 6 | condition: string | number | { [key: string]: string | number } | E 7 | ): Promise; 8 | deleteAll(condition: string[] | number[] | E[]): Promise; 9 | find(id: string): Promise; 10 | findAll(): Promise; 11 | findBy(condition: Query): Promise; 12 | findMany(ids: string[]): Promise; 13 | query(query: string, parameters?: any[]): Promise; 14 | remove(entity: E): Promise; 15 | removeAll(entities: E[]): Promise; 16 | save(entity: E): Promise; 17 | saveAll(entities: E[]): Promise; 18 | update(condition: string | number, data: E): Promise; 19 | updateAll(condition: string[] | number[], data: E): Promise; 20 | } 21 | -------------------------------------------------------------------------------- /src/infrastructure/database/repository/common/Query.ts: -------------------------------------------------------------------------------- 1 | export type Query = { 2 | [P in keyof T]?: T[P] extends never ? Query : Query; 3 | }; 4 | -------------------------------------------------------------------------------- /src/infrastructure/database/repository/common/UnitOfWork.ts: -------------------------------------------------------------------------------- 1 | import { 2 | EntityManager, 3 | getRepository, 4 | EntitySchema, 5 | ObjectType, 6 | } from 'typeorm'; 7 | 8 | export abstract class UnitOfWork { 9 | protected getConnectionName(): string | undefined { 10 | return process.env.ORM_CONNECTION; 11 | } 12 | 13 | /** 14 | * @description Had to do it that way due to limitation of Transaction library 15 | * it doesn't patch getManager and similar helpers from typeOrm - only Repository 16 | * @param entityClass - class of any Entity to get repository and it's manager, 17 | * doesn't really matter what kind of entity, for consistency provide same entity as operation 18 | * requires 19 | */ 20 | protected getManager( 21 | entityClass: ObjectType | EntitySchema | string 22 | ): EntityManager { 23 | return getRepository(entityClass, this.getConnectionName()).manager; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/infrastructure/database/repository/common/UpdateQueryData.ts: -------------------------------------------------------------------------------- 1 | export type UpdateQueryData = { 2 | [P in keyof T]?: 3 | | (T[P] extends Array 4 | ? Array> 5 | : T[P] extends ReadonlyArray 6 | ? ReadonlyArray> 7 | : UpdateQueryData) 8 | | (() => string); 9 | }; 10 | -------------------------------------------------------------------------------- /src/ui/Administration/Equipment/graphql/EquipmentMutation.ts: -------------------------------------------------------------------------------- 1 | import { IResolverObject } from 'apollo-server-express'; 2 | 3 | import { inject, injectable } from 'inversify'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { CreateEquipmentInput } from 'ui/Administration/Equipment/graphql/inputs/CreateEquipmentInput'; 7 | import { Context } from 'ui/common/config/application/apollo/types/Context'; 8 | 9 | import { DOMAIN_APPLICATION_SERVICE_IDENTIFIERS } from 'core/CoreModuleSymbols'; 10 | import { IEquipmentService } from 'core/applicationServices/Equipment/IEquipmentService'; 11 | import { CreateEquipmentRequest } from 'core/applicationServices/Equipment/requests/CreateEquipmentRequest'; 12 | 13 | @injectable() 14 | export class EquipmentMutation implements IResolver { 15 | readonly resolvers: IResolverObject; 16 | 17 | constructor( 18 | @inject(DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.EQUIPMENT_SERVICE) 19 | private readonly equipmentService: IEquipmentService 20 | ) { 21 | this.resolvers = { 22 | createEquipment: this.createEquipment, 23 | }; 24 | } 25 | 26 | private createEquipment = ( 27 | _root: unknown, 28 | { input: { name, depth, height, width } }: { input: CreateEquipmentInput }, 29 | { viewer }: Context 30 | ) => 31 | this.equipmentService.createEquipment( 32 | new CreateEquipmentRequest(name, width, height, depth, viewer!.id) 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /src/ui/Administration/Equipment/graphql/EquipmentQuery.ts: -------------------------------------------------------------------------------- 1 | import { IResolverObject } from 'apollo-server-express'; 2 | 3 | import { inject, injectable } from 'inversify'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { IEquipmentService } from 'core/applicationServices/Equipment/IEquipmentService'; 7 | import { DOMAIN_APPLICATION_SERVICE_IDENTIFIERS } from 'core/CoreModuleSymbols'; 8 | 9 | @injectable() 10 | export class EquipmentQuery implements IResolver { 11 | readonly resolvers: IResolverObject; 12 | 13 | constructor( 14 | @inject(DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.EQUIPMENT_SERVICE) 15 | private readonly equipmentService: IEquipmentService 16 | ) { 17 | this.resolvers = { 18 | equipment: this.equipment, 19 | }; 20 | } 21 | 22 | private equipment = () => this.equipmentService.fetchAllEquipment(); 23 | } 24 | -------------------------------------------------------------------------------- /src/ui/Administration/Equipment/graphql/EquipmentSubQuery.ts: -------------------------------------------------------------------------------- 1 | import { IResolverObject } from 'apollo-server-express'; 2 | 3 | import { injectable } from 'inversify'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | 7 | @injectable() 8 | export class EquipmentSubQuery implements IResolver { 9 | readonly resolvers: IResolverObject; 10 | 11 | constructor() { 12 | this.resolvers = {}; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/ui/Administration/Equipment/graphql/gql/Equipment.graphql: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | equipment: [Equipment!]! @isAuthenticated(role: [ADMIN]) 3 | } 4 | 5 | extend type Mutation { 6 | createEquipment(input: CreateEquipmentInput): Equipment! @isAuthenticated(role: [ADMIN]) # TODO add assigning equipment to user 7 | } 8 | 9 | input CreateEquipmentInput { 10 | name: String! 11 | width: Int! 12 | height: Int! 13 | depth: Int! 14 | } 15 | 16 | type Equipment { 17 | id: ID! 18 | name: String! 19 | width: Int! 20 | height: Int! 21 | depth: Int! 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/ui/Administration/Equipment/graphql/inputs/CreateEquipmentInput.ts: -------------------------------------------------------------------------------- 1 | export type CreateEquipmentInput = { 2 | name: string; 3 | width: number; 4 | height: number; 5 | depth: number; 6 | }; 7 | -------------------------------------------------------------------------------- /src/ui/Administration/Rate/graphql/RateQuery.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { IRateService } from 'core/applicationServices/Rate/IRateService'; 7 | import { DOMAIN_APPLICATION_SERVICE_IDENTIFIERS } from 'core/CoreModuleSymbols'; 8 | 9 | @injectable() 10 | export class RateQuery implements IResolver { 11 | readonly resolvers: IResolverObject; 12 | 13 | constructor( 14 | @inject(DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.RATE_SERVICE) 15 | private readonly rateService: IRateService 16 | ) { 17 | this.resolvers = { 18 | rates: this.rates, 19 | }; 20 | } 21 | 22 | private rates = () => this.rateService.fetchRates(); 23 | } 24 | -------------------------------------------------------------------------------- /src/ui/Administration/Rate/graphql/gql/Rate.graphql: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | rates: [Rate!]! @isAuthenticated(role: [ADMIN]) 3 | } 4 | 5 | type Rate { 6 | id: ID! 7 | value: Float 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/Administration/State/graphql/StateQuery.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { IStateService } from 'core/applicationServices/State/IStateService'; 7 | import { DOMAIN_APPLICATION_SERVICE_IDENTIFIERS } from 'core/CoreModuleSymbols'; 8 | 9 | @injectable() 10 | export class StateQuery implements IResolver { 11 | readonly resolvers: IResolverObject; 12 | 13 | constructor( 14 | @inject(DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.STATE_SERVICE) 15 | private readonly stateService: IStateService 16 | ) { 17 | this.resolvers = { 18 | states: this.states, 19 | }; 20 | } 21 | 22 | private states = () => this.stateService.fetchStates(); 23 | } 24 | -------------------------------------------------------------------------------- /src/ui/Administration/State/graphql/gql/State.graphql: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | states: [State!] @isAuthenticated(role: [ADMIN]) 3 | } 4 | 5 | type State { 6 | id: ID! 7 | name: String! 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/Administration/User/graphql/UserMutation.ts: -------------------------------------------------------------------------------- 1 | import { IResolverObject } from 'apollo-server-express'; 2 | 3 | import { inject, injectable } from 'inversify'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { RemoveUserInput } from 'ui/Administration/User/graphql/inputs/RemoveUserInput'; 7 | 8 | import { DOMAIN_APPLICATION_SERVICE_IDENTIFIERS } from 'core/CoreModuleSymbols'; 9 | import { IUserService } from 'core/applicationServices/User/IUserService'; 10 | import { RemoveUserRequest } from 'core/applicationServices/User/requests/RemoveUserReuqest'; 11 | 12 | @injectable() 13 | export class UserMutation implements IResolver { 14 | readonly resolvers: IResolverObject; 15 | 16 | constructor( 17 | @inject(DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.USER_SERVICE) 18 | private readonly userService: IUserService 19 | ) { 20 | this.resolvers = { 21 | removeUser: this.removeUser, 22 | }; 23 | } 24 | 25 | private removeUser = ( 26 | _root: unknown, 27 | { input: { id } }: { input: RemoveUserInput } 28 | ) => { 29 | return this.userService.removeUser(new RemoveUserRequest(id)); 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /src/ui/Administration/User/graphql/UserQuery.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | import { IResolverObject } from 'apollo-server-express'; 3 | 4 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 5 | 6 | import { DOMAIN_APPLICATION_SERVICE_IDENTIFIERS } from 'core/CoreModuleSymbols'; 7 | import { IUserService } from 'core/applicationServices/User/IUserService'; 8 | 9 | @injectable() 10 | export class UserQuery implements IResolver { 11 | readonly resolvers: IResolverObject; 12 | 13 | constructor( 14 | @inject(DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.USER_SERVICE) 15 | private readonly userService: IUserService 16 | ) { 17 | this.resolvers = { 18 | users: this.users, 19 | }; 20 | } 21 | 22 | private users = () => { 23 | return this.userService.fetchUsers(); 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/ui/Administration/User/graphql/UserSubQuery.ts: -------------------------------------------------------------------------------- 1 | import { IResolverObject } from 'apollo-server-express'; 2 | 3 | import { injectable } from 'inversify'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | 7 | @injectable() 8 | export class UserSubQuery implements IResolver { 9 | readonly resolvers: IResolverObject; 10 | 11 | constructor() { 12 | this.resolvers = {}; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/ui/Administration/User/graphql/gql/User.graphql: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | users: [User!]! @isAuthenticated(role: [ADMIN]) 3 | } 4 | 5 | extend type Mutation { 6 | removeUser(input: RemoveUserInput): Boolean 7 | } 8 | 9 | input RemoveUserInput { 10 | id: ID! 11 | } 12 | 13 | type User { 14 | id: ID! 15 | firstName: String! 16 | email: String! 17 | role: String! 18 | lastName: String! 19 | age: Int! 20 | } 21 | -------------------------------------------------------------------------------- /src/ui/Administration/User/graphql/inputs/RemoveUserInput.ts: -------------------------------------------------------------------------------- 1 | export type RemoveUserInput = { 2 | id: number; 3 | }; 4 | -------------------------------------------------------------------------------- /src/ui/Administration/Warehouse/graphql/WarehouseMutation.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { DOMAIN_APPLICATION_SERVICE_IDENTIFIERS } from 'core/CoreModuleSymbols'; 6 | import { IWarehouseService } from 'core/applicationServices/Warehouse/IWarehouseService'; 7 | import { CreateWarehouseRequest } from 'core/applicationServices/Warehouse/requests/CreateWarehouseRequest'; 8 | import { UpdateWarehouseRequest } from 'core/applicationServices/Warehouse/requests/UpdateWarehouseRequest'; 9 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 10 | import { CreateWarehouseInput } from 'ui/Administration/Warehouse/graphql/inputs/CreateWarehouseInput'; 11 | import { UpdateWarehouseInput } from 'ui/Administration/Warehouse/graphql/inputs/UpdateWarehouseInput'; 12 | 13 | @injectable() 14 | export class WarehouseMutation implements IResolver { 15 | readonly resolvers: IResolverObject; 16 | 17 | constructor( 18 | @inject(DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.WAREHOUSE_SERVICE) 19 | private readonly warehouseService: IWarehouseService 20 | ) { 21 | this.resolvers = { 22 | createWarehouse: this.createWarehouse, 23 | updateWarehouse: this.updateWarehouse, 24 | }; 25 | } 26 | 27 | private createWarehouse = ( 28 | _root: unknown, 29 | { input: { name, stateID } }: { input: CreateWarehouseInput } 30 | ) => 31 | this.warehouseService.createWarehouse( 32 | new CreateWarehouseRequest(name, stateID) 33 | ); 34 | 35 | private updateWarehouse = ( 36 | _root: unknown, 37 | { input: { warehouseID, stateID, name } }: { input: UpdateWarehouseInput } 38 | ) => 39 | this.warehouseService.updateWarehouse( 40 | new UpdateWarehouseRequest(warehouseID, stateID, name) 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /src/ui/Administration/Warehouse/graphql/WarehouseQuery.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { DOMAIN_APPLICATION_SERVICE_IDENTIFIERS } from 'core/CoreModuleSymbols'; 7 | import { IWarehouseService } from 'core/applicationServices/Warehouse/IWarehouseService'; 8 | import { GetWarehouseInput } from 'ui/Administration/Warehouse/graphql/inputs/GetWarehouseInput'; 9 | import { FetchWarehouseRequest } from 'core/applicationServices/Warehouse/requests/FetchWarehouseRequest'; 10 | 11 | @injectable() 12 | export class WarehouseQuery implements IResolver { 13 | readonly resolvers: IResolverObject; 14 | 15 | constructor( 16 | @inject(DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.WAREHOUSE_SERVICE) 17 | private readonly warehouseService: IWarehouseService 18 | ) { 19 | this.resolvers = { 20 | warehouses: this.warehouses, 21 | warehouse: this.warehouse, 22 | }; 23 | } 24 | 25 | private warehouses = () => this.warehouseService.fetchWarehouses(); 26 | 27 | private warehouse = (_root: unknown, { id }: GetWarehouseInput) => 28 | this.warehouseService.fetchWarehouse(new FetchWarehouseRequest(id)); 29 | } 30 | -------------------------------------------------------------------------------- /src/ui/Administration/Warehouse/graphql/WarehouseSubQuery.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { DOMAIN_APPLICATION_SERVICE_IDENTIFIERS } from 'core/CoreModuleSymbols'; 7 | import { IWarehouseService } from 'core/applicationServices/Warehouse/IWarehouseService'; 8 | import { IStateService } from 'core/applicationServices/State/IStateService'; 9 | import { IWarehouseWarehouseItemService } from 'core/applicationServices/Warehouse/IWarehouseWarehouseItemService'; 10 | import { Warehouse } from 'core/domain/Warehouse/Warehouse'; 11 | import { FetchStateRequest } from 'core/applicationServices/State/requests/FetchStateRequest'; 12 | import { FetchWarehouseItemsRequest } from 'core/applicationServices/WarehouseItem/requests/FetchWarehouseItemsRequest'; 13 | 14 | @injectable() 15 | export class WarehouseSubQuery implements IResolver { 16 | readonly resolvers: IResolverObject; 17 | 18 | constructor( 19 | @inject(DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.WAREHOUSE_SERVICE) 20 | private readonly warehouseService: IWarehouseService, 21 | @inject( 22 | DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.WAREHOUSE_WAREHOUSE_ITEM_SERVICE 23 | ) 24 | private readonly warehouseWarehouseItemService: IWarehouseWarehouseItemService, 25 | @inject(DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.STATE_SERVICE) 26 | private readonly stateService: IStateService 27 | ) { 28 | this.resolvers = { 29 | Warehouse: { 30 | state: this.state, 31 | warehouseItems: this.warehouseItems, 32 | }, 33 | }; 34 | } 35 | 36 | private state = ({ id }: Warehouse) => 37 | this.stateService.fetchState(new FetchStateRequest(id)); 38 | 39 | private warehouseItems = ({ id }: Warehouse) => 40 | this.warehouseWarehouseItemService.fetchWarehouseItems( 41 | new FetchWarehouseItemsRequest(id) 42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /src/ui/Administration/Warehouse/graphql/gql/Warehouse.graphql: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | warehouses: [Warehouse!]! @isAuthenticated(role: [ADMIN]) 3 | warehouse(id: ID!): Warehouse! @isAuthenticated(role: [ADMIN]) 4 | } 5 | 6 | extend type Mutation { 7 | createWarehouse(input: CreateWarehouseInput): Warehouse! @isAuthenticated(role: [ADMIN]) # TODO Add option to pass more props related to warehouse 8 | updateWarehouse(input: UpdateWarehouseInput): Warehouse! @isAuthenticated(role: [ADMIN]) # TODO Add option to pass more props related to warehouse 9 | } 10 | 11 | input UpdateWarehouseInput { 12 | warehouseID: ID! 13 | stateID: ID 14 | name: String 15 | } 16 | 17 | input CreateWarehouseInput { 18 | name: String! 19 | stateID: ID 20 | } 21 | 22 | type Warehouse { 23 | id: ID! 24 | name: String! 25 | widthCost: Float! 26 | heightCost: Float! 27 | depthCost: Float! 28 | capacityWidth: Int!, 29 | capacityHeight: Int!, 30 | capacityDepth: Int!, 31 | capacityWidthLoad: Int!, 32 | capacityHeightLoad: Int!, 33 | capacityDepthLoad: Int!, 34 | available: Boolean!, 35 | state: State! 36 | warehouseItems: [WarehouseItem!]! 37 | } 38 | -------------------------------------------------------------------------------- /src/ui/Administration/Warehouse/graphql/inputs/CreateWarehouseInput.ts: -------------------------------------------------------------------------------- 1 | export type CreateWarehouseInput = { 2 | name: string; 3 | stateID?: number; 4 | }; 5 | -------------------------------------------------------------------------------- /src/ui/Administration/Warehouse/graphql/inputs/GetWarehouseInput.ts: -------------------------------------------------------------------------------- 1 | export type GetWarehouseInput = { 2 | id: number; 3 | }; 4 | -------------------------------------------------------------------------------- /src/ui/Administration/Warehouse/graphql/inputs/UpdateWarehouseInput.ts: -------------------------------------------------------------------------------- 1 | export type UpdateWarehouseInput = { 2 | warehouseID: number; 3 | stateID?: number; 4 | name?: string; 5 | }; 6 | -------------------------------------------------------------------------------- /src/ui/Administration/WarehouseItem/graphql/WarehouseItemQuery.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { DOMAIN_APPLICATION_SERVICE_IDENTIFIERS } from 'core/CoreModuleSymbols'; 6 | import { IWarehouseItemService } from 'core/applicationServices/WarehouseItem/IWarehouseItemService'; 7 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 8 | import { GetWarehouseInput } from 'ui/Administration/Warehouse/graphql/inputs/GetWarehouseInput'; 9 | import { FetchWarehouseItemRequest } from 'core/applicationServices/WarehouseItem/requests/FetchWarehouseItemRequest'; 10 | 11 | @injectable() 12 | export class WarehouseItemQuery implements IResolver { 13 | readonly resolvers: IResolverObject; 14 | 15 | constructor( 16 | @inject(DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.WAREHOUSE_ITEM_SERVICE) 17 | private readonly warehouseItemService: IWarehouseItemService 18 | ) { 19 | this.resolvers = { 20 | warehouseItem: this.warehouseItem, 21 | warehouseItems: this.warehouseItems, 22 | }; 23 | } 24 | 25 | private warehouseItem = (_root: unknown, { id }: GetWarehouseInput) => 26 | this.warehouseItemService.fetchWarehouseItem( 27 | new FetchWarehouseItemRequest(id) 28 | ); 29 | 30 | private warehouseItems = () => 31 | this.warehouseItemService.fetchWarehouseItems(); 32 | } 33 | -------------------------------------------------------------------------------- /src/ui/Administration/WarehouseItem/graphql/WarehouseItemSubQuery.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { DOMAIN_APPLICATION_SERVICE_IDENTIFIERS } from 'core/CoreModuleSymbols'; 7 | import { IWarehouseItemEquipmentService } from 'core/applicationServices/WarehouseItem/IWarehouseItemEquipmentService'; 8 | import { IWarehouseItemWarehouseService } from 'core/applicationServices/WarehouseItem/IWarehouseItemWarehouseService'; 9 | import { WarehouseItem } from 'core/domain/Warehouse/WarehouseItem'; 10 | import { FetchWarehouseItemEquipmentRequest } from 'core/applicationServices/WarehouseItem/requests/FetchWarehouseItemEquipmentRequest'; 11 | import { FetchWarehouseItemWarehouseRequest } from 'core/applicationServices/WarehouseItem/requests/FetchWarehouseItemWarehouseRequest'; 12 | 13 | @injectable() 14 | export class WarehouseItemSubQuery implements IResolver { 15 | readonly resolvers: IResolverObject; 16 | 17 | constructor( 18 | @inject( 19 | DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.WAREHOUSE_ITEM_EQUIPMENT_SERVICE 20 | ) 21 | private readonly warehouseItemEquipmentService: IWarehouseItemEquipmentService, 22 | @inject( 23 | DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.WAREHOUSE_ITEM_WAREHOUSE_SERVICE 24 | ) 25 | private readonly warehouseItemWarehouseService: IWarehouseItemWarehouseService 26 | ) { 27 | this.resolvers = { 28 | WarehouseItem: { 29 | equipment: this.equipment, 30 | warehouse: this.warehouse, 31 | }, 32 | }; 33 | } 34 | 35 | private equipment = ({ id }: WarehouseItem) => 36 | this.warehouseItemEquipmentService.fetchEquipment( 37 | new FetchWarehouseItemEquipmentRequest(id) 38 | ); 39 | 40 | private warehouse = ({ id }: WarehouseItem) => 41 | this.warehouseItemWarehouseService.fetchWarehouse( 42 | new FetchWarehouseItemWarehouseRequest(id) 43 | ); 44 | } 45 | -------------------------------------------------------------------------------- /src/ui/Administration/WarehouseItem/graphql/gql/WarehouseItem.graphql: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | warehouseItem(id: ID): WarehouseItem! @isAuthenticated(role: [ADMIN]) 3 | warehouseItems: [WarehouseItem!]! @isAuthenticated(role: [ADMIN]) 4 | } 5 | 6 | extend type Mutation { 7 | createWarehouseItem(input: CrateWarehouseItemInput): WarehouseItem! @isAuthenticated(role: [ADMIN]) 8 | updateWarehouseItem(input: UpdateWarehouseItemInput): WarehouseItem! @isAuthenticated(role: [ADMIN]) 9 | } 10 | 11 | input CrateWarehouseItemInput { 12 | name: String! 13 | cost: Float 14 | warehouseID: ID! 15 | equipmentID: ID! 16 | } 17 | 18 | input UpdateWarehouseItemInput { 19 | id: ID! 20 | name: String 21 | cost: Float 22 | warehouseID: ID 23 | equipmentID: ID 24 | } 25 | 26 | type WarehouseItem { 27 | id: ID! 28 | name: String! 29 | cost: Float! 30 | equipment: Equipment! 31 | warehouse: Warehouse! 32 | } 33 | -------------------------------------------------------------------------------- /src/ui/Administration/WarehouseItem/graphql/inputs/CreateWarehouseItemInput.ts: -------------------------------------------------------------------------------- 1 | export type CreateWarehouseItemInput = { 2 | name: string; 3 | cost?: number; 4 | warehouseID: number; 5 | equipmentID: number; 6 | }; 7 | -------------------------------------------------------------------------------- /src/ui/Administration/WarehouseItem/graphql/inputs/GetWarehouseItemInput.ts: -------------------------------------------------------------------------------- 1 | export type GetWarehouseItemInput = { 2 | id: number; 3 | }; 4 | -------------------------------------------------------------------------------- /src/ui/Administration/WarehouseItem/graphql/inputs/UpdateWarehouseItemInput.ts: -------------------------------------------------------------------------------- 1 | export type UpdateWarehouseItemInput = { 2 | id: number; 3 | name?: string; 4 | cost?: number; 5 | warehouseID?: number; 6 | equipmentID?: number; 7 | }; 8 | -------------------------------------------------------------------------------- /src/ui/Administration/common/graphql/AdministrationMutation.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | 7 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 8 | 9 | @injectable() 10 | export class AdministrationMutation implements IResolver { 11 | readonly resolvers: IResolverObject; 12 | 13 | constructor( 14 | @inject(UI_SCHEMA_IDENTIFIERS.EQUIPMENT_MUTATIONS) 15 | public readonly equipmentMutations: IResolver, 16 | @inject(UI_SCHEMA_IDENTIFIERS.ADMINISTRATION_USER_MUTATIONS) 17 | public readonly userMutations: IResolver, 18 | @inject(UI_SCHEMA_IDENTIFIERS.ADMINISTRATION_WAREHOUSE_MUTATIONS) 19 | public readonly warehouseMutations: IResolver, 20 | @inject(UI_SCHEMA_IDENTIFIERS.ADMINISTRATION_WAREHOUSE_ITEM_MUTATIONS) 21 | public readonly warehouseItemMutations: IResolver 22 | ) { 23 | this.resolvers = { 24 | ...this.userMutations.resolvers, 25 | ...this.equipmentMutations.resolvers, 26 | ...this.warehouseMutations.resolvers, 27 | ...this.warehouseItemMutations.resolvers, 28 | }; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/ui/Administration/common/graphql/AdministrationQuery.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 7 | 8 | @injectable() 9 | export class AdministrationQuery implements IResolver { 10 | readonly resolvers: IResolverObject; 11 | 12 | constructor( 13 | @inject(UI_SCHEMA_IDENTIFIERS.ADMINISTRATION_USER_QUERIES) 14 | public readonly userQueries: IResolver, 15 | @inject(UI_SCHEMA_IDENTIFIERS.EQUIPMENT_QUERIES) 16 | public readonly equipmentQueries: IResolver, 17 | @inject(UI_SCHEMA_IDENTIFIERS.STATE_QUERIES) 18 | public readonly stateQueries: IResolver, 19 | @inject(UI_SCHEMA_IDENTIFIERS.RATE_QUERIES) 20 | public readonly rateQueries: IResolver, 21 | @inject(UI_SCHEMA_IDENTIFIERS.ADMINISTRATION_WAREHOUSE_QUERIES) 22 | public readonly warehouseQueries: IResolver, 23 | @inject(UI_SCHEMA_IDENTIFIERS.ADMINISTRATION_WAREHOUSE_ITEM_QUERIES) 24 | public readonly warehouseItemsQueries: IResolver 25 | ) { 26 | this.resolvers = { 27 | ...this.userQueries.resolvers, 28 | ...this.equipmentQueries.resolvers, 29 | ...this.rateQueries.resolvers, 30 | ...this.stateQueries.resolvers, 31 | ...this.warehouseQueries.resolvers, 32 | ...this.warehouseItemsQueries.resolvers, 33 | }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/ui/Administration/common/graphql/AdministrationSubQuery.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 7 | 8 | @injectable() 9 | export class AdministrationSubQuery implements IResolver { 10 | readonly resolvers: IResolverObject; 11 | 12 | constructor( 13 | @inject(UI_SCHEMA_IDENTIFIERS.ADMINISTRATION_USER_SUBQUERIES) 14 | public readonly userSubQueries: IResolver, 15 | @inject(UI_SCHEMA_IDENTIFIERS.EQUIPMENT_SUBQUERIES) 16 | public readonly equipmentSubQueries: IResolver, 17 | @inject(UI_SCHEMA_IDENTIFIERS.ADMINISTRATION_WAREHOUSE_SUBQUERIES) 18 | public readonly warehouseSubQueries: IResolver, 19 | @inject(UI_SCHEMA_IDENTIFIERS.ADMINISTRATION_WAREHOUSE_ITEM_SUBQUERIES) 20 | public readonly warehouseItemSubQueries: IResolver 21 | ) { 22 | this.resolvers = { 23 | ...this.userSubQueries.resolvers, 24 | ...this.equipmentSubQueries.resolvers, 25 | ...this.warehouseSubQueries.resolvers, 26 | ...this.warehouseItemSubQueries.resolvers, 27 | }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/ui/Portal/Authentication/rest/v1/requests/AuthenticationRequestBody.ts: -------------------------------------------------------------------------------- 1 | export type AuthenticationRequestBody = { 2 | email: string; 3 | password: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/ui/Portal/Authentication/rest/v1/requests/SignupRequestBody.ts: -------------------------------------------------------------------------------- 1 | export type SignUpRequestBody = { 2 | readonly age: number; 3 | readonly email: string; 4 | readonly firstName: string; 5 | readonly lastName: string; 6 | readonly password: string; 7 | }; 8 | -------------------------------------------------------------------------------- /src/ui/Portal/Equipment/graphql/EquipmentQueries.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { Context } from 'ui/common/config/application/apollo/types/Context'; 7 | import { DOMAIN_APPLICATION_SERVICE_IDENTIFIERS } from 'core/CoreModuleSymbols'; 8 | import { IUserEquipmentService } from 'core/applicationServices/User/IUserEquipmentService'; 9 | import { FetchUserEquipmentRequest } from 'core/applicationServices/User/requests/FetchUserEquipmentRequest'; 10 | import { CalculateUserEquipmentCostRequest } from 'core/applicationServices/User/requests/CalculateUserEquipmentCostRequest'; 11 | import { CalculateEquipmentCostInput } from 'ui/Portal/Equipment/graphql/inputs/CalculateEquipmentCostInput'; 12 | 13 | @injectable() 14 | export class EquipmentQuery implements IResolver { 15 | readonly resolvers: IResolverObject; 16 | 17 | constructor( 18 | @inject(DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.USER_EQUIPMENT_SERVICE) 19 | private readonly userEquipmentService: IUserEquipmentService 20 | ) { 21 | this.resolvers = { 22 | myEquipment: this.myEquipment, 23 | calculateEquipmentCost: this.calculateEquipmentCost, 24 | }; 25 | } 26 | 27 | private myEquipment = (_root: unknown, _args: unknown, { viewer }: Context) => 28 | this.userEquipmentService.fetchEquipment( 29 | new FetchUserEquipmentRequest(viewer!.id) 30 | ); 31 | 32 | private calculateEquipmentCost = ( 33 | _root: unknown, 34 | { 35 | input: { equipmentID, warehouseID }, 36 | }: { input: CalculateEquipmentCostInput }, 37 | { viewer }: Context 38 | ) => 39 | this.userEquipmentService.calculateEquipmentCost( 40 | new CalculateUserEquipmentCostRequest( 41 | equipmentID, 42 | warehouseID, 43 | viewer!.id 44 | ) 45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /src/ui/Portal/Equipment/graphql/gql/Equipment.graphql: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | myEquipment: [Equipment!]! @isAuthenticated(role: [MEMBER]) 3 | calculateEquipmentCost(input: CalculateEquipmentCostInput): EquipmentCost! @isAuthenticated(role: [MEMBER]) 4 | } 5 | 6 | input CalculateEquipmentCostInput { 7 | equipmentID: ID! 8 | warehouseID: ID! 9 | } 10 | 11 | type EquipmentCost { 12 | cost: Float! 13 | } 14 | -------------------------------------------------------------------------------- /src/ui/Portal/Equipment/graphql/inputs/CalculateEquipmentCostInput.ts: -------------------------------------------------------------------------------- 1 | export type CalculateEquipmentCostInput = { 2 | equipmentID: number; 3 | warehouseID: number; 4 | }; 5 | -------------------------------------------------------------------------------- /src/ui/Portal/Equipment/rest/v1/EquipmentController.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BaseHttpController, 3 | controller, 4 | httpPost, 5 | request, 6 | requestBody, 7 | results, 8 | } from 'inversify-express-utils'; 9 | import { inject } from 'inversify'; 10 | 11 | import { Request } from 'express'; 12 | 13 | import { OK } from 'http-status-codes'; 14 | 15 | import { DOMAIN_APPLICATION_SERVICE_IDENTIFIERS } from 'core/CoreModuleSymbols'; 16 | import { IEquipmentService } from 'core/applicationServices/Equipment/IEquipmentService'; 17 | import { CreateEquipmentRequest } from 'core/applicationServices/Equipment/requests/CreateEquipmentRequest'; 18 | import { USER_ROLE } from 'core/domain/User/UserRole'; 19 | 20 | import { CreateEquipmentRequestBody } from 'ui/Portal/Equipment/rest/v1/requests/CreateEquipmentRequestBody'; 21 | import { isAuthenticated } from 'ui/common/config/application/express/auth/middlewares/IsAuthenticated'; 22 | import { getCurrentUser } from 'ui/common/config/application/express/auth/utils/getHttpContext'; 23 | 24 | @controller('/v1/equipment') 25 | export class EquipmentController extends BaseHttpController { 26 | constructor( 27 | @inject(DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.EQUIPMENT_SERVICE) 28 | private readonly equipmentService: IEquipmentService 29 | ) { 30 | super(); 31 | } 32 | 33 | @httpPost('/', isAuthenticated({ role: USER_ROLE.MEMBER })) 34 | public async create( 35 | @requestBody() 36 | { name, width, height, depth }: CreateEquipmentRequestBody, 37 | @request() 38 | req: Request 39 | ): Promise { 40 | const currentUser = getCurrentUser(req); 41 | 42 | const createdEquipment = await this.equipmentService.createEquipment( 43 | new CreateEquipmentRequest( 44 | name, 45 | width, 46 | height, 47 | depth, 48 | currentUser.details!.id 49 | ) 50 | ); 51 | return this.json(createdEquipment, OK); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/ui/Portal/Equipment/rest/v1/requests/CreateEquipmentRequestBody.ts: -------------------------------------------------------------------------------- 1 | export type CreateEquipmentRequestBody = { 2 | readonly name: string; 3 | readonly width: number; 4 | readonly height: number; 5 | readonly depth: number; 6 | }; 7 | -------------------------------------------------------------------------------- /src/ui/Portal/User/graphql/UserQuery.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { DOMAIN_APPLICATION_SERVICE_IDENTIFIERS } from 'core/CoreModuleSymbols'; 7 | import { IUserService } from 'core/applicationServices/User/IUserService'; 8 | import { FetchUserRequest } from 'core/applicationServices/User/requests/FetchUserRequest'; 9 | import { Context } from 'ui/common/config/application/apollo/types/Context'; 10 | 11 | @injectable() 12 | export class UserQuery implements IResolver { 13 | readonly resolvers: IResolverObject; 14 | 15 | constructor( 16 | @inject(DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.USER_SERVICE) 17 | private readonly userService: IUserService 18 | ) { 19 | this.resolvers = { 20 | me: this.me, 21 | }; 22 | } 23 | 24 | private me = (_root: unknown, _args: unknown, { viewer }: Context) => { 25 | return this.userService.fetchUser(new FetchUserRequest(viewer!.id)); 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /src/ui/Portal/User/graphql/gql/User.graphql: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | me: User! @isAuthenticated(role: [MEMBER]) 3 | } 4 | -------------------------------------------------------------------------------- /src/ui/Portal/User/graphql/inputs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Melzar/onion-architecture-boilerplate/846d39a18a53e18739504979427ee87e41a705d3/src/ui/Portal/User/graphql/inputs/.gitkeep -------------------------------------------------------------------------------- /src/ui/Portal/User/rest/v1/UserController.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BaseHttpController, 3 | controller, 4 | httpDelete, 5 | requestBody, 6 | } from 'inversify-express-utils'; 7 | import { inject } from 'inversify'; 8 | 9 | import { OK } from 'http-status-codes'; 10 | 11 | import { DOMAIN_APPLICATION_SERVICE_IDENTIFIERS } from 'core/CoreModuleSymbols'; 12 | import { IUserService } from 'core/applicationServices/User/IUserService'; 13 | import { USER_ROLE } from 'core/domain/User/UserRole'; 14 | import { RemoveUserRequest } from 'core/applicationServices/User/requests/RemoveUserReuqest'; 15 | 16 | import { isAuthenticated } from 'ui/common/config/application/express/auth/middlewares/IsAuthenticated'; 17 | import { DeleteUserRequestBody } from 'ui/Portal/User/rest/v1/requests/DeleteUserRequestBody'; 18 | 19 | @controller('/v1/user') 20 | export class UserController extends BaseHttpController { 21 | constructor( 22 | @inject(DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.USER_SERVICE) 23 | private readonly userService: IUserService 24 | ) { 25 | super(); 26 | } 27 | 28 | @httpDelete('/', isAuthenticated({ role: USER_ROLE.MEMBER })) 29 | public async delete(@requestBody() { id }: DeleteUserRequestBody) { 30 | await this.userService.removeUser(new RemoveUserRequest(id)); 31 | 32 | return this.json(OK); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/ui/Portal/User/rest/v1/requests/DeleteUserRequestBody.ts: -------------------------------------------------------------------------------- 1 | export type DeleteUserRequestBody = { 2 | readonly id: number; 3 | }; 4 | -------------------------------------------------------------------------------- /src/ui/Portal/Warehouse/WarehouseQuery.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { DOMAIN_APPLICATION_SERVICE_IDENTIFIERS } from 'core/CoreModuleSymbols'; 7 | import { IWarehouseService } from 'core/applicationServices/Portal/Warehouse/IWarehouseService'; 8 | 9 | @injectable() 10 | export class WarehouseQuery implements IResolver { 11 | readonly resolvers: IResolverObject; 12 | 13 | constructor( 14 | @inject(DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.PORTAL_WAREHOUSE_SERVICE) 15 | private readonly warehouseService: IWarehouseService 16 | ) { 17 | this.resolvers = { 18 | availableWarehouses: this.availableWarehouses, 19 | }; 20 | } 21 | 22 | private availableWarehouses = () => 23 | this.warehouseService.fetchAvailableWarehouses(); 24 | } 25 | -------------------------------------------------------------------------------- /src/ui/Portal/Warehouse/graphql/gql/Warehouse.graphql: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | availableWarehouses: [Warehouse!]! @isAuthenticated(role: [MEMBER]) 3 | } 4 | 5 | -------------------------------------------------------------------------------- /src/ui/Portal/WarehouseItem/graphql/WarehouseItemMutation.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { DOMAIN_APPLICATION_SERVICE_IDENTIFIERS } from 'core/CoreModuleSymbols'; 7 | import { IWarehouseItemService } from 'core/applicationServices/Portal/WarehouseItem/IWarehouseItemService'; 8 | import { AddWarehouseItemInput } from 'ui/Portal/WarehouseItem/graphql/inputs/AddWarehouseItemInput'; 9 | import { AddWarehouseItemRequest } from 'core/applicationServices/Portal/WarehouseItem/requests/AddWarehouseItemRequest'; 10 | 11 | @injectable() 12 | export class WarehouseItemMutation implements IResolver { 13 | readonly resolvers: IResolverObject; 14 | 15 | constructor( 16 | @inject( 17 | DOMAIN_APPLICATION_SERVICE_IDENTIFIERS.PORTAL_WAREHOUSE_ITEM_SERVICE 18 | ) 19 | private readonly warehouseItemService: IWarehouseItemService 20 | ) { 21 | this.resolvers = { 22 | addWarehouseItem: this.addWarehouseItem, 23 | }; 24 | } 25 | 26 | private addWarehouseItem = ( 27 | _root: unknown, 28 | { 29 | input: { equipmentID, warehouseID, name }, 30 | }: { input: AddWarehouseItemInput } 31 | ) => 32 | this.warehouseItemService.addWarehouseItem( 33 | new AddWarehouseItemRequest(equipmentID, warehouseID, name) 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /src/ui/Portal/WarehouseItem/graphql/gql/WarehouseItem.graphql: -------------------------------------------------------------------------------- 1 | extend type Mutation { 2 | addWarehouseItem(input: AddWarehouseItem): WarehouseItem! @isAuthenticated(role: [MEMBER]) 3 | } 4 | 5 | input AddWarehouseItem { 6 | equipmentID: ID! 7 | warehouseID: ID! 8 | name: String 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/Portal/WarehouseItem/graphql/inputs/AddWarehouseItemInput.ts: -------------------------------------------------------------------------------- 1 | export type AddWarehouseItemInput = { 2 | equipmentID: number; 3 | warehouseID: number; 4 | name?: string; 5 | }; 6 | -------------------------------------------------------------------------------- /src/ui/Portal/common/graphql/PortalMutation.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 7 | 8 | @injectable() 9 | export class PortalMutation implements IResolver { 10 | readonly resolvers: IResolverObject; 11 | 12 | constructor( 13 | @inject(UI_SCHEMA_IDENTIFIERS.PORTAL_WAREHOUSE_ITEM_MUTATIONS) 14 | public readonly warehouseItemMutations: IResolver 15 | ) { 16 | this.resolvers = { 17 | ...warehouseItemMutations.resolvers, 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ui/Portal/common/graphql/PortalQuery.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 7 | 8 | @injectable() 9 | export class PortalQuery implements IResolver { 10 | readonly resolvers: IResolverObject; 11 | 12 | constructor( 13 | @inject(UI_SCHEMA_IDENTIFIERS.PORTAL_USER_QUERIES) 14 | public readonly userQueries: IResolver, 15 | @inject(UI_SCHEMA_IDENTIFIERS.PORTAL_EQUIPMENT_QUERIES) 16 | public readonly equipmentQueries: IResolver, 17 | @inject(UI_SCHEMA_IDENTIFIERS.PORTAL_WAREHOUSE_QUERIES) 18 | public readonly warehouseQueries: IResolver 19 | ) { 20 | this.resolvers = { 21 | ...this.userQueries.resolvers, 22 | ...this.equipmentQueries.resolvers, 23 | ...this.warehouseQueries.resolvers, 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/ui/Portal/common/graphql/PortalSubQuery.ts: -------------------------------------------------------------------------------- 1 | import { injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | 7 | @injectable() 8 | export class PortalSubQuery implements IResolver { 9 | readonly resolvers: IResolverObject; 10 | 11 | constructor() { 12 | this.resolvers = {}; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/ui/common/config/application/apollo/ApolloApplication.ts: -------------------------------------------------------------------------------- 1 | import { ApolloServer } from 'apollo-server-express'; 2 | 3 | import { inject, injectable } from 'inversify'; 4 | 5 | import express from 'express'; 6 | 7 | import { BaseApplication } from 'ui/common/config/application/common/BaseApplication'; 8 | import { IApplication } from 'ui/common/config/application/common/IApplication'; 9 | 10 | import { UI_APPLICATION_IDENTIFIERS } from 'ui/UiModuleSymbols'; 11 | import { APOLLO_BASE_PATH } from 'ui/common/config/consts/variables'; 12 | 13 | @injectable() 14 | export class ApolloApplication extends BaseApplication 15 | implements IApplication { 16 | private readonly expressApp: express.Application; 17 | 18 | constructor( 19 | @inject(UI_APPLICATION_IDENTIFIERS.APOLLO_SERVER) app: ApolloServer, 20 | @inject(UI_APPLICATION_IDENTIFIERS.EXPRESS) expressApp: express.Application 21 | ) { 22 | super(app); 23 | this.expressApp = expressApp; 24 | } 25 | 26 | initialize(): void { 27 | this.initializeExtensions(); 28 | } 29 | 30 | initializeBodyParsers(): void { 31 | Error('NOT IMPLEMENTED'); 32 | } 33 | 34 | initializeExtensions(): void { 35 | this.app.applyMiddleware({ 36 | app: this.expressApp, 37 | path: APOLLO_BASE_PATH, 38 | cors: true, 39 | }); 40 | } 41 | 42 | initializeHandlers(): void { 43 | Error('NOT IMPLEMENTED'); 44 | } 45 | 46 | initializeLogging(): void { 47 | Error('NOT IMPLEMENTED'); 48 | } 49 | 50 | initializePlugins(): void { 51 | Error('NOT IMPLEMENTED'); 52 | } 53 | 54 | initializeSecurity(): void { 55 | Error('NOT IMPLEMENTED'); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/ui/common/config/application/apollo/ApolloContext.ts: -------------------------------------------------------------------------------- 1 | import { Request } from 'express'; 2 | 3 | import { inject, injectable } from 'inversify'; 4 | 5 | import { IApolloContext } from 'ui/common/config/application/apollo/common/IApolloContext'; 6 | import { Context } from 'ui/common/config/application/apollo/types/Context'; 7 | import { JWTTokenUtil } from 'ui/common/config/application/common/auth/utils/JWTTokenUtil'; 8 | import { UI_APPLICATION_IDENTIFIERS } from 'ui/UiModuleSymbols'; 9 | import { GraphQLTokenPayload } from 'ui/common/config/application/apollo/auth/types/GraphQLTokenPayload'; 10 | 11 | @injectable() 12 | export class ApolloContext implements IApolloContext { 13 | constructor( 14 | @inject(UI_APPLICATION_IDENTIFIERS.JWT_TOKEN_UTIL) 15 | public readonly jwtTokenUtil: JWTTokenUtil 16 | ) {} 17 | 18 | context = async ({ req }: { req: Request }): Promise => { 19 | const token = (req.headers.authorization || '').replace('Bearer ', ''); 20 | 21 | // https://github.com/apollographql/apollo-server/issues/3039 22 | // https://github.com/apollographql/apollo-server/issues/1709 23 | // https://github.com/apollographql/apollo-server/issues/1709#issuecomment-495793375 24 | // As long as first issue won't be resolved we won't be able to do it differently 25 | // without integrating express in this flow 26 | 27 | try { 28 | const { viewer, claims } = this.jwtTokenUtil.decodeToken< 29 | GraphQLTokenPayload 30 | >(token); 31 | return { 32 | claims, 33 | viewer, 34 | }; 35 | } catch { 36 | // If there is an error and directive is applied directive will throw Forbidden error 37 | return {}; 38 | } 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /src/ui/common/config/application/apollo/auth/types/GraphQLTokenPayload.ts: -------------------------------------------------------------------------------- 1 | export type GraphQLTokenPayload = { 2 | claims?: { 3 | role: string; 4 | }; 5 | viewer: { 6 | id: number; 7 | name: string; 8 | email: string; 9 | type?: string; 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /src/ui/common/config/application/apollo/common/IApolloContext.ts: -------------------------------------------------------------------------------- 1 | import { Request } from 'express'; 2 | 3 | import { Context } from 'ui/common/config/application/apollo/types/Context'; 4 | 5 | export interface IApolloContext { 6 | context: ({ req }: { req: Request }) => Promise; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/common/config/application/apollo/common/IResolver.ts: -------------------------------------------------------------------------------- 1 | export interface IResolver { 2 | readonly resolvers: R; 3 | } 4 | -------------------------------------------------------------------------------- /src/ui/common/config/application/apollo/consts/schemaDirectives.ts: -------------------------------------------------------------------------------- 1 | import { IsAuthenticatedDirective } from 'ui/common/config/application/apollo/directives/IsAuthenticatedDirective'; 2 | 3 | export const schemaDirectives = { 4 | isAuthenticated: IsAuthenticatedDirective, 5 | }; 6 | -------------------------------------------------------------------------------- /src/ui/common/config/application/apollo/directives/IsAuthenticatedDirective.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLFieldResolver, GraphQLResolveInfo } from 'graphql'; 2 | 3 | import { ForbiddenError } from 'apollo-server-errors'; 4 | 5 | import { BaseDirective } from 'ui/common/config/application/apollo/directives/BaseDirective'; 6 | 7 | type IsAuthenticatedArguments = { 8 | role: string; // TODO Change to enum 9 | }; 10 | 11 | export class IsAuthenticatedDirective extends BaseDirective { 12 | protected resolveField( 13 | resolve: GraphQLFieldResolver, 14 | args: [any, { [argName: string]: any }, any, GraphQLResolveInfo], 15 | directiveArgs: IsAuthenticatedArguments 16 | ): Promise { 17 | const [, , { viewer, claims }] = args; 18 | 19 | if (!viewer) { 20 | throw new ForbiddenError('FORBIDDEN ACCESS'); 21 | } 22 | 23 | const { role } = directiveArgs; 24 | 25 | if (!role) { 26 | return resolve.apply(this, args); 27 | } 28 | 29 | if (!claims || !role.includes(claims.role)) { 30 | throw new ForbiddenError('FORBIDDEN ACCESS'); // TODO Apply error enums at least 31 | } 32 | 33 | return resolve.apply(this, args); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/ui/common/config/application/apollo/gql/Directives.graphql: -------------------------------------------------------------------------------- 1 | directive @isAuthenticated(role: [Role]) on FIELD_DEFINITION 2 | -------------------------------------------------------------------------------- /src/ui/common/config/application/apollo/gql/Node.graphql: -------------------------------------------------------------------------------- 1 | interface Node { 2 | id: ID! 3 | } 4 | -------------------------------------------------------------------------------- /src/ui/common/config/application/apollo/gql/Role.graphql: -------------------------------------------------------------------------------- 1 | enum Role { 2 | ADMIN , 3 | MEMBER, 4 | } 5 | -------------------------------------------------------------------------------- /src/ui/common/config/application/apollo/gql/schema.graphql: -------------------------------------------------------------------------------- 1 | type Query 2 | type Mutation 3 | -------------------------------------------------------------------------------- /src/ui/common/config/application/apollo/plugins/RequestDidStartPlugin.ts: -------------------------------------------------------------------------------- 1 | import { ForbiddenError } from 'apollo-server-express'; 2 | import { 3 | ApolloServerPlugin, 4 | GraphQLRequestListener, 5 | } from 'apollo-server-plugin-base'; 6 | 7 | import { injectable } from 'inversify'; 8 | 9 | import { Context } from 'ui/common/config/application/apollo/types/Context'; 10 | 11 | // https://github.com/apollographql/apollo-server/issues/1709#issuecomment-575086351 12 | @injectable() 13 | export class RequestDidStartPlugin implements ApolloServerPlugin { 14 | requestDidStart(): GraphQLRequestListener | void { 15 | return { 16 | willSendResponse({ response, errors }) { 17 | if (response && response.http) { 18 | if ( 19 | errors && 20 | errors.find(err => err.originalError instanceof ForbiddenError) 21 | ) { 22 | response.data = undefined; 23 | response.http.status = 401; 24 | } 25 | } 26 | }, 27 | }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/ui/common/config/application/apollo/schema/RootMutation.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolvers } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 7 | 8 | @injectable() 9 | export class RootMutation implements IResolver { 10 | readonly resolvers: IResolvers; 11 | 12 | constructor( 13 | @inject(UI_SCHEMA_IDENTIFIERS.ADMINISTRATION_MUTATIONS) 14 | public readonly administrationMutations: IResolver, 15 | @inject(UI_SCHEMA_IDENTIFIERS.PORTAL_MUTATIONS) 16 | public readonly portalMutations: IResolver, 17 | @inject(UI_SCHEMA_IDENTIFIERS.SHARED_MUTATIONS) 18 | public readonly sharedMutations: IResolver 19 | ) { 20 | this.resolvers = { 21 | ...this.administrationMutations.resolvers, 22 | ...this.portalMutations.resolvers, 23 | ...this.sharedMutations.resolvers, 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/ui/common/config/application/apollo/schema/RootQuery.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolvers } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 7 | 8 | @injectable() 9 | export class RootQuery implements IResolver { 10 | readonly resolvers: IResolvers; 11 | 12 | constructor( 13 | @inject(UI_SCHEMA_IDENTIFIERS.ADMINISTRATION_QUERIES) 14 | public readonly administrationQueries: IResolver, 15 | @inject(UI_SCHEMA_IDENTIFIERS.PORTAL_QUERIES) 16 | public readonly portalQueries: IResolver, 17 | @inject(UI_SCHEMA_IDENTIFIERS.SHARED_QUERIES) 18 | public readonly sharedQueries: IResolver 19 | ) { 20 | this.resolvers = { 21 | ...this.administrationQueries.resolvers, 22 | ...this.portalQueries.resolvers, 23 | ...this.sharedQueries.resolvers, 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/ui/common/config/application/apollo/schema/RootResolver.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolvers } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { UI_APPLICATION_IDENTIFIERS } from 'ui/UiModuleSymbols'; 7 | 8 | @injectable() 9 | export class RootResolver implements IResolver { 10 | readonly resolvers: IResolvers; 11 | 12 | constructor( 13 | @inject(UI_APPLICATION_IDENTIFIERS.SCHEMA_QUERIES) 14 | public readonly queries: IResolver, 15 | @inject(UI_APPLICATION_IDENTIFIERS.SCHEMA_MUTATIONS) 16 | public readonly mutations: IResolver, 17 | @inject(UI_APPLICATION_IDENTIFIERS.SCHEMA_SUBQUERIES) 18 | public readonly subqueries: IResolver 19 | ) { 20 | this.resolvers = { 21 | ...this.subqueries.resolvers, 22 | Query: { 23 | ...this.queries.resolvers, 24 | }, 25 | Mutation: { 26 | ...this.mutations.resolvers, 27 | }, 28 | Node: { 29 | __resolveType: () => null, 30 | }, 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/ui/common/config/application/apollo/schema/RootSubQuery.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolvers } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 7 | 8 | @injectable() 9 | export class RootSubQuery implements IResolver { 10 | readonly resolvers: IResolvers; 11 | 12 | constructor( 13 | @inject(UI_SCHEMA_IDENTIFIERS.ADMINISTRATION_SUBQUERIES) 14 | public readonly administrationSubQueries: IResolver, 15 | @inject(UI_SCHEMA_IDENTIFIERS.PORTAL_SUBQUERIES) 16 | public readonly portalSubQueries: IResolver, 17 | @inject(UI_SCHEMA_IDENTIFIERS.SHARED_SUBQUERIES) 18 | public readonly sharedSubQueries: IResolver 19 | ) { 20 | this.resolvers = { 21 | ...this.administrationSubQueries.resolvers, 22 | ...this.portalSubQueries.resolvers, 23 | ...this.sharedSubQueries.resolvers, 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/ui/common/config/application/apollo/types/Context.ts: -------------------------------------------------------------------------------- 1 | export type Context = { 2 | viewer?: { 3 | id: number; 4 | name: string; 5 | type?: string; 6 | email: string; 7 | }; 8 | claims?: { 9 | role: string; 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /src/ui/common/config/application/common/BaseApplication.ts: -------------------------------------------------------------------------------- 1 | export abstract class BaseApplication { 2 | protected readonly app: T; 3 | 4 | protected constructor(app: T) { 5 | this.app = app; 6 | } 7 | 8 | public abstract initialize(): void; 9 | 10 | public getApplication(): T { 11 | return this.app; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ui/common/config/application/common/IApplication.ts: -------------------------------------------------------------------------------- 1 | export interface IApplication { 2 | /** 3 | * Body Parsers 4 | * @Description Apply request related body parsers 5 | */ 6 | initializeBodyParsers(): void; 7 | 8 | /** 9 | * Handlers 10 | * @Description Apply here application handlers 11 | */ 12 | initializeHandlers(): void; 13 | /** 14 | * Loggers 15 | * @Description Apply here application wide loggers 16 | */ 17 | initializeLogging(): void; 18 | 19 | /** 20 | * Plugins 21 | * @Description Apply here any external plugins for app 22 | */ 23 | initializePlugins(): void; 24 | 25 | /** 26 | * Extensions 27 | * @Description Apply here extensions like swagger etc 28 | */ 29 | initializeExtensions(): void; 30 | 31 | /** 32 | * Security 33 | * @Description Apply security related plugins like JWT, request security etc... 34 | */ 35 | initializeSecurity(): void; 36 | } 37 | -------------------------------------------------------------------------------- /src/ui/common/config/application/common/IConfig.ts: -------------------------------------------------------------------------------- 1 | export interface IConfig { 2 | initialize(): R; 3 | } 4 | -------------------------------------------------------------------------------- /src/ui/common/config/application/common/auth/IAuthenticationHandler.ts: -------------------------------------------------------------------------------- 1 | import { AuthenticationRequest } from 'core/applicationServices/Authentication/requests/AuthenticationRequest'; 2 | import { Authentication } from 'ui/common/config/application/common/auth/models/Authentication'; 3 | 4 | export interface IAuthenticationHandler { 5 | authenticate(request: AuthenticationRequest): Promise; 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/common/config/application/common/auth/models/Authentication.ts: -------------------------------------------------------------------------------- 1 | export class Authentication { 2 | constructor(public readonly token: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /src/ui/common/config/application/common/auth/utils/JWTTokenUtil.ts: -------------------------------------------------------------------------------- 1 | import { IncomingHttpHeaders } from 'http'; 2 | 3 | import jwt, { Secret } from 'jsonwebtoken'; 4 | import { injectable } from 'inversify'; 5 | 6 | import { APP_TOKEN_SECRET } from 'ui/common/config/consts/variables'; 7 | 8 | @injectable() 9 | export class JWTTokenUtil { 10 | private readonly AUTH_HEADER = 'authorization'; 11 | 12 | private readonly SCHEME = 'bearer'; 13 | 14 | private readonly MATCHER = /(\S+)\s+(\S+)/; 15 | 16 | generateToken( 17 | payload: any, 18 | secret: Secret, 19 | expiresIn: string | number, 20 | payloadKey?: string 21 | ): string { 22 | return jwt.sign(payloadKey ? { [payloadKey]: payload } : payload, secret, { 23 | expiresIn, 24 | }); 25 | } 26 | 27 | decodeToken(token: string): R { 28 | try { 29 | return jwt.verify(token, APP_TOKEN_SECRET) as R; 30 | } catch { 31 | return null as R; 32 | } 33 | } 34 | 35 | getTokenFromHeaders(headers: IncomingHttpHeaders): string | null { 36 | const authHeader = headers[this.AUTH_HEADER]; 37 | if (!authHeader) { 38 | return null; 39 | } 40 | const matches = authHeader.match(this.MATCHER); 41 | 42 | return matches && matches[2]; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/ui/common/config/application/express/auth/middlewares/IsAuthenticated.ts: -------------------------------------------------------------------------------- 1 | import * as express from 'express'; 2 | 3 | import { FORBIDDEN, getStatusText, UNAUTHORIZED } from 'http-status-codes'; 4 | 5 | import { getCurrentUser } from 'ui/common/config/application/express/auth/utils/getHttpContext'; 6 | import { UserInterfaceError } from 'ui/common/config/errors/UserInterfaceError'; 7 | 8 | export const isAuthenticated = (config?: { role: string }) => async ( 9 | req: express.Request, 10 | res: express.Response, 11 | next: express.NextFunction 12 | ): Promise => { 13 | const user = getCurrentUser(req); 14 | 15 | if (!user) { 16 | next( 17 | new UserInterfaceError( 18 | UNAUTHORIZED, 19 | getStatusText(UNAUTHORIZED).toUpperCase() 20 | ) 21 | ); 22 | return; 23 | } 24 | 25 | const isAuthenticatedUser = await user.isAuthenticated(); 26 | 27 | if (!isAuthenticatedUser) { 28 | next( 29 | new UserInterfaceError( 30 | UNAUTHORIZED, 31 | getStatusText(UNAUTHORIZED).toUpperCase() 32 | ) 33 | ); 34 | return; 35 | } 36 | if (config) { 37 | const isInRole = await user.isInRole(config.role); 38 | if (!isInRole) { 39 | next( 40 | new UserInterfaceError( 41 | FORBIDDEN, 42 | getStatusText(FORBIDDEN).toUpperCase() 43 | ) 44 | ); 45 | return; 46 | } 47 | } 48 | next(); 49 | }; 50 | -------------------------------------------------------------------------------- /src/ui/common/config/application/express/auth/models/Principal.ts: -------------------------------------------------------------------------------- 1 | import { interfaces } from 'inversify-express-utils'; 2 | 3 | import { User } from 'ui/common/models/User'; 4 | 5 | export class Principal implements interfaces.Principal { 6 | public details: User | undefined; 7 | 8 | public constructor(details: User | undefined) { 9 | this.details = details; 10 | } 11 | 12 | public isAuthenticated(): Promise { 13 | return Promise.resolve(!!this.details); 14 | } 15 | 16 | public isResourceOwner(resourceId: any): Promise { 17 | return Promise.resolve(resourceId === true); 18 | } 19 | 20 | public isInRole(role: string): Promise { 21 | return Promise.resolve(role === this.details?.role); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/ui/common/config/application/express/auth/types/TokenPayload.ts: -------------------------------------------------------------------------------- 1 | import { User } from 'ui/common/models/User'; 2 | 3 | export type TokenPayload = { 4 | user: User; 5 | }; 6 | -------------------------------------------------------------------------------- /src/ui/common/config/application/express/auth/utils/getHttpContext.ts: -------------------------------------------------------------------------------- 1 | import { interfaces } from 'inversify-express-utils'; 2 | import { Request } from 'express'; 3 | 4 | import { Principal } from 'ui/common/config/application/express/auth/models/Principal'; 5 | 6 | /** 7 | * @Description as HttpContext is not properly injected into controller this is kind of 8 | * workaround which is done manually. Watch this issue as it could solve it https://github.com/inversify/inversify-express-utils/pull/253 9 | * Also take a look at this source https://stackoverflow.com/questions/54218295/inject-httpcontext-into-inversifyjs-middleware/54233115#54233115 10 | * and https://github.com/inversify/InversifyJS/issues/673 11 | */ 12 | export const getCurrentUser = (request: Request): Principal => { 13 | const httpContext: interfaces.HttpContext = Reflect.getMetadata( 14 | 'inversify-express-utils:httpcontext', 15 | request 16 | ); 17 | return httpContext.user; 18 | }; 19 | -------------------------------------------------------------------------------- /src/ui/common/config/application/express/utils/unless.ts: -------------------------------------------------------------------------------- 1 | import { NextFunction, Request, Response } from 'express'; 2 | 3 | // SOURCE: https://stackoverflow.com/a/51981393 4 | export const unless = (path: string, middleware: any) => { 5 | return (req: Request, res: Response, next: NextFunction) => { 6 | if (path === req.path) { 7 | return next(); 8 | } 9 | return middleware(req, res, next); 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /src/ui/common/config/consts/variables.ts: -------------------------------------------------------------------------------- 1 | import * as dotenv from 'dotenv'; 2 | 3 | dotenv.config(); 4 | 5 | export const APP_TOKEN_SECRET = process.env.APP_TOKEN_SECRET || ''; 6 | export const APP_TOKEN_LIFE = process.env.APP_TOKEN_LIFE || '24h'; 7 | export const PORT = process.env.PORT || '3000'; 8 | export const LOG_LEVEL = process.env.LOG_LEVEL || 'debug'; 9 | export const SWAGGER_BASE_PATH = process.env.SWAGGER_BASE_PATH || ''; 10 | export const APOLLO_BASE_PATH = process.env.APOLLO_BASE_PATH || ''; 11 | export const { SWAGGER_HOST } = process.env; 12 | export const IS_DEVELOPMENT = process.env.NODE_ENV === 'development'; 13 | -------------------------------------------------------------------------------- /src/ui/common/config/errors/UserInterfaceError.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'core/common/errors/BaseError'; 2 | 3 | export class UserInterfaceError extends BaseError { 4 | constructor( 5 | public readonly status: number, 6 | public readonly code?: string, 7 | public readonly message: string = '', 8 | public readonly name: string = '' 9 | ) { 10 | super(code, message, name); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/ui/common/config/errors/handlers/errorHandler.ts: -------------------------------------------------------------------------------- 1 | import { Application, NextFunction, Request, Response } from 'express'; 2 | 3 | import { 4 | INTERNAL_SERVER_ERROR, 5 | NOT_FOUND, 6 | UNPROCESSABLE_ENTITY, 7 | } from 'http-status-codes'; 8 | 9 | import { BaseError } from 'core/common/errors/BaseError'; 10 | import { CoreError } from 'core/common/errors/CoreError'; 11 | import { ErrorResponse } from 'ui/common/config/errors/models/ErrorResponse'; 12 | import { UserInterfaceError } from 'ui/common/config/errors/UserInterfaceError'; 13 | 14 | export const errorHandler = (app: Application) => 15 | app.use( 16 | (error: BaseError, req: Request, res: Response, next: NextFunction) => { 17 | next(); 18 | switch (error.constructor) { 19 | case UserInterfaceError: 20 | return res 21 | .status((error as UserInterfaceError).status) 22 | .json(new ErrorResponse(error.code, error.message)); 23 | case CoreError: 24 | return res 25 | .status(UNPROCESSABLE_ENTITY) 26 | .json(new ErrorResponse(error.code, error.message)); 27 | case BaseError: 28 | return res 29 | .status(NOT_FOUND) 30 | .json(new ErrorResponse(error.code, error.message)); 31 | default: 32 | return res 33 | .status(INTERNAL_SERVER_ERROR) 34 | .json( 35 | new ErrorResponse(INTERNAL_SERVER_ERROR.toString(), error.message) 36 | ); 37 | } 38 | } 39 | ); 40 | -------------------------------------------------------------------------------- /src/ui/common/config/errors/models/ErrorResponse.ts: -------------------------------------------------------------------------------- 1 | export class ErrorResponse { 2 | constructor( 3 | public readonly code?: string, 4 | public readonly message?: string 5 | ) {} 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/common/config/logger/BaseLogger.ts: -------------------------------------------------------------------------------- 1 | export abstract class BaseLogger { 2 | protected readonly logger: T; 3 | 4 | constructor(logger: T) { 5 | this.logger = logger; 6 | } 7 | 8 | public getLogger(): T { 9 | return this.logger; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/ui/common/config/logger/ILogger.ts: -------------------------------------------------------------------------------- 1 | export interface ILogger { 2 | initialize(): void; 3 | write(message: string): void; 4 | } 5 | -------------------------------------------------------------------------------- /src/ui/common/mappings/UIMapper.ts: -------------------------------------------------------------------------------- 1 | import { injectable } from 'inversify'; 2 | import { Mapper } from '@wufe/mapper'; 3 | 4 | import { UserDomainToUserUI } from 'ui/common/mappings/User/UserDomainToUserUI'; 5 | 6 | @injectable() 7 | export class UIMapper { 8 | public readonly mapper: Mapper; 9 | 10 | constructor() { 11 | this.mapper = new Mapper().withConfiguration(configuration => 12 | configuration 13 | .shouldIgnoreSourcePropertiesIfNotInDestination(true) 14 | .shouldAutomaticallyMapArrays(true) 15 | ); 16 | 17 | this.initialize(); 18 | } 19 | 20 | private initialize(): void { 21 | UserDomainToUserUI().configureMapping(this.mapper); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/ui/common/mappings/User/UserDomainToUserUI.ts: -------------------------------------------------------------------------------- 1 | import { Mapper } from '@wufe/mapper'; 2 | 3 | import { IMapping } from 'core/common/mapper/IMapping'; 4 | 5 | import { User } from 'core/domain/User/User'; 6 | import { DOMAIN_MAPPING_IDENTIFIERS } from 'core/CoreModuleSymbols'; 7 | 8 | import { User as UserUI } from 'ui/common/models/User'; 9 | import { UI_MAPPINGS_IDENTIFIERS } from 'ui/UiModuleSymbols'; 10 | 11 | export const UserDomainToUserUI = (): IMapping => ({ 12 | configureMapping(mapper: Mapper): void { 13 | mapper.createMap( 14 | { 15 | destination: UI_MAPPINGS_IDENTIFIERS.USER_UI, 16 | source: DOMAIN_MAPPING_IDENTIFIERS.USER_DOMAIN, 17 | }, 18 | User 19 | ); 20 | }, 21 | }); 22 | -------------------------------------------------------------------------------- /src/ui/common/models/User.ts: -------------------------------------------------------------------------------- 1 | export class User { 2 | constructor( 3 | public readonly id: number, 4 | public readonly firstName: string, 5 | public readonly email: string, 6 | public readonly role: string 7 | ) {} 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description - required by inversify to have metadata for @controller annotation 3 | */ 4 | export { AuthenticationController } from 'ui/Portal/Authentication/rest/v1/AuthenticationController'; 5 | export { EquipmentController } from 'ui/Portal/Equipment/rest/v1/EquipmentController'; 6 | export { UserController } from 'ui/Portal/User/rest/v1/UserController'; 7 | -------------------------------------------------------------------------------- /src/ui/shared/Authentication/graphql/AuthenticationMutation.ts: -------------------------------------------------------------------------------- 1 | import { IResolverObject } from 'apollo-server-express'; 2 | 3 | import { inject, injectable } from 'inversify'; 4 | 5 | import { UI_APPLICATION_IDENTIFIERS } from 'ui/UiModuleSymbols'; 6 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 7 | import { IAuthenticationHandler } from 'ui/common/config/application/common/auth/IAuthenticationHandler'; 8 | 9 | import { AuthenticationRequest } from 'core/applicationServices/Authentication/requests/AuthenticationRequest'; 10 | import { AuthenticateInput } from 'ui/shared/Authentication/graphql/inputs/AuthenticateInput'; 11 | 12 | @injectable() 13 | export class AuthenticationMutation implements IResolver { 14 | readonly resolvers: IResolverObject; 15 | 16 | constructor( 17 | @inject(UI_APPLICATION_IDENTIFIERS.GRAPHQL_JWT_AUTHENTICATION_HANDLER) 18 | private readonly authenticationHandler: IAuthenticationHandler 19 | ) { 20 | this.resolvers = { 21 | authenticate: this.authenticate, 22 | }; 23 | } 24 | 25 | private authenticate = ( 26 | _root: unknown, 27 | { input: { email, password } }: { input: AuthenticateInput } 28 | ) => { 29 | return this.authenticationHandler.authenticate( 30 | new AuthenticationRequest(email, password) 31 | ); 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /src/ui/shared/Authentication/graphql/gql/Authentication.graphql: -------------------------------------------------------------------------------- 1 | extend type Mutation { 2 | authenticate(input: AuthenticateInput): Authentication! 3 | } 4 | 5 | input AuthenticateInput { 6 | email: String! 7 | password: String! 8 | } 9 | 10 | type Authentication { 11 | token: String! 12 | } 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/ui/shared/Authentication/graphql/inputs/AuthenticateInput.ts: -------------------------------------------------------------------------------- 1 | export type AuthenticateInput = { 2 | email: string; 3 | password: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/ui/shared/common/graphql/SharedMutation.ts: -------------------------------------------------------------------------------- 1 | import { inject, injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | 7 | import { UI_SCHEMA_IDENTIFIERS } from 'ui/UiModuleSymbols'; 8 | 9 | @injectable() 10 | export class SharedMutation implements IResolver { 11 | readonly resolvers: IResolverObject; 12 | 13 | constructor( 14 | @inject(UI_SCHEMA_IDENTIFIERS.AUTHENTICATION_MUTATIONS) 15 | public readonly authenticationMutations: IResolver 16 | ) { 17 | this.resolvers = { 18 | ...this.authenticationMutations.resolvers, 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/ui/shared/common/graphql/SharedQuery.ts: -------------------------------------------------------------------------------- 1 | import { injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | 7 | @injectable() 8 | export class SharedQuery implements IResolver { 9 | readonly resolvers: IResolverObject; 10 | 11 | constructor() { 12 | this.resolvers = {}; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/ui/shared/common/graphql/SharedSubQuery.ts: -------------------------------------------------------------------------------- 1 | import { injectable } from 'inversify'; 2 | 3 | import { IResolverObject } from 'apollo-server-express'; 4 | 5 | import { IResolver } from 'ui/common/config/application/apollo/common/IResolver'; 6 | 7 | @injectable() 8 | export class SharedSubQuery implements IResolver { 9 | readonly resolvers: IResolverObject; 10 | 11 | constructor() { 12 | this.resolvers = {}; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /stryker.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | mutator: 'typescript', 4 | packageManager: 'yarn', 5 | reporters: ['progress'], 6 | testRunner: 'mocha', 7 | transpilers: [ 8 | 'typescript' 9 | ], 10 | files: [ 11 | "ormconfig.js", 12 | "src/**/*.ts", 13 | "test/**/*.ts", 14 | ".env.test" 15 | ], 16 | fileLogLevel: 'debug', 17 | testFramework: 'mocha', 18 | coverageAnalysis: 'perTest', 19 | tsconfigFile: 'tsconfig.json', 20 | mutate: ['src/**/*.ts'], 21 | mochaOptions: { 22 | spec: [ 'test/**/*.spec.ts' ], 23 | config: 'test/.mocharc.json', 24 | } 25 | }); 26 | }; 27 | -------------------------------------------------------------------------------- /test/.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "diff": true, 3 | "exit": true, 4 | "recursive": true, 5 | "reporter": "spec", 6 | "require": [ 7 | "dotenv/config", 8 | "ts-node/register", 9 | "tsconfig-paths/register" 10 | ], 11 | "extension": [ 12 | "ts" 13 | ], 14 | "spec": "test/**/*.spec.ts", 15 | "slow": 75, 16 | "timeout": 10000, 17 | "ui": "bdd" 18 | } 19 | -------------------------------------------------------------------------------- /test/config/db/RollbackException.ts: -------------------------------------------------------------------------------- 1 | export class RollbackException extends Error {} 2 | -------------------------------------------------------------------------------- /test/config/db/TransactionCreator.ts: -------------------------------------------------------------------------------- 1 | import { 2 | IsolationLevel, 3 | Propagation, 4 | Transactional, 5 | } from 'typeorm-transactional-cls-hooked'; 6 | 7 | import { RollbackException } from 'config/db/RollbackException'; 8 | 9 | import { RunFunction } from 'config/types/RunFunction'; 10 | 11 | export class TransactionCreator { 12 | @Transactional({ 13 | connectionName: () => process.env.ORM_CONNECTION, 14 | propagation: Propagation.NESTED, 15 | isolationLevel: IsolationLevel.SERIALIZABLE, 16 | }) 17 | static async run(func: RunFunction) { 18 | await func(); 19 | throw new RollbackException(`Transaction rollback`); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/config/helpers/clearTestDB.ts: -------------------------------------------------------------------------------- 1 | import { getConnection } from 'typeorm'; 2 | 3 | import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions'; 4 | 5 | import { getPostgresConnection } from 'config/helpers/getPostgresConnection'; 6 | 7 | import { getCurrentConnection } from 'config/helpers/getCurrentConnection'; 8 | 9 | export const clearTestDB = async (testName?: string): Promise => { 10 | const connection = await getCurrentConnection(); 11 | 12 | getConnection(testName).close(); 13 | 14 | const db = await getPostgresConnection( 15 | connection.options as PostgresConnectionOptions 16 | ); 17 | 18 | // db.$pool.end(); 19 | 20 | await db.none('DROP DATABASE $1:name', testName); 21 | }; 22 | -------------------------------------------------------------------------------- /test/config/helpers/getCurrentConnection.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Connection, 3 | createConnection, 4 | getConnection, 5 | getConnectionManager, 6 | } from 'typeorm'; 7 | 8 | export const getCurrentConnection = async (): Promise => { 9 | if (!getConnectionManager().has(process.env.ORM_CONNECTION || '')) { 10 | await createConnection(process.env.ORM_CONNECTION || ''); 11 | } 12 | return getConnection(process.env.ORM_CONNECTION); 13 | }; 14 | -------------------------------------------------------------------------------- /test/config/helpers/getPostgresConnection.ts: -------------------------------------------------------------------------------- 1 | import pgPromise, { IDatabase } from 'pg-promise'; 2 | import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions'; 3 | 4 | export const getPostgresConnection = ({ 5 | database, 6 | port, 7 | username, 8 | password, 9 | }: PostgresConnectionOptions): IDatabase<{}> => { 10 | const pgp = pgPromise(); 11 | 12 | return pgp({ 13 | database, 14 | port, 15 | user: username, 16 | password, 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /test/config/helpers/inTransaction.ts: -------------------------------------------------------------------------------- 1 | import { RollbackException } from 'config/db/RollbackException'; 2 | import { RunFunction } from 'config/types/RunFunction'; 3 | import { TransactionCreator } from 'config/db/TransactionCreator'; 4 | 5 | export const inTransaction = (func: RunFunction) => { 6 | return async () => { 7 | try { 8 | await TransactionCreator.run(func); 9 | } catch (e) { 10 | if (e instanceof RollbackException) { 11 | } else { 12 | throw e; 13 | } 14 | } 15 | }; 16 | }; 17 | -------------------------------------------------------------------------------- /test/config/helpers/prepareAuthenticationToken.ts: -------------------------------------------------------------------------------- 1 | import { getConnection } from 'typeorm'; 2 | 3 | import { User } from 'infrastructure/database/entities/User'; 4 | 5 | import { JWTTokenUtil } from '../../../src/ui/common/config/application/common/auth/utils/JWTTokenUtil'; 6 | 7 | export const prepareAuthenticationToken = async ( 8 | email: string, 9 | dbName?: string 10 | ): Promise => { 11 | const jwtTokenUtil = new JWTTokenUtil(); 12 | 13 | const user = await getConnection(dbName) 14 | .getRepository(User) 15 | .createQueryBuilder() 16 | .leftJoinAndSelect('User.role', 'Role') 17 | .where('User.email = :email', { email }) 18 | .getOne(); 19 | 20 | if (!user) { 21 | return ''; 22 | } 23 | 24 | return jwtTokenUtil.generateToken( 25 | { 26 | id: user.id, 27 | firstName: user.firstName, 28 | email: user.email, 29 | role: user.role.name, 30 | }, 31 | process.env.APP_TOKEN_SECRET || '', 32 | process.env.APP_TOKEN_LIFE || '', 33 | 'user' 34 | ); 35 | }; 36 | -------------------------------------------------------------------------------- /test/config/helpers/prepareTestApp.ts: -------------------------------------------------------------------------------- 1 | import { InversifyExpressServer } from 'inversify-express-utils'; 2 | 3 | import { Application } from 'express'; 4 | 5 | import { ExpressApplication } from 'ui/common/config/application/express/ExpressApplication'; 6 | 7 | import { AppContainer } from 'dependency/AppContainer'; 8 | 9 | import { UI_APPLICATION_IDENTIFIERS } from 'ui/UiModuleSymbols'; 10 | 11 | export const prepareTestApp = async (): Promise => { 12 | const container = new AppContainer(); 13 | 14 | container.init(); 15 | 16 | container 17 | .get(UI_APPLICATION_IDENTIFIERS.EXPRESS_APPLICATION) 18 | .initialize(); 19 | 20 | return container 21 | .get( 22 | UI_APPLICATION_IDENTIFIERS.INVERSIFY_APPLICATION 23 | ) 24 | .build(); 25 | }; 26 | -------------------------------------------------------------------------------- /test/config/helpers/prepareTestDB.ts: -------------------------------------------------------------------------------- 1 | import { Connection } from 'typeorm'; 2 | import { createConnection } from 'typeorm-seeding'; 3 | 4 | import 'infrastructure/database/fixtures/factories/RoleFactory'; 5 | import 'infrastructure/database/fixtures/factories/UserFactory'; 6 | import 'infrastructure/database/fixtures/factories/EquipmentFactory'; 7 | 8 | import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions'; 9 | 10 | import { prepareTestTransaction } from 'config/helpers/prepareTestTransaction'; 11 | import { getPostgresConnection } from 'config/helpers/getPostgresConnection'; 12 | import { getCurrentConnection } from 'config/helpers/getCurrentConnection'; 13 | 14 | prepareTestTransaction(); 15 | 16 | export const prepareTestDB = async (testName?: string): Promise => { 17 | const connection = await getCurrentConnection(); 18 | 19 | const options = connection.options as PostgresConnectionOptions; 20 | 21 | const db = await getPostgresConnection( 22 | connection.options as PostgresConnectionOptions 23 | ); 24 | 25 | await db.none('CREATE DATABASE $1:name', testName); 26 | db.$pool.end(); 27 | 28 | const dbConnecton = await createConnection({ 29 | ...options, 30 | name: testName, 31 | database: testName, 32 | }); 33 | 34 | await dbConnecton.dropDatabase(); 35 | await dbConnecton.runMigrations(); 36 | return dbConnecton; 37 | }; 38 | -------------------------------------------------------------------------------- /test/config/helpers/prepareTestTransaction.ts: -------------------------------------------------------------------------------- 1 | import { 2 | initializeTransactionalContext, 3 | patchTypeORMRepositoryWithBaseRepository, 4 | } from 'typeorm-transactional-cls-hooked'; 5 | 6 | export const prepareTestTransaction = () => { 7 | initializeTransactionalContext(); 8 | patchTypeORMRepositoryWithBaseRepository(); 9 | }; 10 | -------------------------------------------------------------------------------- /test/config/mocks/mockRepositoryConnectionName.ts: -------------------------------------------------------------------------------- 1 | import sinon from 'sinon'; 2 | 3 | export const mockRepositoryConnectionName = (testName?: string) => { 4 | sinon.stub(process.env, 'ORM_CONNECTION').value(testName); 5 | }; 6 | -------------------------------------------------------------------------------- /test/config/seeds/AuthenticationSeed.ts: -------------------------------------------------------------------------------- 1 | import { Factory, Seeder } from 'typeorm-seeding'; 2 | 3 | import { Role } from 'infrastructure/database/entities/Role'; 4 | import { USER_ROLE } from 'infrastructure/database/enum/UserRole'; 5 | import { User } from 'infrastructure/database/entities/User'; 6 | 7 | export class AuthenticationSeed implements Seeder { 8 | async run(factory: Factory): Promise { 9 | await this.prepareAuthenticationMemberUserSeed(factory); 10 | await this.prepareAuthenticationAdminUserSeed(factory); 11 | } 12 | 13 | private async prepareAuthenticationMemberUserSeed( 14 | factory: Factory 15 | ): Promise { 16 | const memberRole = await factory(Role)().create({ 17 | name: USER_ROLE.MEMBER, 18 | }); 19 | 20 | await factory(User)().create({ 21 | email: 'onion_member_test@example.com', 22 | role: memberRole, 23 | }); 24 | } 25 | 26 | private async prepareAuthenticationAdminUserSeed( 27 | factory: Factory 28 | ): Promise { 29 | const adminRole = await factory(Role)().create({ 30 | name: USER_ROLE.ADMIN, 31 | }); 32 | 33 | await factory(User)().create({ 34 | email: 'onion_admin_test@example.com', 35 | role: adminRole, 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/config/seeds/UserSeed.ts: -------------------------------------------------------------------------------- 1 | import { Factory, Seeder, times } from 'typeorm-seeding'; 2 | 3 | import { Role } from 'infrastructure/database/entities/Role'; 4 | import { USER_ROLE } from 'infrastructure/database/enum/UserRole'; 5 | import { User } from 'infrastructure/database/entities/User'; 6 | import { Equipment } from 'infrastructure/database/entities/Equipment'; 7 | 8 | export class UserSeed implements Seeder { 9 | async run(factory: Factory): Promise { 10 | await this.prepareUserSeedToDelete(factory); 11 | } 12 | 13 | private async prepareUserSeedToDelete(factory: Factory): Promise { 14 | const memberRole = await factory(Role)().create({ 15 | name: USER_ROLE.MEMBER, 16 | }); 17 | 18 | const user = await factory(User)().create({ 19 | email: 'onion_member_test_delete@example.com', 20 | role: memberRole, 21 | }); 22 | 23 | await times(5, async () => { 24 | await factory(Equipment)().create({ 25 | user, 26 | }); 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/config/types/RunFunction.ts: -------------------------------------------------------------------------------- 1 | export type RunFunction = () => Promise | void; 2 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "emitDecoratorMetadata": true, 4 | "experimentalDecorators": true, 5 | "allowSyntheticDefaultImports": true, 6 | "resolveJsonModule": true, 7 | "target": "es6", 8 | "module": "commonjs", 9 | "outDir": "dist", 10 | "strict": true, 11 | "sourceMap": true, 12 | "moduleResolution": "node", 13 | "lib": [ 14 | "es5", 15 | "es6", 16 | "dom" 17 | ], 18 | "plugins": [ 19 | { "transform": "@zerollup/ts-transform-paths" } 20 | ], 21 | "esModuleInterop": true 22 | }, 23 | "include": [ 24 | "src/**/*.ts", 25 | "tests/**/*.ts" 26 | ], 27 | "exclude": [ 28 | "node_modules" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "core/*": ["src/core/*"], 7 | "dependency/*": ["src/dependency/*"], 8 | "infrastructure/*": ["src/infrastructure/*"], 9 | "ui/*": ["src/ui/*"], 10 | "config/*": ["test/config/*"], 11 | "*": [ 12 | "@types/*" 13 | ] 14 | } 15 | } 16 | } 17 | --------------------------------------------------------------------------------