@merkaly/api 0.2.4-6 → 0.2.4-7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. package/.DS_Store +0 -0
  2. package/.bin/deploy.sh +9 -0
  3. package/.bin/package.sh +7 -0
  4. package/.docker/Dockerfile +21 -0
  5. package/.dockerignore +12 -0
  6. package/.env +21 -0
  7. package/.eslintignore +8 -0
  8. package/.eslintrc.js +35 -0
  9. package/.github/dependabot.yml +17 -0
  10. package/.github/semantic.yml +5 -0
  11. package/.github/workflows/pull_request.yml +35 -0
  12. package/.gitignore +42 -0
  13. package/.husky/.gitignore +1 -0
  14. package/.husky/commit-msg +5 -0
  15. package/.husky/common.sh +8 -0
  16. package/.husky/pre-commit +5 -0
  17. package/.husky/pre-push +4 -0
  18. package/.idea/.gitignore +5 -0
  19. package/.idea/api.iml +13 -0
  20. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  21. package/.idea/inspectionProfiles/Project_Default.xml +11 -0
  22. package/.idea/modules.xml +8 -0
  23. package/.idea/vcs.xml +12 -0
  24. package/.idea/workspace.xml +2320 -0
  25. package/.output/modules/sales/orders/order.entity.d.ts +1 -1
  26. package/.output/modules/sales/orders/order.validator.js +2 -3
  27. package/authCertificate.pem +19 -0
  28. package/cloudbuild.yaml +20 -0
  29. package/commitlint.config.js +3 -0
  30. package/jest.config.js +14 -0
  31. package/merkaly-api-0.2.4-6.tgz +0 -0
  32. package/nest-cli.json +9 -0
  33. package/package.json +8 -7
  34. package/serviceAccount.json +7 -0
  35. package/src/abstract/absctract.listener.ts +2 -0
  36. package/src/abstract/abstract.controller.ts +27 -0
  37. package/src/abstract/abstract.entity.ts +19 -0
  38. package/src/abstract/abstract.exception.ts +56 -0
  39. package/src/abstract/abstract.fixture.ts +7 -0
  40. package/src/abstract/abstract.migration.ts +13 -0
  41. package/src/abstract/abstract.repository.ts +79 -0
  42. package/src/abstract/abstract.router.ts +7 -0
  43. package/src/abstract/abstract.validator.ts +62 -0
  44. package/src/app.config.ts +57 -0
  45. package/src/app.console.ts +30 -0
  46. package/src/app.controller.ts +48 -0
  47. package/src/app.migration.ts +7 -0
  48. package/src/app.module.ts +92 -0
  49. package/src/app.strategy.ts +25 -0
  50. package/src/commands/assets.command.ts +38 -0
  51. package/src/commands/deploy.command.ts +6 -0
  52. package/src/commands/fixture.command.ts +11 -0
  53. package/src/commands/generate.command.ts +286 -0
  54. package/src/decorators/public.decorator.ts +5 -0
  55. package/src/decorators/user.decorator.ts +21 -0
  56. package/src/exceptions/missing-identity.exception.ts +11 -0
  57. package/src/exceptions/store-not-implemented.exception.ts +13 -0
  58. package/src/exceptions/store-not-recognized.exception.ts +11 -0
  59. package/src/guards/auth.guard.ts +43 -0
  60. package/src/guards/organization.guard.ts +39 -0
  61. package/src/interceptors/mongo.interceptor.ts +16 -0
  62. package/src/main.ts +37 -0
  63. package/src/middlewares/logger.middleware.ts +15 -0
  64. package/src/middlewares/organization.middleware.ts +76 -0
  65. package/src/migrations/1667226478717-product_price_enhance.ts +29 -0
  66. package/src/migrations/1667329249561-product_add_seo_code_dimension.ts +37 -0
  67. package/src/migrations/1667601099139-product_activve_and_hashtag.ts +35 -0
  68. package/src/migrations/1668136428972-content_banners-use-as-image.ts +56 -0
  69. package/src/migrations/1680483744321-order-billing-shipping-status.ts +32 -0
  70. package/src/modules/assets/asset.controller.ts +33 -0
  71. package/src/modules/assets/asset.entity.ts +26 -0
  72. package/src/modules/assets/asset.module.ts +21 -0
  73. package/src/modules/assets/asset.repository.ts +51 -0
  74. package/src/modules/assets/asset.schema.ts +4 -0
  75. package/src/modules/assets/asset.service.ts +41 -0
  76. package/src/modules/auth/auth.controller.ts +42 -0
  77. package/src/modules/auth/auth.module.ts +18 -0
  78. package/src/modules/auth/logout.ts +0 -0
  79. package/src/modules/command.module.ts +19 -0
  80. package/src/modules/content/banners/banner.controller.ts +56 -0
  81. package/src/modules/content/banners/banner.entity.ts +17 -0
  82. package/src/modules/content/banners/banner.fixture.ts +19 -0
  83. package/src/modules/content/banners/banner.listener.ts +6 -0
  84. package/src/modules/content/banners/banner.module.ts +21 -0
  85. package/src/modules/content/banners/banner.repository.ts +38 -0
  86. package/src/modules/content/banners/banner.schema.ts +4 -0
  87. package/src/modules/content/banners/banner.types.ts +7 -0
  88. package/src/modules/content/banners/banner.validator.ts +19 -0
  89. package/src/modules/content/content.module.ts +20 -0
  90. package/src/modules/content/pages/page.controller.ts +53 -0
  91. package/src/modules/content/pages/page.entity.ts +27 -0
  92. package/src/modules/content/pages/page.fixture.ts +19 -0
  93. package/src/modules/content/pages/page.listener.ts +6 -0
  94. package/src/modules/content/pages/page.module.ts +21 -0
  95. package/src/modules/content/pages/page.repository.ts +44 -0
  96. package/src/modules/content/pages/page.schema.ts +4 -0
  97. package/src/modules/content/pages/page.types.ts +9 -0
  98. package/src/modules/content/pages/page.validator.ts +29 -0
  99. package/src/modules/global.module.ts +70 -0
  100. package/src/modules/insight/controllers/address.controller.ts +29 -0
  101. package/src/modules/insight/controllers/order.controller.ts +70 -0
  102. package/src/modules/insight/controllers/products.controller.ts +18 -0
  103. package/src/modules/insight/insight.module.ts +24 -0
  104. package/src/modules/insight/validators/order.validator.ts +10 -0
  105. package/src/modules/inventory/brands/brand.controller.ts +59 -0
  106. package/src/modules/inventory/brands/brand.entity.ts +14 -0
  107. package/src/modules/inventory/brands/brand.exception.ts +9 -0
  108. package/src/modules/inventory/brands/brand.listener.ts +18 -0
  109. package/src/modules/inventory/brands/brand.module.ts +19 -0
  110. package/src/modules/inventory/brands/brand.repository.ts +39 -0
  111. package/src/modules/inventory/brands/brand.schema.ts +4 -0
  112. package/src/modules/inventory/brands/brand.validator.ts +23 -0
  113. package/src/modules/inventory/categories/category.controller.ts +59 -0
  114. package/src/modules/inventory/categories/category.entity.ts +21 -0
  115. package/src/modules/inventory/categories/category.exception.ts +9 -0
  116. package/src/modules/inventory/categories/category.fixture.ts +18 -0
  117. package/src/modules/inventory/categories/category.listener.ts +17 -0
  118. package/src/modules/inventory/categories/category.module.ts +19 -0
  119. package/src/modules/inventory/categories/category.repository.ts +40 -0
  120. package/src/modules/inventory/categories/category.schema.ts +4 -0
  121. package/src/modules/inventory/categories/category.validator.ts +30 -0
  122. package/src/modules/inventory/inventory.module.ts +22 -0
  123. package/src/modules/inventory/products/entities/code.entity.ts +15 -0
  124. package/src/modules/inventory/products/entities/dimension.entity.ts +18 -0
  125. package/src/modules/inventory/products/entities/price.entity.ts +12 -0
  126. package/src/modules/inventory/products/entities/seo.entity.ts +15 -0
  127. package/src/modules/inventory/products/product.controller.ts +59 -0
  128. package/src/modules/inventory/products/product.entity.ts +53 -0
  129. package/src/modules/inventory/products/product.exception.ts +9 -0
  130. package/src/modules/inventory/products/product.fixture.ts +19 -0
  131. package/src/modules/inventory/products/product.listener.ts +27 -0
  132. package/src/modules/inventory/products/product.module.ts +20 -0
  133. package/src/modules/inventory/products/product.repository.ts +108 -0
  134. package/src/modules/inventory/products/product.schema.ts +15 -0
  135. package/src/modules/inventory/products/product.validator.ts +71 -0
  136. package/src/modules/inventory/products/validators/code.validator.ts +15 -0
  137. package/src/modules/inventory/products/validators/dimension.validator.ts +19 -0
  138. package/src/modules/inventory/products/validators/price.validator.ts +10 -0
  139. package/src/modules/inventory/products/validators/seo.validator.ts +15 -0
  140. package/src/modules/inventory/properties/property.controller.ts +56 -0
  141. package/src/modules/inventory/properties/property.entity.ts +18 -0
  142. package/src/modules/inventory/properties/property.exception.ts +9 -0
  143. package/src/modules/inventory/properties/property.listener.ts +20 -0
  144. package/src/modules/inventory/properties/property.module.ts +21 -0
  145. package/src/modules/inventory/properties/property.repository.ts +23 -0
  146. package/src/modules/inventory/properties/property.schema.ts +4 -0
  147. package/src/modules/inventory/properties/property.validator.ts +27 -0
  148. package/src/modules/sales/clients/client.controller.ts +60 -0
  149. package/src/modules/sales/clients/client.entity.ts +25 -0
  150. package/src/modules/sales/clients/client.exception.ts +9 -0
  151. package/src/modules/sales/clients/client.listener.ts +20 -0
  152. package/src/modules/sales/clients/client.module.ts +19 -0
  153. package/src/modules/sales/clients/client.repository.ts +37 -0
  154. package/src/modules/sales/clients/client.schema.ts +4 -0
  155. package/src/modules/sales/clients/client.validator.ts +43 -0
  156. package/src/modules/sales/orders/billing/billing.entity.ts +22 -0
  157. package/src/modules/sales/orders/billing/billing.types.ts +10 -0
  158. package/src/modules/sales/orders/billing/billing.validator.ts +21 -0
  159. package/src/modules/sales/orders/billing/entities/address.entity.ts +27 -0
  160. package/src/modules/sales/orders/billing/entities/customer.entity.ts +14 -0
  161. package/src/modules/sales/orders/billing/entities/status.entity.ts +16 -0
  162. package/src/modules/sales/orders/billing/validators/address.validator.ts +28 -0
  163. package/src/modules/sales/orders/billing/validators/customer.validator.ts +14 -0
  164. package/src/modules/sales/orders/customer/customer.entity.ts +14 -0
  165. package/src/modules/sales/orders/customer/customer.validator.ts +14 -0
  166. package/src/modules/sales/orders/item/item.entity.ts +21 -0
  167. package/src/modules/sales/orders/item/item.schema.ts +8 -0
  168. package/src/modules/sales/orders/item/item.validator.ts +10 -0
  169. package/src/modules/sales/orders/order.controller.ts +93 -0
  170. package/src/modules/sales/orders/order.entity.ts +47 -0
  171. package/src/modules/sales/orders/order.listener.ts +20 -0
  172. package/src/modules/sales/orders/order.module.ts +19 -0
  173. package/src/modules/sales/orders/order.repository.ts +189 -0
  174. package/src/modules/sales/orders/order.schema.ts +35 -0
  175. package/src/modules/sales/orders/order.validator.ts +72 -0
  176. package/src/modules/sales/orders/shipping/entities/address.entity.ts +27 -0
  177. package/src/modules/sales/orders/shipping/entities/customer.entity.ts +14 -0
  178. package/src/modules/sales/orders/shipping/entities/status.entity.ts +16 -0
  179. package/src/modules/sales/orders/shipping/shipping.entity.ts +25 -0
  180. package/src/modules/sales/orders/shipping/shipping.types.ts +12 -0
  181. package/src/modules/sales/orders/shipping/shipping.validator.ts +25 -0
  182. package/src/modules/sales/orders/shipping/validators/address.validator.ts +28 -0
  183. package/src/modules/sales/orders/shipping/validators/customer.validator.ts +14 -0
  184. package/src/modules/sales/orders/status/status.entity.ts +16 -0
  185. package/src/modules/sales/orders/status/status.validator.ts +8 -0
  186. package/src/modules/sales/sales.module.ts +20 -0
  187. package/src/modules/setting/connections/connection.controller.ts +27 -0
  188. package/src/modules/setting/connections/connection.module.ts +17 -0
  189. package/src/modules/setting/connections/connection.validator.ts +15 -0
  190. package/src/modules/setting/layout/layout.controller.ts +34 -0
  191. package/src/modules/setting/layout/layout.entity.ts +13 -0
  192. package/src/modules/setting/layout/layout.listener.ts +7 -0
  193. package/src/modules/setting/layout/layout.module.ts +21 -0
  194. package/src/modules/setting/layout/layout.repository.ts +29 -0
  195. package/src/modules/setting/layout/layout.schema.ts +4 -0
  196. package/src/modules/setting/members/member.controller.ts +22 -0
  197. package/src/modules/setting/members/member.module.ts +17 -0
  198. package/src/modules/setting/members/member.validator.ts +3 -0
  199. package/src/modules/setting/organization/organization.controller.ts +33 -0
  200. package/src/modules/setting/organization/organization.entity.ts +27 -0
  201. package/src/modules/setting/organization/organization.listener.ts +46 -0
  202. package/src/modules/setting/organization/organization.module.ts +21 -0
  203. package/src/modules/setting/organization/organization.repository.ts +55 -0
  204. package/src/modules/setting/organization/organization.types.ts +65 -0
  205. package/src/modules/setting/organization/organization.validator.ts +56 -0
  206. package/src/modules/setting/setting.module.ts +23 -0
  207. package/src/modules/setting/theme/theme.controller.ts +34 -0
  208. package/src/modules/setting/theme/theme.entity.ts +13 -0
  209. package/src/modules/setting/theme/theme.listener.ts +6 -0
  210. package/src/modules/setting/theme/theme.module.ts +21 -0
  211. package/src/modules/setting/theme/theme.repository.ts +23 -0
  212. package/src/modules/setting/theme/theme.schema.ts +4 -0
  213. package/src/modules/users/user.controller.ts +75 -0
  214. package/src/modules/users/user.module.ts +20 -0
  215. package/src/modules/users/user.validator.ts +28 -0
  216. package/src/providers/auth0.provider.ts +36 -0
  217. package/src/providers/storage.provider.ts +22 -0
  218. package/src/services/auth0.service.ts +7 -0
  219. package/src/services/logger.service.ts +33 -0
  220. package/src/services/mongo.service.ts +44 -0
  221. package/src/services/storage.service.ts +39 -0
  222. package/src/types.ts +19 -0
  223. package/tsconfig.json +40 -0
  224. package/tsconfig.package.json +20 -0
  225. package/yarn.lock +8782 -0
@@ -0,0 +1,92 @@
1
+ import {
2
+ CacheModule,
3
+ Inject,
4
+ Logger,
5
+ MiddlewareConsumer,
6
+ Module,
7
+ ModuleMetadata,
8
+ NestModule,
9
+ RequestMethod,
10
+ Scope,
11
+ } from '@nestjs/common';
12
+ import { ConfigModule } from '@nestjs/config';
13
+ import { APP_INTERCEPTOR, RouterModule } from '@nestjs/core';
14
+ import { Routes } from '@nestjs/core/router/interfaces';
15
+ import { EventEmitter2, EventEmitterModule } from '@nestjs/event-emitter';
16
+ import { AppController } from './app.controller';
17
+ import { AppStrategy } from './app.strategy';
18
+ import { MongoInterceptor } from './interceptors/mongo.interceptor';
19
+ import { LoggerMiddleware } from './middlewares/logger.middleware';
20
+ import { OrganizationMiddleware } from './middlewares/organization.middleware';
21
+ import { AssetModule } from './modules/assets/asset.module';
22
+ import { CommandsModule } from './modules/command.module';
23
+ import { ContentModule } from './modules/content/content.module';
24
+ import { GlobalModule } from './modules/global.module';
25
+ import { InsightModule } from './modules/insight/insight.module';
26
+ import { InventoryModule } from './modules/inventory/inventory.module';
27
+ import { SettingModule } from './modules/setting/setting.module';
28
+ import { SalesModule } from './modules/sales/sales.module';
29
+ import { UserModule } from './modules/users/user.module';
30
+ import { LoggerService } from './services/logger.service';
31
+ import { AuthModule } from "./modules/auth/auth.module";
32
+
33
+ export const router = [
34
+ AssetModule,
35
+ AuthModule,
36
+ ContentModule,
37
+ InventoryModule,
38
+ InsightModule,
39
+ SettingModule,
40
+ SalesModule,
41
+ UserModule,
42
+ ];
43
+
44
+ const modules = [
45
+ ...router,
46
+ GlobalModule.register(),
47
+ CommandsModule.register(),
48
+ RouterModule.register(router as Routes),
49
+ CacheModule.register({ isGlobal: true }),
50
+ ConfigModule.forRoot({ isGlobal: true }),
51
+ EventEmitterModule.forRoot({ wildcard: true }),
52
+ ];
53
+
54
+ export const metadata: ModuleMetadata = {
55
+ controllers: [AppController],
56
+ imports: modules,
57
+ providers: [
58
+ AppStrategy,
59
+ {
60
+ provide: APP_INTERCEPTOR,
61
+ scope: Scope.REQUEST,
62
+ useClass: MongoInterceptor,
63
+ },
64
+ ],
65
+ };
66
+
67
+ @Module(metadata)
68
+ export class AppModule implements NestModule {
69
+ @Inject()
70
+ protected readonly $event: EventEmitter2;
71
+
72
+ @Inject()
73
+ protected readonly $logger: LoggerService;
74
+
75
+ public configure(consumer: MiddlewareConsumer): MiddlewareConsumer {
76
+ this.$event.onAny((event) => Logger.verbose(`Event emitted: ${event}`));
77
+
78
+ consumer
79
+ .apply(OrganizationMiddleware)
80
+ .exclude(
81
+ { path: '/health', method: RequestMethod.GET },
82
+ { path: '/organizations', method: RequestMethod.GET }
83
+ )
84
+ .forRoutes({ path: '/*', method: RequestMethod.ALL });
85
+
86
+ consumer
87
+ .apply(LoggerMiddleware)
88
+ .forRoutes({ path: '/*', method: RequestMethod.ALL });
89
+
90
+ return consumer;
91
+ }
92
+ }
@@ -0,0 +1,25 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import { PassportStrategy } from '@nestjs/passport';
3
+ import { readFileSync } from 'fs';
4
+ import { ExtractJwt, Strategy, StrategyOptions } from 'passport-jwt';
5
+ import { join } from 'path';
6
+ import { AppConfig } from './app.config';
7
+ import { DecodedUser } from './decorators/user.decorator';
8
+
9
+ @Injectable()
10
+ export class AppStrategy extends PassportStrategy(Strategy) {
11
+ public constructor() {
12
+ const strategy: StrategyOptions = {
13
+ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
14
+ audience: AppConfig.auth0.audience,
15
+ ignoreExpiration: true,
16
+ secretOrKey: process.env.AUTH_CERTIFICATE || readFileSync(join(process.cwd(), '/authCertificate.pem')),
17
+ };
18
+
19
+ super(strategy);
20
+ }
21
+
22
+ public validate(user: DecodedUser) {
23
+ return user;
24
+ }
25
+ }
@@ -0,0 +1,38 @@
1
+ import { Inject } from '@nestjs/common';
2
+ import { Command, Console } from 'nestjs-console';
3
+ import { AssetEntity } from '../modules/assets/asset.entity';
4
+ import { AssetRepository } from '../modules/assets/asset.repository';
5
+ import { ProductEntity } from '../modules/inventory/products/product.entity';
6
+ import { ProductRepository } from '../modules/inventory/products/product.repository';
7
+ import { StorageService } from '../services/storage.service';
8
+
9
+ @Console({ command: 'assets', description: 'Prune, cleand and remove assets' })
10
+ export class AssetsCommand {
11
+ @Inject()
12
+ protected readonly $storage: StorageService;
13
+
14
+ @Inject()
15
+ protected readonly $assetRepository: AssetRepository;
16
+
17
+ @Inject()
18
+ protected readonly $productRepository: ProductRepository;
19
+
20
+ @Command({ command: 'prune', description: 'Remove assest that hasnt relation with another entity' })
21
+ public async prune() {
22
+
23
+ const products: ProductEntity[] = await this.$productRepository.$model
24
+ .find({ files: { $exists: true, $not: { $size: 0 } } });
25
+
26
+ const files = products.map(({ files }) => files).flat();
27
+ const assets: AssetEntity[] = await this.$assetRepository.$model.find({ '_id': { $nin: files } });
28
+
29
+ // Remove automatically assets that not are stored in google storage
30
+ const externalAssets = assets.filter(asset => asset.url.startsWith('https://storage.googleapis.com') === false);
31
+ const internalAssets = assets.filter(asset => asset.url.startsWith('https://storage.googleapis.com'));
32
+
33
+ await this.$assetRepository.$model.find({ '_id': { $nin: files } });
34
+ await this.$assetRepository.$model.deleteMany({ _id: { $in: externalAssets.map(asset => asset._id) } });
35
+
36
+ return process.exit();
37
+ }
38
+ }
@@ -0,0 +1,6 @@
1
+ import { Console } from 'nestjs-console';
2
+
3
+ @Console({ command: 'deploy', description: 'Deploy App' })
4
+ export class DeployCommand {
5
+
6
+ }
@@ -0,0 +1,11 @@
1
+ import { Command, Console } from 'nestjs-console';
2
+
3
+ @Console({ command: 'fixture', description: 'Fill db with default required data' })
4
+ export class FixtureCommand {
5
+ @Command({ command: 'settings:payments', description: 'Add all default settings payments' })
6
+ public async settingsPayments() {
7
+ const types = [];
8
+
9
+ return Promise.all(types);
10
+ }
11
+ }
@@ -0,0 +1,286 @@
1
+ import { faker } from '@faker-js/faker';
2
+ import { Inject } from '@nestjs/common';
3
+ import { Command, Console, createSpinner } from 'nestjs-console';
4
+ import { AssetEntity } from '../modules/assets/asset.entity';
5
+ import { AssetRepository } from '../modules/assets/asset.repository';
6
+ import { PageFixture } from '../modules/content/pages/page.fixture';
7
+ import { PageRepository } from '../modules/content/pages/page.repository';
8
+ import { BrandRepository } from '../modules/inventory/brands/brand.repository';
9
+ import { CreateBrandValidator } from '../modules/inventory/brands/brand.validator';
10
+ import { CategoryRepository } from '../modules/inventory/categories/category.repository';
11
+ import { CreateCategoryValidator } from '../modules/inventory/categories/category.validator';
12
+ import { ProductRepository } from '../modules/inventory/products/product.repository';
13
+ import { CreateProductValidator } from '../modules/inventory/products/product.validator';
14
+ import { ClientRepository } from '../modules/sales/clients/client.repository';
15
+ import { CreateClientValidator } from '../modules/sales/clients/client.validator';
16
+ import { OrderRepository } from '../modules/sales/orders/order.repository';
17
+ import { CreateOrderValidator } from '../modules/sales/orders/order.validator';
18
+ import { StatusType } from '../modules/sales/orders/status/status.validator';
19
+ import { CustomerValidator } from "../modules/sales/orders/customer/customer.validator";
20
+ import { BillingMethod } from "../modules/sales/orders/billing/billing.types";
21
+ import { ShippingMethod } from "../modules/sales/orders/shipping/shipping.types";
22
+ import { MetaAddress } from "../types";
23
+
24
+ @Console({ command: 'generate', description: 'Generate massive fake data' })
25
+ export class GenerateCommand {
26
+ @Inject() protected readonly brandRepository: BrandRepository;
27
+ @Inject() protected readonly categoryRepository: CategoryRepository;
28
+ @Inject() protected readonly productRepository: ProductRepository;
29
+ @Inject() protected readonly clientRepository: ClientRepository;
30
+ @Inject() protected readonly assetRepository: AssetRepository;
31
+ @Inject() protected readonly orderRepository: OrderRepository;
32
+ @Inject() protected readonly pageRepository: PageRepository;
33
+
34
+ private static generate<T = unknown>(iterator: number, promiseCb: () => Promise<T>) {
35
+ const listOfPromises = [];
36
+
37
+ for (let i = 0; i < iterator; i++) {
38
+ listOfPromises.push(promiseCb());
39
+ }
40
+
41
+ return Promise.all(listOfPromises);
42
+ }
43
+
44
+ @Command({ command: 'brands <quantity>', description: 'Generate and persist fake brands' })
45
+ public async generateBrands(quantity = 5) {
46
+ const spinner = createSpinner();
47
+ spinner.start(`Creating ${quantity} new brands`);
48
+
49
+ const callback = () => {
50
+ const brand = new CreateBrandValidator();
51
+ brand.name = [faker.vehicle.manufacturer(), faker.vehicle.model(), faker.lorem.words(1)].join(' ');
52
+ brand.description = faker.lorem.sentence();
53
+
54
+ return this.brandRepository.create(brand);
55
+ };
56
+
57
+ return GenerateCommand.generate(quantity, callback)
58
+ .then(({ length }) => spinner.succeed(`Created ${length} of ${quantity} brands`));
59
+ }
60
+
61
+ @Command({ command: 'categories <quantity>', description: 'Generate and persist fake categories' })
62
+ public async generateCategories(quantity = 10) {
63
+ const spinner = createSpinner();
64
+ spinner.start(`Creating ${quantity} new categories`);
65
+
66
+ const callback = () => {
67
+ const category = new CreateCategoryValidator();
68
+ category.name = faker.lorem.words(3);
69
+ category.description = faker.lorem.sentence();
70
+
71
+ return this.categoryRepository.create(category);
72
+ };
73
+
74
+ return GenerateCommand.generate(quantity, callback)
75
+ .then(({ length }) => spinner.succeed(`Created ${length} of ${quantity} categories`));
76
+ }
77
+
78
+ @Command({ command: 'products <quantity>', description: 'Generate and persist fake products' })
79
+ public async generateProducts(quantity = 100) {
80
+ const spinner = createSpinner();
81
+ spinner.start(`Creating ${quantity} new products`);
82
+
83
+ const allBrands = await this.brandRepository.find();
84
+ const allCategories = await this.categoryRepository.find();
85
+
86
+ const callback = async () => {
87
+ const product = new CreateProductValidator();
88
+
89
+ product.name = `${faker.commerce.product()} ${faker.commerce.product()} ${faker.commerce.product()} `;
90
+ product.description = faker.commerce.productDescription();
91
+
92
+ product.price.sale = Number(faker.commerce.price(1000, 10000, 2));
93
+ product.price.purchase = product.price.sale - Number(faker.commerce.price(80, 100, 2));
94
+
95
+ product.brand = faker.helpers.arrayElement(allBrands.items)._id;
96
+ product.category = faker.helpers.arrayElement(allCategories.items)._id;
97
+
98
+ product.active = faker.datatype.boolean();
99
+
100
+ product.seo.slug = faker.lorem.slug();
101
+ product.seo.title = faker.commerce.productName();
102
+ product.seo.description = faker.commerce.productDescription();
103
+
104
+ product.dimension.depth = faker.datatype.number(100);
105
+ product.dimension.height = faker.datatype.number(100);
106
+ product.dimension.weight = faker.datatype.number(10);
107
+ product.dimension.width = faker.datatype.number(100);
108
+
109
+ product.code.sku = faker.lorem.slug();
110
+ product.code.gtin = faker.lorem.slug();
111
+ product.code.mpn = faker.lorem.slug();
112
+
113
+ product.hashtags = faker.lorem.words().split(' ');
114
+
115
+ const { _id: file1 } = await this.createAsset();
116
+ const { _id: file2 } = await this.createAsset();
117
+ const { _id: file3 } = await this.createAsset();
118
+ const { _id: file4 } = await this.createAsset();
119
+ const { _id: file5 } = await this.createAsset();
120
+
121
+ product.files.push(file1, file2, file3, file4, file5);
122
+
123
+ return this.productRepository.create(product);
124
+ };
125
+
126
+ return GenerateCommand.generate(quantity, callback)
127
+ .then(({ length }) => spinner.succeed(`Created ${length} of ${quantity} products`));
128
+ }
129
+
130
+ @Command({ command: 'clients <quantity>', description: 'Generate and persist fake clients' })
131
+ public async generateClients(quantity = 50) {
132
+ const spinner = createSpinner();
133
+ spinner.start(`Creating ${quantity} new clients`);
134
+
135
+ const callback = () => {
136
+ const client = new CreateClientValidator();
137
+
138
+ client.name = faker.company.name();
139
+ client.email = faker.internet.exampleEmail();
140
+ client.phone = faker.phone.number();
141
+ client.identificationNumber = faker.phone.imei();
142
+
143
+ return this.clientRepository.create(client);
144
+ };
145
+
146
+ return GenerateCommand.generate(quantity, callback)
147
+ .then(({ length }) => spinner.succeed(`Created ${length} of ${quantity} clients`));
148
+ }
149
+
150
+ @Command({ command: 'orders <quantity>', description: 'Generate and persist fake orders' })
151
+ public async generateOrders(quantity = 10) {
152
+ const spinner = createSpinner();
153
+ spinner.start(`Creating ${quantity} new orders`);
154
+
155
+ const allProducts = await this.productRepository.$model.find();
156
+ const allClients = await this.clientRepository.$model.find();
157
+
158
+ const callback = async () => {
159
+ const order = new CreateOrderValidator();
160
+
161
+ const generateAddress = (): MetaAddress => ({
162
+ street: faker.address.streetAddress(false),
163
+ number: faker.address.buildingNumber(),
164
+ complement: faker.address.secondaryAddress(),
165
+ city: faker.address.city(),
166
+ state: faker.address.stateAbbr(),
167
+ country: faker.address.countryCode('alpha-2'),
168
+ code: faker.address.zipCode(),
169
+ });
170
+
171
+ const generateCustomer = (): CustomerValidator => ({
172
+ email: faker.internet.email(),
173
+ name: faker.internet.userName(),
174
+ phone: faker.phone.number(),
175
+ });
176
+
177
+ order.billing = {
178
+ address: generateAddress(),
179
+ customer: generateCustomer(),
180
+ method: faker.helpers.arrayElement(Object.values(BillingMethod))
181
+ };
182
+
183
+ order.shipping = {
184
+ address: generateAddress(),
185
+ customer: generateCustomer(),
186
+ method: faker.helpers.arrayElement(Object.values(ShippingMethod)),
187
+ price: Number(faker.commerce.price(1000, 10000, 2))
188
+ };
189
+
190
+ order.customer = generateCustomer();
191
+
192
+ const items = Number(faker.random.numeric(1).toString());
193
+
194
+ order.items = [...Array(items)].map(() => ({
195
+ quantity: Number(faker.random.numeric(2)),
196
+ product: faker.helpers.arrayElement(allProducts)._id,
197
+ }));
198
+
199
+ order.client = faker.helpers.arrayElement(allClients)._id;
200
+
201
+ const createdOrder = await this.orderRepository.create(order);
202
+ await createdOrder.updateOne({
203
+ $set: {
204
+ createdAt: faker.date.recent(200)
205
+ }
206
+ })
207
+
208
+ const generateStatus = (status: StatusType, date: Date) => ({
209
+ name: status,
210
+ user: faker.internet.email(),
211
+ date: faker.date.recent(10, date),
212
+ });
213
+
214
+ faker.helpers.maybe(() => {
215
+ const status = generateStatus(StatusType.ACCEPTED, createdOrder.createdAt);
216
+ createdOrder.status.push(status);
217
+ return faker.helpers.maybe(() => {
218
+ const status1 = generateStatus(StatusType.IN_PREPARATION, status.date);
219
+ createdOrder.status.push();
220
+ return faker.helpers.maybe(() => {
221
+ const status2 = generateStatus(StatusType.SENDED, status1.date);
222
+ createdOrder.status.push(status2);
223
+ return faker.helpers.maybe(() => {
224
+ const status3 = generateStatus(StatusType.COMPLETED, status2.date);
225
+ createdOrder.status.push();
226
+ return faker.helpers.maybe(() => {
227
+ const status4 = generateStatus(StatusType.CANCELED, status3.date);
228
+ createdOrder.status.push(status4);
229
+ }, { probability: 0.1 });
230
+ }, { probability: 0.3 });
231
+ }, { probability: 0.5 });
232
+ }, { probability: 0.7 });
233
+ }, { probability: 0.9 });
234
+
235
+ return createdOrder.save();
236
+ };
237
+
238
+ for await(const iterator of Array(Number(quantity)).fill(null)) {
239
+ await callback()
240
+ .then(({ fullNumber }) => spinner.text = (`Created order [${fullNumber}]`))
241
+ }
242
+
243
+ return spinner.succeed(`Created ${quantity} orders`)
244
+ }
245
+
246
+ @Command({ command: 'pages <quantity>', description: 'Generate and persist fake content pages' })
247
+ public async generateContentPages(quantity = 10) {
248
+ const spinner = createSpinner();
249
+ spinner.start(`Creating ${quantity} new pages`);
250
+ const fixture = new PageFixture();
251
+
252
+ const callback = async () => {
253
+ const page = fixture.normal();
254
+
255
+ const createPage = await this.pageRepository.create(page);
256
+
257
+ return createPage.save();
258
+ };
259
+
260
+ return GenerateCommand.generate(quantity, callback)
261
+ .then(({ length }) => spinner.succeed(`Created ${length} of ${quantity} pages`));
262
+ }
263
+
264
+ @Command({ command: 'all', description: 'Execute all seeders' })
265
+ public async generateAll() {
266
+ await this.generateBrands(10);
267
+ await this.generateCategories(20);
268
+ await this.generateProducts(100);
269
+
270
+ await this.generateClients(10);
271
+ await this.generateOrders(100);
272
+ }
273
+
274
+ protected async createAsset() {
275
+ const asset: Partial<AssetEntity> = {};
276
+
277
+ asset.name = faker.lorem.words(3);
278
+ asset.description = faker.lorem.sentence();
279
+ asset.url = faker.image.food(635, 475, true);
280
+ asset.weak = false;
281
+ asset.type = faker.system.mimeType();
282
+ asset.size = Number(faker.random.numeric(5));
283
+
284
+ return this.assetRepository.create(asset);
285
+ }
286
+ }
@@ -0,0 +1,5 @@
1
+ import { CustomDecorator, SetMetadata } from '@nestjs/common';
2
+
3
+ export const IS_PUBLIC_KEY = 'isPublic';
4
+
5
+ export const Public: () => CustomDecorator = () => SetMetadata(IS_PUBLIC_KEY, true);
@@ -0,0 +1,21 @@
1
+ import { createParamDecorator, ExecutionContext } from '@nestjs/common';
2
+ import { Request } from 'express';
3
+
4
+ export interface DecodedUser {
5
+ iss: string,
6
+ sub: string,
7
+ aud: string[],
8
+ iat: number,
9
+ exp: number,
10
+ azp: string,
11
+ scope: string,
12
+ org_id?: string
13
+ }
14
+
15
+ export const GetUser = createParamDecorator((key: keyof DecodedUser, ctx: ExecutionContext) => {
16
+ const { user } = ctx.switchToHttp().getRequest<Request>();
17
+
18
+ return key
19
+ ? user[key]
20
+ : user;
21
+ });
@@ -0,0 +1,11 @@
1
+ import { PreconditionFailedException } from '@nestjs/common';
2
+
3
+ export class MissingIdentityException extends PreconditionFailedException {
4
+ public constructor() {
5
+ super('Missing identity parameter on your request');
6
+ }
7
+
8
+ public static throw() {
9
+ throw new MissingIdentityException;
10
+ }
11
+ }
@@ -0,0 +1,13 @@
1
+ import { Logger, NotFoundException } from '@nestjs/common';
2
+
3
+ export class StoreNotImplementedException extends NotFoundException {
4
+ public constructor(identity: string) {
5
+ super(`No store found by that id or name: [${identity}]`);
6
+ }
7
+
8
+ public static throw(identity: string) {
9
+
10
+ Logger.warn('Store not found or implemented', identity)
11
+ throw new StoreNotImplementedException(identity);
12
+ }
13
+ }
@@ -0,0 +1,11 @@
1
+ import { NotAcceptableException } from '@nestjs/common/exceptions/not-acceptable.exception';
2
+
3
+ export class StoreNotRecognizedException extends NotAcceptableException {
4
+ public constructor() {
5
+ super(`The store could not be accepted`);
6
+ }
7
+
8
+ public static throw() {
9
+ throw new StoreNotRecognizedException();
10
+ }
11
+ }
@@ -0,0 +1,43 @@
1
+ import { ExecutionContext, Inject, Injectable, UnauthorizedException } from '@nestjs/common';
2
+ import { Reflector } from '@nestjs/core';
3
+ import { AuthGuard as JwtGuard } from '@nestjs/passport';
4
+ import { IS_PUBLIC_KEY } from '../decorators/public.decorator';
5
+ import { DecodedUser } from '../decorators/user.decorator';
6
+
7
+ declare module 'express' {
8
+ interface Request {
9
+ user?: DecodedUser;
10
+ }
11
+ }
12
+
13
+ @Injectable()
14
+ export class AuthGuard extends JwtGuard('jwt') {
15
+
16
+ @Inject() private reflector: Reflector;
17
+
18
+ public async canActivate(context: ExecutionContext): Promise<any> {
19
+ const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
20
+ context.getHandler(),
21
+ context.getClass(),
22
+ ]);
23
+
24
+ if (isPublic) {
25
+ return true;
26
+ }
27
+
28
+ return super.canActivate(context);
29
+ }
30
+
31
+ public handleRequest(err: Record<string, unknown>, user: DecodedUser): any {
32
+ if (err) {
33
+ throw err;
34
+ }
35
+
36
+ if (!user) {
37
+ throw new UnauthorizedException();
38
+ }
39
+
40
+ return user;
41
+ }
42
+
43
+ }
@@ -0,0 +1,39 @@
1
+ import { CanActivate, ExecutionContext, Inject, Injectable } from '@nestjs/common';
2
+ import { Request } from 'express';
3
+ import { AppController } from '../app.controller';
4
+ import { IS_PUBLIC_KEY } from "../decorators/public.decorator";
5
+ import { Reflector } from "@nestjs/core";
6
+
7
+ @Injectable()
8
+ export class OrganizationGuard implements CanActivate {
9
+ @Inject() private reflector: Reflector;
10
+
11
+ public async canActivate(context: ExecutionContext) {
12
+
13
+ const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
14
+ context.getHandler(),
15
+ context.getClass(),
16
+ ]);
17
+
18
+ if (isPublic) {
19
+ return true;
20
+ }
21
+
22
+ if (context.getType() === 'http') {
23
+ const allowedHandlers: any[] = [AppController.prototype.userOrganizations];
24
+
25
+ if (allowedHandlers.includes(context.getHandler())) {
26
+ return true;
27
+ }
28
+
29
+ const request = context.switchToHttp().getRequest<Request>();
30
+
31
+ const { organization } = request.session;
32
+
33
+ return !!organization?.id;
34
+ }
35
+
36
+ return false;
37
+ }
38
+
39
+ }
@@ -0,0 +1,16 @@
1
+ import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
2
+ import { InjectConnection } from '@nestjs/mongoose';
3
+ import { Connection } from 'mongoose';
4
+ import { Observable } from 'rxjs';
5
+ import { finalize } from 'rxjs/operators';
6
+
7
+ @Injectable()
8
+ export class MongoInterceptor implements NestInterceptor {
9
+ @InjectConnection()
10
+ protected readonly $connection: Connection;
11
+
12
+ public intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
13
+ return next.handle()
14
+ .pipe(finalize(() => this.$connection.close()));
15
+ }
16
+ }
package/src/main.ts ADDED
@@ -0,0 +1,37 @@
1
+ import { Logger, ValidationPipe } from '@nestjs/common';
2
+ import { NestApplication, NestFactory } from '@nestjs/core';
3
+ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
4
+ import session from 'express-session';
5
+ import { AppConfig } from './app.config';
6
+ import { AppModule } from './app.module';
7
+ import { AuthGuard } from './guards/auth.guard';
8
+ import { OrganizationGuard } from './guards/organization.guard';
9
+
10
+ (async () => {
11
+ const app = await NestFactory.create(AppModule, {
12
+ cors: true,
13
+ });
14
+
15
+ app.use(session({
16
+ secret: 'thisIsNotASecretAnyMore',
17
+ resave: false,
18
+ saveUninitialized: false,
19
+ }));
20
+
21
+ const builder = new DocumentBuilder()
22
+ .setTitle(AppConfig.server.name)
23
+ .setDescription(AppConfig.server.description)
24
+ .setVersion(AppConfig.server.version)
25
+ .addBearerAuth()
26
+ .build();
27
+
28
+ //Creating Swagger Doc for API
29
+ const document = SwaggerModule.createDocument(app, builder);
30
+ SwaggerModule.setup('/', app, document);
31
+
32
+ return app
33
+ .useGlobalGuards(app.get(AuthGuard), app.get(OrganizationGuard))
34
+ .useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }))
35
+ .listen(AppConfig.server.port)
36
+ .then(async () => Logger.verbose(`Running on: ${await app.getUrl()}`, NestApplication.name));
37
+ })();