@mshima/generator-jhipster-nodejs 0.0.0-stage → 0.0.1

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 (209) hide show
  1. package/LICENSE.txt +204 -0
  2. package/README.md +243 -2
  3. package/build-info.json +3 -0
  4. package/cli/cli-customizations.cjs +9 -0
  5. package/cli/cli.cjs +40 -0
  6. package/cli/logo.js +31 -0
  7. package/cli/version.cjs +12 -0
  8. package/generators/ci-cd/USAGE +5 -0
  9. package/generators/ci-cd/command.js +5 -0
  10. package/generators/ci-cd/generator.js +158 -0
  11. package/generators/ci-cd/index.js +2 -0
  12. package/generators/ci-cd/templates/.gitlab-ci.yml.ejs +137 -0
  13. package/generators/ci-cd/templates/azure-pipelines.yml.ejs +68 -0
  14. package/generators/ci-cd/templates/circle.yml.ejs +59 -0
  15. package/generators/ci-cd/templates/docker-registry.yml.ejs +58 -0
  16. package/generators/ci-cd/templates/github-ci.yml.ejs +90 -0
  17. package/generators/ci-cd/templates/jenkins/Jenkinsfile.ejs +104 -0
  18. package/generators/ci-cd/templates/jenkins/idea.gdsl +90 -0
  19. package/generators/ci-cd/templates/jenkins/jenkins.yml.ejs +33 -0
  20. package/generators/ci-cd/templates/travis.yml.ejs +75 -0
  21. package/generators/client/command.js +5 -0
  22. package/generators/client/generator.js +21 -0
  23. package/generators/client/generators/bootstrap/command.js +5 -0
  24. package/generators/client/generators/bootstrap/generator.js +28 -0
  25. package/generators/client/generators/bootstrap/index.js +2 -0
  26. package/generators/client/index.js +2 -0
  27. package/generators/common/generators/bootstrap/command.js +5 -0
  28. package/generators/common/generators/bootstrap/generator.js +37 -0
  29. package/generators/common/generators/bootstrap/index.js +2 -0
  30. package/generators/docker/command.js +5 -0
  31. package/generators/docker/generator.js +16 -0
  32. package/generators/docker/generators/bootstrap/command.js +5 -0
  33. package/generators/docker/generators/bootstrap/generator.js +56 -0
  34. package/generators/docker/generators/bootstrap/index.js +2 -0
  35. package/generators/docker/index.js +2 -0
  36. package/generators/docker/templates/docker/app.yml.ejs +25 -0
  37. package/generators/generator-nodejs-constants.js +32 -0
  38. package/generators/languages/command.js +5 -0
  39. package/generators/languages/generator.js +22 -0
  40. package/generators/languages/index.js +2 -0
  41. package/generators/languages/templates/src/main/webapp/i18n/en/home.json +19 -0
  42. package/generators/languages/templates/src/main/webapp/i18n/es/home.json +19 -0
  43. package/generators/languages/templates/src/main/webapp/i18n/it/home.json +19 -0
  44. package/generators/node-server/command.js +96 -0
  45. package/generators/node-server/entity-files.js +41 -0
  46. package/generators/node-server/files.js +254 -0
  47. package/generators/node-server/generator.js +702 -0
  48. package/generators/node-server/generators/bootstrap/command.js +5 -0
  49. package/generators/node-server/generators/bootstrap/generator.js +83 -0
  50. package/generators/node-server/generators/bootstrap/index.js +2 -0
  51. package/generators/node-server/index.js +2 -0
  52. package/generators/node-server/resources/package.json +76 -0
  53. package/generators/node-server/support/api-fake-data.js +54 -0
  54. package/generators/node-server/support/columns.js +73 -0
  55. package/generators/node-server/support/database.js +24 -0
  56. package/generators/node-server/support/entity-authorities.js +32 -0
  57. package/generators/node-server/support/entity-paths.js +13 -0
  58. package/generators/node-server/support/enums.js +11 -0
  59. package/generators/node-server/support/index.js +9 -0
  60. package/generators/node-server/support/mail-templates.js +82 -0
  61. package/generators/node-server/support/migrations.js +197 -0
  62. package/generators/node-server/support/validators.js +25 -0
  63. package/generators/node-server/templates/.dockerignore.ejs +16 -0
  64. package/generators/node-server/templates/.gitignore.jhi.nodejs.ejs +24 -0
  65. package/generators/node-server/templates/Dockerfile.ejs +54 -0
  66. package/generators/node-server/templates/README.md.jhi.nodejs.ejs +220 -0
  67. package/generators/node-server/templates/package.json.ejs +84 -0
  68. package/generators/node-server/templates/server/README.md.ejs +269 -0
  69. package/generators/node-server/templates/server/e2e/_entityFileName_.database.e2e-spec.ts.ejs +192 -0
  70. package/generators/node-server/templates/server/e2e/_entityFileName_.e2e-spec.ts.ejs +402 -0
  71. package/generators/node-server/templates/server/e2e/account.e2e-spec.ts.ejs +349 -0
  72. package/generators/node-server/templates/server/e2e/app.e2e-spec.ts.ejs +188 -0
  73. package/generators/node-server/templates/server/e2e/authority.e2e-spec.ts.ejs +50 -0
  74. package/generators/node-server/templates/server/e2e/cors.e2e-spec.ts.ejs +110 -0
  75. package/generators/node-server/templates/server/e2e/management.e2e-spec.ts.ejs +180 -0
  76. package/generators/node-server/templates/server/e2e/oauth2-bearer.e2e-spec.ts.ejs +71 -0
  77. package/generators/node-server/templates/server/e2e/session.e2e-spec.ts.ejs +219 -0
  78. package/generators/node-server/templates/server/e2e/setup.test.js.ejs +1 -0
  79. package/generators/node-server/templates/server/e2e/user.e2e-spec.ts.ejs +318 -0
  80. package/generators/node-server/templates/server/env.ejs +1 -0
  81. package/generators/node-server/templates/server/eslint.config.mjs.ejs +48 -0
  82. package/generators/node-server/templates/server/nest-cli.json.ejs +11 -0
  83. package/generators/node-server/templates/server/ormconfig.ts.ejs +35 -0
  84. package/generators/node-server/templates/server/package.json.ejs +143 -0
  85. package/generators/node-server/templates/server/sonar-project.properties.ejs +10 -0
  86. package/generators/node-server/templates/server/src/app.config.spec.ts.ejs +13 -0
  87. package/generators/node-server/templates/server/src/app.config.ts.ejs +179 -0
  88. package/generators/node-server/templates/server/src/app.module.ts.ejs +80 -0
  89. package/generators/node-server/templates/server/src/application-config.ts.ejs +153 -0
  90. package/generators/node-server/templates/server/src/auth/account.controller.ts.ejs +183 -0
  91. package/generators/node-server/templates/server/src/auth/auth.module.ts.ejs +104 -0
  92. package/generators/node-server/templates/server/src/auth/auth.service.ts.ejs +294 -0
  93. package/generators/node-server/templates/server/src/auth/csrf.middleware.spec.ts.ejs +65 -0
  94. package/generators/node-server/templates/server/src/auth/csrf.middleware.ts.ejs +76 -0
  95. package/generators/node-server/templates/server/src/auth/decorators/auth-user.decorator.ts.ejs +8 -0
  96. package/generators/node-server/templates/server/src/auth/decorators/roles.decorator.ts.ejs +4 -0
  97. package/generators/node-server/templates/server/src/auth/dto/key-and-password.dto.ts.ejs +17 -0
  98. package/generators/node-server/templates/server/src/auth/dto/password-change.dto.ts.ejs +17 -0
  99. package/generators/node-server/templates/server/src/auth/dto/user-login.dto.ts.ejs +21 -0
  100. package/generators/node-server/templates/server/src/auth/guards/auth.guard.ts.ejs +50 -0
  101. package/generators/node-server/templates/server/src/auth/guards/oauth2-login.guard.ts.ejs +6 -0
  102. package/generators/node-server/templates/server/src/auth/guards/roles.guard.ts.ejs +25 -0
  103. package/generators/node-server/templates/server/src/auth/index.ts.ejs +8 -0
  104. package/generators/node-server/templates/server/src/auth/jwt.config.spec.ts.ejs +22 -0
  105. package/generators/node-server/templates/server/src/auth/jwt.config.ts.ejs +29 -0
  106. package/generators/node-server/templates/server/src/auth/oauth2.authorities.spec.ts.ejs +24 -0
  107. package/generators/node-server/templates/server/src/auth/oauth2.authorities.ts.ejs +33 -0
  108. package/generators/node-server/templates/server/src/auth/oauth2.config.ts.ejs +51 -0
  109. package/generators/node-server/templates/server/src/auth/passport.jwt.strategy.ts.ejs +45 -0
  110. package/generators/node-server/templates/server/src/auth/passport.oauth2-bearer.strategy.ts.ejs +32 -0
  111. package/generators/node-server/templates/server/src/auth/passport.oauth2.strategy.spec.ts.ejs +27 -0
  112. package/generators/node-server/templates/server/src/auth/passport.oauth2.strategy.ts.ejs +44 -0
  113. package/generators/node-server/templates/server/src/auth/password-util.ts.ejs +10 -0
  114. package/generators/node-server/templates/server/src/auth/password.service.ts.ejs +34 -0
  115. package/generators/node-server/templates/server/src/auth/payload.interface.ts.ejs +14 -0
  116. package/generators/node-server/templates/server/src/auth/role-type.ts.ejs +7 -0
  117. package/generators/node-server/templates/server/src/auth/session-user.middleware.ts.ejs +33 -0
  118. package/generators/node-server/templates/server/src/auth/session.entity.ts.ejs +36 -0
  119. package/generators/node-server/templates/server/src/auth/session.store.spec.ts.ejs +99 -0
  120. package/generators/node-server/templates/server/src/auth/session.store.ts.ejs +116 -0
  121. package/generators/node-server/templates/server/src/auth/user.jwt.controller.ts.ejs +26 -0
  122. package/generators/node-server/templates/server/src/auth/user.oauth2.controller.ts.ejs +78 -0
  123. package/generators/node-server/templates/server/src/auth/user.session.controller.ts.ejs +103 -0
  124. package/generators/node-server/templates/server/src/common/common.module.ts.ejs +19 -0
  125. package/generators/node-server/templates/server/src/common/database/base.entity.ts.ejs +13 -0
  126. package/generators/node-server/templates/server/src/common/database/column-transformers.spec.ts.ejs +46 -0
  127. package/generators/node-server/templates/server/src/common/database/column-transformers.ts.ejs +69 -0
  128. package/generators/node-server/templates/server/src/common/database/column-types.spec.ts.ejs +21 -0
  129. package/generators/node-server/templates/server/src/common/database/column-types.ts.ejs +29 -0
  130. package/generators/node-server/templates/server/src/common/database/pagination.entity.spec.ts.ejs +66 -0
  131. package/generators/node-server/templates/server/src/common/database/pagination.entity.ts.ejs +108 -0
  132. package/generators/node-server/templates/server/src/common/dto/base.dto.ts.ejs +19 -0
  133. package/generators/node-server/templates/server/src/common/errors/error-constants.ts.ejs +10 -0
  134. package/generators/node-server/templates/server/src/common/errors/problem-details.filter.ts.ejs +63 -0
  135. package/generators/node-server/templates/server/src/common/errors/problem.exception.ts.ejs +92 -0
  136. package/generators/node-server/templates/server/src/common/field_validators.ejs +77 -0
  137. package/generators/node-server/templates/server/src/common/header-util.ts.ejs +105 -0
  138. package/generators/node-server/templates/server/src/common/interceptors/logging.interceptor.spec.ts.ejs +93 -0
  139. package/generators/node-server/templates/server/src/common/interceptors/logging.interceptor.ts.ejs +48 -0
  140. package/generators/node-server/templates/server/src/common/logging.spec.ts.ejs +83 -0
  141. package/generators/node-server/templates/server/src/common/logging.ts.ejs +129 -0
  142. package/generators/node-server/templates/server/src/common/metrics.spec.ts.ejs +43 -0
  143. package/generators/node-server/templates/server/src/common/metrics.ts.ejs +198 -0
  144. package/generators/node-server/templates/server/src/common/request.ts.ejs +8 -0
  145. package/generators/node-server/templates/server/src/common/sortable-properties.ts.ejs +43 -0
  146. package/generators/node-server/templates/server/src/common/updatable-properties.ts.ejs +14 -0
  147. package/generators/node-server/templates/server/src/config/application-dev.yml.ejs +118 -0
  148. package/generators/node-server/templates/server/src/config/application-prod.yml.ejs +97 -0
  149. package/generators/node-server/templates/server/src/config/application-secret-samples.yml.ejs +42 -0
  150. package/generators/node-server/templates/server/src/config/application-test.yml.ejs +68 -0
  151. package/generators/node-server/templates/server/src/config/application-tls-samples.yml.ejs +15 -0
  152. package/generators/node-server/templates/server/src/config/application-tls.yml.ejs +15 -0
  153. package/generators/node-server/templates/server/src/config/application.yml.ejs +149 -0
  154. package/generators/node-server/templates/server/src/config.spec.ts.ejs +81 -0
  155. package/generators/node-server/templates/server/src/config.ts.ejs +255 -0
  156. package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.controller.ts.ejs +178 -0
  157. package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.entity.ts.ejs +110 -0
  158. package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.mapper.ts.ejs +37 -0
  159. package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.module.ts.ejs +14 -0
  160. package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.service.ts.ejs +123 -0
  161. package/generators/node-server/templates/server/src/entities/_entityFileName_/dto/_entityFileName_.dto.ts.ejs +99 -0
  162. package/generators/node-server/templates/server/src/mail/mail.module.ts.ejs +49 -0
  163. package/generators/node-server/templates/server/src/mail/mail.service.spec.ts.ejs +105 -0
  164. package/generators/node-server/templates/server/src/mail/mail.service.ts.ejs +120 -0
  165. package/generators/node-server/templates/server/src/main.ts.ejs +114 -0
  166. package/generators/node-server/templates/server/src/management/api-docs.controller.ts.ejs +27 -0
  167. package/generators/node-server/templates/server/src/management/api-docs.service.ts.ejs +8 -0
  168. package/generators/node-server/templates/server/src/management/configuration.controller.ts.ejs +80 -0
  169. package/generators/node-server/templates/server/src/management/health.controller.spec.ts.ejs +79 -0
  170. package/generators/node-server/templates/server/src/management/health.controller.ts.ejs +87 -0
  171. package/generators/node-server/templates/server/src/management/health.module.ts.ejs +9 -0
  172. package/generators/node-server/templates/server/src/management/loggers.controller.ts.ejs +40 -0
  173. package/generators/node-server/templates/server/src/management/management.controller.spec.ts.ejs +26 -0
  174. package/generators/node-server/templates/server/src/management/management.controller.ts.ejs +34 -0
  175. package/generators/node-server/templates/server/src/management/management.module.ts.ejs +21 -0
  176. package/generators/node-server/templates/server/src/management/metrics.controller.ts.ejs +85 -0
  177. package/generators/node-server/templates/server/src/migrations/1570200270081-CreateTables.ts.ejs +64 -0
  178. package/generators/node-server/templates/server/src/migrations/1570200270082-CreateSessions.ts.ejs +26 -0
  179. package/generators/node-server/templates/server/src/migrations/1570200490072-SeedUsersRoles.ts.ejs +74 -0
  180. package/generators/node-server/templates/server/src/migrations/_entityConstraintsMigration_.ts.ejs +40 -0
  181. package/generators/node-server/templates/server/src/migrations/_entityMigration_.ts.ejs +26 -0
  182. package/generators/node-server/templates/server/src/migrations/support/schema.ts.ejs +202 -0
  183. package/generators/node-server/templates/server/src/orm.config.ts.ejs +147 -0
  184. package/generators/node-server/templates/server/src/registry/consul.service.ts.ejs +70 -0
  185. package/generators/node-server/templates/server/src/registry/eureka.service.ts.ejs +129 -0
  186. package/generators/node-server/templates/server/src/swagger.ts.ejs +24 -0
  187. package/generators/node-server/templates/server/src/tls.ts.ejs +27 -0
  188. package/generators/node-server/templates/server/src/users/authority.controller.ts.ejs +85 -0
  189. package/generators/node-server/templates/server/src/users/authority.entity.ts.ejs +22 -0
  190. package/generators/node-server/templates/server/src/users/dto/authority.dto.ts.ejs +10 -0
  191. package/generators/node-server/templates/server/src/users/dto/user.dto.ts.ejs +116 -0
  192. package/generators/node-server/templates/server/src/users/public.user.controller.ts.ejs +51 -0
  193. package/generators/node-server/templates/server/src/users/user.controller.ts.ejs +191 -0
  194. package/generators/node-server/templates/server/src/users/user.entity.ts.ejs +63 -0
  195. package/generators/node-server/templates/server/src/users/user.mapper.ts.ejs +26 -0
  196. package/generators/node-server/templates/server/src/users/user.module.ts.ejs +19 -0
  197. package/generators/node-server/templates/server/src/users/user.service.ts.ejs +156 -0
  198. package/generators/node-server/templates/server/tsconfig.build.json.ejs +9 -0
  199. package/generators/node-server/templates/server/tsconfig.json.ejs +23 -0
  200. package/generators/node-server/templates/server/typeorm-migration.ts.ejs +18 -0
  201. package/generators/node-server/templates/server/vitest.config.e2e.ts.ejs +16 -0
  202. package/generators/node-server/templates/server/vitest.config.ts.ejs +16 -0
  203. package/generators/server/command.js +7 -0
  204. package/generators/server/generator.js +20 -0
  205. package/generators/server/generators/bootstrap/command.js +5 -0
  206. package/generators/server/generators/bootstrap/generator.js +15 -0
  207. package/generators/server/generators/bootstrap/index.js +2 -0
  208. package/generators/server/index.js +2 -0
  209. package/package.json +75 -4
@@ -0,0 +1,123 @@
1
+ import { Injectable, HttpException, HttpStatus, Logger } from '@nestjs/common';
2
+ import { InjectRepository } from '@nestjs/typeorm';
3
+ import { EntityMetadata, FindManyOptions, FindOneOptions, Repository } from 'typeorm';
4
+ import { <%= entityClass %> } from './<%= entityFileName %>.entity.ts';
5
+ import { <%= dtoClass %> } from './dto/<%= entityFileName %>.dto.ts';
6
+ import { <%= entityClass %>Mapper } from './<%= entityFileName %>.mapper.ts';
7
+ <%_ if (databaseType === 'mongodb') { _%>
8
+ import { updatableProperties } from '../../common/updatable-properties.ts';
9
+ <%_ if (databaseTypeMongodb) { _%>
10
+ import { ObjectId } from 'mongodb';
11
+ import { documentOrder } from '../../common/sortable-properties.ts';
12
+ <%_ } _%>
13
+ <%_ } _%>
14
+
15
+ <%_
16
+ // The relationships the entity stores (the persistableRelationships of JHipster), loaded with it.
17
+ const eagerLoadRelations = persistableRelationships.map(relationship => relationship.propertyName);
18
+ const pkType = primaryKey.tsType;
19
+ _%>
20
+ <%_ if (typeormRelationsSupport && eagerLoadRelations.length > 0) { _%>
21
+ const relations = {
22
+ <%_ for (const rel of eagerLoadRelations) { _%>
23
+ '<%= rel %>': true,
24
+ <%_ } _%>
25
+ } as const;
26
+
27
+ <%_ } _%>
28
+ @Injectable()
29
+ export class <%= entityClass %>Service {
30
+ logger = new Logger('<%= entityClass %>Service');
31
+
32
+ constructor(@InjectRepository(<%= entityClass %>) private <%= entityInstance %>Repository: Repository<<%= entityClass %>>) {}
33
+
34
+ /** The TypeORM metadata of the entity, the sort of its lists is validated with. */
35
+ get metadata(): EntityMetadata {
36
+ return this.<%= entityInstance %>Repository.metadata;
37
+ }
38
+
39
+ async findById(id: <%= pkType %>): Promise<<%= dtoClass %> | undefined> {
40
+ <%_ if (databaseTypeMongodb) { _%>
41
+ // An id that is not an ObjectId is the one of no document, like an unknown id of JHipster Spring Boot.
42
+ if (!ObjectId.isValid(id)) {
43
+ return undefined;
44
+ }
45
+ <%_ } _%>
46
+ const result = await this.<%= entityInstance %>Repository.findOne({
47
+ <%_ if (typeormRelationsSupport && eagerLoadRelations.length > 0) { _%>
48
+ relations,
49
+ <%_ } _%>
50
+ where: { id },
51
+ });
52
+ return <%= entityClass %>Mapper.fromEntityToDTO(result);
53
+ }
54
+
55
+ async findByFields(options: FindOneOptions<<%= dtoClass %>>): Promise<<%= dtoClass %> | undefined> {
56
+ const result = await this.<%= entityInstance %>Repository.findOne(options);
57
+ return <%= entityClass %>Mapper.fromEntityToDTO(result);
58
+ }
59
+
60
+ async findAndCount(options: FindManyOptions<<%= dtoClass %>>): Promise<[<%= dtoClass %>[], number]> {
61
+ const resultList = await this.<%= entityInstance %>Repository.findAndCount(
62
+ <%_ if (typeormRelationsSupport && eagerLoadRelations.length > 0) { _%>
63
+ { ...options, relations },
64
+ <%_ } else if (databaseTypeMongodb) { _%>
65
+ { ...options, order: documentOrder(this.metadata, options.order) },
66
+ <%_ } else { _%>
67
+ options,
68
+ <%_ } _%>
69
+ );
70
+ const <%= entityInstance %>DTO: <%= dtoClass %>[] = [];
71
+ if (resultList && resultList[0]) {
72
+ resultList[0].forEach(<%= entityInstance %> => <%= entityInstance %>DTO.push(<%= entityClass %>Mapper.fromEntityToDTO(<%= entityInstance %>)));
73
+ resultList[0] = <%= entityInstance %>DTO;
74
+ }
75
+ return resultList;
76
+ }
77
+
78
+ <%_ for (const relationship of nodejsMappedByRelationships.filter(relationship => relationship.relationshipOneToOne)) { _%>
79
+ /** The records without <%= relationship.relationshipName %>, like the findAllWhere<%- relationship.relationshipNameCapitalized %>IsNull of JHipster Spring Boot. */
80
+ async findAllWhere<%- relationship.relationshipNameCapitalized %>IsNull(): Promise<<%= dtoClass %>[]> {
81
+ const results = await this.<%= entityInstance %>Repository.find({ relations: { <%= relationship.propertyName %>: true } });
82
+ return results.filter(<%= entityInstance %> => !<%= entityInstance %>.<%= relationship.propertyName %>).map(<%= entityInstance %> => <%= entityClass %>Mapper.fromEntityToDTO(<%= entityInstance %>));
83
+ }
84
+
85
+ <%_ } _%>
86
+ async save(<%= entityInstance %>DTO: <%= dtoClass %>, creator?: string): Promise<<%= dtoClass %>> {
87
+ const entity = <%= entityClass %>Mapper.fromDTOtoEntity(<%= entityInstance %>DTO);
88
+ if (creator) {
89
+ entity.createdBy = creator;
90
+ entity.lastModifiedBy = creator;
91
+ }
92
+ const result = await this.<%= entityInstance %>Repository.save(entity);
93
+ return <%= entityClass %>Mapper.fromEntityToDTO(result);
94
+ }
95
+
96
+ async update(<%= entityInstance %>DTO: <%= dtoClass %>, updater?: string): Promise<<%= dtoClass %>> {
97
+ const entity = <%= entityClass %>Mapper.fromDTOtoEntity(<%= entityInstance %>DTO);
98
+ if (updater) {
99
+ entity.lastModifiedBy = updater;
100
+ }
101
+ <%_ if (databaseType === 'mongodb') { _%>
102
+ await this.<%= entityInstance %>Repository.update(entity.id!, updatableProperties(this.<%= entityInstance %>Repository.metadata, entity));
103
+ <%_ } else { _%>
104
+ await this.<%= entityInstance %>Repository.save(entity);
105
+ <%_ } _%>
106
+ // The stored entity, with its relationships and audit fields, rather than the request.
107
+ const result = await this.findById(entity.id!);
108
+ if (!result) {
109
+ throw new HttpException('Entity not found', HttpStatus.NOT_FOUND);
110
+ }
111
+ return result;
112
+ }
113
+
114
+ async deleteById(id: <%= pkType %>): Promise<void> {
115
+ <%_ if (databaseTypeMongodb) { _%>
116
+ if (!ObjectId.isValid(id)) {
117
+ return;
118
+ }
119
+ <%_ } _%>
120
+ await this.<%= entityInstance %>Repository.delete(id);
121
+ }
122
+
123
+ }
@@ -0,0 +1,99 @@
1
+ import { ApiProperty } from '@nestjs/swagger';
2
+ import { Allow<% if (anyPropertyHasValidation || fields.some(field => field.fieldIsEnum || field.nodejsTypeValidators.length > 0)) { %>, IsNotEmpty, IsOptional, IsEnum, MinLength, MaxLength, Length, Min, Max, Matches, IsInt, IsNumber, IsBoolean, IsUUID, IsISO8601<% } %> } from 'class-validator';
3
+ <%_ if (databaseTypeMongodb) { _%>
4
+ import { Transform } from 'class-transformer';
5
+ <%_ } _%>
6
+ import { BaseDTO<% if (relationships.length > 0) { %>, type RelatedDTO<% } %> } from '../../../common/dto/base.dto.ts';
7
+
8
+ <%_
9
+ let isUserRelationship = false;
10
+ const uniqueEntities = {};
11
+ const uniqueEnums = {};
12
+ const fieldsWithoutId = [];
13
+
14
+ for (idx in fields) {
15
+ if (fields[idx].fieldIsEnum && (
16
+ !uniqueEnums[fields[idx].fieldType] || (uniqueEnums[fields[idx].fieldType] && fields[idx].fieldValues.length !== 0))) {
17
+ uniqueEnums[fields[idx].fieldType] = this._.kebabCase(fields[idx].fieldType);
18
+ }
19
+ if (fields[idx].fieldName !== 'id') {
20
+ fieldsWithoutId.push(fields[idx]);
21
+ }
22
+ }
23
+ for (idx in relationships) {
24
+ const relationship = relationships[idx];
25
+ const otherDto = relationship.otherEntity.dtoClass;
26
+ if (relationship.otherEntity.entityClass === 'User'){
27
+ isUserRelationship = true;
28
+ }
29
+ else if (!uniqueEntities[otherDto] && otherDto != dtoClass) {
30
+ uniqueEntities[otherDto] = relationship.otherEntity.nodejsDtoPath;
31
+ }
32
+ }
33
+ _%>
34
+
35
+ <%_ Object.keys(uniqueEntities).forEach(function(entityDto) { _%>
36
+ import { <%= entityDto %> } from '../../../<%= uniqueEntities[entityDto] %>';
37
+ <%_ }); _%>
38
+ <%_ Object.keys(uniqueEnums).forEach(function(enumClass) { _%>
39
+ import { <%= enumClass %> } from '../../enumeration/<%= uniqueEnums[enumClass] %>.ts';
40
+ <%_ }); _%>
41
+
42
+ <%_ if (isUserRelationship === true) { _%>
43
+ import { <%= user.dtoClass%> } from '../../../users/dto/user.dto.ts';
44
+ <%_ } _%>
45
+
46
+ /**
47
+ * A <%= dtoClass %> object.
48
+ */
49
+ export class <%= dtoClass %> extends BaseDTO {
50
+ <%_ if (databaseTypeMongodb) { _%>
51
+ @Transform(({ value }) => value?.toHexString ? value?.toHexString() : value, {toPlainOnly: true})
52
+ <%_ } _%>
53
+ @Allow()
54
+ <%= primaryKey.name %>?: <%= primaryKey.tsType %>;
55
+
56
+ <%_ for (idx in fieldsWithoutId) {
57
+ const field = fieldsWithoutId[idx];
58
+ if (typeof field.javadoc !== 'undefined') { _%>
59
+ <%- formatAsFieldJavadoc(field.javadoc) %>
60
+ <%_ }
61
+ const required = field.fieldValidationRequired;
62
+ const fieldValidate = field.fieldValidate;
63
+ const fieldType = field.fieldType;
64
+ const fieldTypeBlobContent = field.fieldTypeBlobContent;
65
+ const fieldName = field.fieldName;
66
+ const fieldNameUnderscored = field.fieldNameUnderscored;
67
+ const fieldNameAsDatabaseColumn = field.fieldNameAsDatabaseColumn;
68
+ if (fieldValidate === true || field.fieldIsEnum || field.nodejsTypeValidators.length > 0) {
69
+ _%>
70
+ <%- include('../../../common/field_validators', { field }); -%>
71
+ <%_ } else { _%>
72
+ @Allow()
73
+ <%_ } _%>
74
+ <%_ if (field.fieldIsEnum) { _%>
75
+ @ApiProperty({ enum: <%= fieldType %>, <%_ if (typeof field.javadoc != 'undefined') { _%> description: '<%- formatAsApiDescription(field.javadoc) %>' <%_ } else { _%> description: '<%= fieldName %> enum field' <%_ } if (!required) { _%>, required: false <%_ } _%>})
76
+ <%_ } else { _%>
77
+ @ApiProperty({ <%_ if (typeof field.javadoc != 'undefined') { _%> description: '<%- formatAsApiDescription(field.javadoc) %>' <%_ } else { _%> description: '<%= fieldName %> field' <%_ } if (!required) { _%>, required: false <%_ } _%>})
78
+ <%_ } _%>
79
+ <%= fieldName %><%- field.fieldValidationRequired ? '!' : '?' %>: <%= field.nodejsFieldType %>;
80
+
81
+ <%_ if ((fieldType === 'byte[]' || fieldType === 'ByteBuffer') && fieldTypeBlobContent !== 'text') { _%>
82
+
83
+ @Allow()
84
+ <%= fieldName %>ContentType<%- field.fieldValidationRequired ? '!' : '?' %>: string;
85
+ <%_ }
86
+ } _%>
87
+
88
+ <%_
89
+ for (const relationship of relationships) {
90
+ if (typeof relationship.javadoc != 'undefined') { _%>
91
+ <%- formatAsFieldJavadoc(relationship.javadoc) %>
92
+ <%_ } _%>
93
+ @Allow()
94
+ @ApiProperty({ type: () => <%= relationship.otherEntity.dtoClass %><%- relationship.collection ? ', isArray: true' : '' %>, <%_ if (typeof relationship.javadoc != 'undefined') { _%> description: '<%- formatAsApiDescription(relationship.javadoc) %>' <%_ } else { _%> description: '<%= relationship.propertyName %> relationship' <%_ } _%> })
95
+ <%= relationship.propertyName %><%- relationship.relationshipRequired ? '!' : '?' %>: RelatedDTO<<%= relationship.otherEntity.dtoClass %><%- relationship.collection ? '[]' : '' %>>;
96
+ <%_ } _%>
97
+
98
+ // jhipster-needle-entity-add-field - JHipster will add fields here, do not remove
99
+ }
@@ -0,0 +1,49 @@
1
+ import * as path from 'path';
2
+
3
+ import { Module } from '@nestjs/common';
4
+ import { ConfigService } from '@nestjs/config';
5
+ import { HelperOptions } from 'handlebars';
6
+ import { MailerModule, MailerOptions } from '@nestjs-modules/mailer';
7
+ import { HandlebarsAdapter } from '@nestjs-modules/mailer/adapters/handlebars.adapter';
8
+
9
+ import { MailService } from './mail.service.ts';
10
+
11
+ /** The templates of the account mails, like the templates/mail of JHipster Spring Boot. */
12
+ export const mailTemplatesFolder = path.join(import.meta.dirname, '../templates/mail');
13
+
14
+ /**
15
+ * The helpers of the templates: message, the message of a key in the language of the mail, its {0}, {1}... replaced by
16
+ * the parameters, like the #{key(...)} of Thymeleaf. The messages are the ones of the context of the mail.
17
+ */
18
+ export const mailTemplateHelpers = {
19
+ message(key: string, ...parameters: unknown[]): string {
20
+ const { data } = parameters.pop() as HelperOptions;
21
+ const messages = (data?.root?.messages ?? {}) as Record<string, string>;
22
+ const values = parameters.map(value => (typeof value === 'string' || typeof value === 'number' ? `${value}` : ''));
23
+ return (messages[key] ?? key).replace(/\{(\d+)\}/g, (_, index: string) => values[Number(index)] ?? '');
24
+ },
25
+ };
26
+
27
+ /**
28
+ * The SMTP server of the mail properties, like spring.mail, and the Handlebars templates of the mails: they only
29
+ * interpolate values, escaped, and call the helpers of the server, they run no code.
30
+ */
31
+ export function mailerOptions(configService: ConfigService): MailerOptions {
32
+ const username = configService.get<string>('mail.username');
33
+ return {
34
+ transport: {
35
+ host: configService.get<string>('mail.host'),
36
+ port: Number(configService.get('mail.port')),
37
+ auth: username ? { user: username, pass: configService.get<string>('mail.password') } : undefined,
38
+ },
39
+ defaults: { from: configService.get<string>('jhipster.mail.from') },
40
+ template: { dir: mailTemplatesFolder, adapter: new HandlebarsAdapter(mailTemplateHelpers), options: { strict: true } },
41
+ };
42
+ }
43
+
44
+ @Module({
45
+ imports: [MailerModule.forRootAsync({ inject: [ConfigService], useFactory: mailerOptions })],
46
+ providers: [MailService],
47
+ exports: [MailService],
48
+ })
49
+ export class MailModule {}
@@ -0,0 +1,105 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
+
3
+ import { MAILER_OPTIONS, MailerService } from '@nestjs-modules/mailer';
4
+ import { ConfigModule, ConfigService } from '@nestjs/config';
5
+ import { Test, TestingModule } from '@nestjs/testing';
6
+
7
+ import { MailModule, mailerOptions } from './mail.module.ts';
8
+ import { MailService, parseProperties } from './mail.service.ts';
9
+
10
+ describe('MailService', () => {
11
+ let moduleRef: TestingModule;
12
+ let mailService: MailService;
13
+ let sendMail: ReturnType<typeof vi.spyOn>;
14
+
15
+ const user = { login: 'mailuser', email: 'mailuser@localhost.it', password: '', langKey: 'en', activationKey: 'activationKey', resetKey: 'resetKey' };
16
+
17
+ /** The mail the JSON transport of nodemailer gives back instead of sending it. */
18
+ const sentMail = async (): Promise<{ from: { address: string }; subject: string; html: string }> =>
19
+ JSON.parse(((await sendMail.mock.results[0].value) as { message: string }).message);
20
+
21
+ beforeEach(async () => {
22
+ moduleRef = await Test.createTestingModule({
23
+ imports: [
24
+ ConfigModule.forRoot({
25
+ isGlobal: true,
26
+ ignoreEnvFile: true,
27
+ load: [() => ({ mail: { host: 'localhost', port: 25 }, jhipster: { mail: { from: '<%= baseName %>@localhost', 'base-url': 'http://127.0.0.1:<%= serverPort %>' } } })],
28
+ }),
29
+ MailModule,
30
+ ],
31
+ })
32
+ .overrideProvider(MAILER_OPTIONS)
33
+ .useFactory({ factory: (configService: ConfigService) => ({ ...mailerOptions(configService), transport: { jsonTransport: true } }), inject: [ConfigService] })
34
+ .compile();
35
+ mailService = moduleRef.get(MailService);
36
+ sendMail = vi.spyOn(moduleRef.get(MailerService), 'sendMail');
37
+ });
38
+
39
+ afterEach(async () => {
40
+ await moduleRef.close();
41
+ });
42
+
43
+ it('should send the activation mail with the activation link', async () => {
44
+ await mailService.sendActivationEmail(user);
45
+
46
+ const mail = await sentMail();
47
+ expect(mail.from.address).toBe('<%= baseName %>@localhost');
48
+ expect(mail.subject).toBe('<%- baseName %> account activation');
49
+ expect(mail.html).toContain('<a href="http://127.0.0.1:<%= serverPort %>/account/activate?key=activationKey">');
50
+ expect(mail.html).toContain('<p>Dear mailuser</p>');
51
+ });
52
+
53
+ it('should send the creation mail with the link to set the password', async () => {
54
+ await mailService.sendCreationEmail(user);
55
+
56
+ const mail = await sentMail();
57
+ expect(mail.subject).toBe('<%- baseName %> account activation');
58
+ expect(mail.html).toContain('<a href="http://127.0.0.1:<%= serverPort %>/account/reset/finish?key=resetKey">');
59
+ });
60
+
61
+ it('should send the password reset mail with the reset link', async () => {
62
+ await mailService.sendPasswordResetMail(user);
63
+
64
+ const mail = await sentMail();
65
+ expect(mail.subject).toBe('<%- baseName %> password reset');
66
+ expect(mail.html).toContain('<a href="http://127.0.0.1:<%= serverPort %>/account/reset/finish?key=resetKey">');
67
+ });
68
+
69
+ it('should escape the user values in the mail', async () => {
70
+ await mailService.sendActivationEmail({ ...user, login: '<b>mailuser</b>' });
71
+
72
+ expect((await sentMail()).html).toContain('<p>Dear &lt;b&gt;mailuser&lt;/b&gt;</p>');
73
+ });
74
+
75
+ it('should use the default messages for a language without its messages file', async () => {
76
+ await mailService.sendPasswordResetMail({ ...user, langKey: 'unknown' });
77
+
78
+ expect((await sentMail()).subject).toBe('<%- baseName %> password reset');
79
+ });
80
+
81
+ it('should use the default messages for a langKey that is not a language tag', async () => {
82
+ await mailService.sendPasswordResetMail({ ...user, langKey: '../config/application' });
83
+
84
+ expect((await sentMail()).subject).toBe('<%- baseName %> password reset');
85
+ });
86
+
87
+ it('should not send a mail to a user without email', async () => {
88
+ await mailService.sendActivationEmail({ ...user, email: '' });
89
+
90
+ expect(sendMail).not.toHaveBeenCalled();
91
+ });
92
+
93
+ it('should not fail when the mail could not be sent', async () => {
94
+ sendMail.mockRejectedValue(new Error('Connection refused'));
95
+
96
+ await expect(mailService.sendActivationEmail(user)).resolves.toBeUndefined();
97
+ });
98
+
99
+ it('should parse the messages of a properties file', () => {
100
+ expect(parseProperties('# comment\nemail.greeting=Caro {0}\nemail.title = \\u00c9quipe\n')).toEqual({
101
+ 'email.greeting': 'Caro {0}',
102
+ 'email.title': 'Équipe',
103
+ });
104
+ });
105
+ });
@@ -0,0 +1,120 @@
1
+ import { existsSync, readFileSync } from 'fs';
2
+ import * as path from 'path';
3
+
4
+ import { Injectable, Logger } from '@nestjs/common';
5
+ import { ConfigService } from '@nestjs/config';
6
+ import { MailerService } from '@nestjs-modules/mailer';
7
+
8
+ import { <%= user.dtoClass %> } from '../users/dto/user.dto.ts';
9
+
10
+ /** A language tag of JHipster, like pt-br: the langKey of a user, which the user can change, read as a file name. */
11
+ const LANGUAGE_TAG = /^[a-zA-Z0-9-]+$/;
12
+
13
+ const i18nFolder = path.join(import.meta.dirname, '../i18n');
14
+
15
+ /** The messages of a .properties file, like the ones of the MessageSource of Spring. */
16
+ export function parseProperties(content: string): Record<string, string> {
17
+ const messages: Record<string, string> = {};
18
+ for (const line of content.split(/\r?\n/)) {
19
+ const trimmed = line.trim();
20
+ if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith('!')) {
21
+ continue;
22
+ }
23
+ const separator = trimmed.search(/[=:]/);
24
+ if (separator > 0) {
25
+ messages[trimmed.substring(0, separator).trim()] = trimmed
26
+ .substring(separator + 1)
27
+ .trim()
28
+ .replace(/\\u([0-9a-fA-F]{4})/g, (_, code: string) => String.fromCharCode(parseInt(code, 16)))
29
+ .replace(/\\(.)/g, '$1');
30
+ }
31
+ }
32
+ return messages;
33
+ }
34
+
35
+ /**
36
+ * Sends the account mails, like the MailService of JHipster Spring Boot: the activation mail of a registered user, the
37
+ * creation mail of a user created by an administrator and the password reset mail, in the language of the user (its
38
+ * langKey), with the SMTP server of the mail properties. Like the @Async methods of Spring, a mail is sent without
39
+ * failing the request: a mail that could not be sent is logged.
40
+ */
41
+ @Injectable()
42
+ export class MailService {
43
+ logger = new Logger('MailService');
44
+
45
+ private readonly defaultMessages: Record<string, string>;
46
+
47
+ private readonly languageMessages = new Map<string, Record<string, string>>();
48
+
49
+ constructor(
50
+ private readonly mailerService: MailerService,
51
+ private readonly configService: ConfigService,
52
+ ) {
53
+ this.defaultMessages = parseProperties(readFileSync(path.join(i18nFolder, 'messages.properties'), 'utf8'));
54
+ }
55
+
56
+ async sendActivationEmail(user: <%= user.dtoClass %>): Promise<void> {
57
+ this.logger.debug(`Sending activation email to '${user.email}'`);
58
+ await this.sendEmailFromTemplate(user, 'activationEmail', 'email.activation.title');
59
+ }
60
+
61
+ async sendCreationEmail(user: <%= user.dtoClass %>): Promise<void> {
62
+ this.logger.debug(`Sending creation email to '${user.email}'`);
63
+ await this.sendEmailFromTemplate(user, 'creationEmail', 'email.activation.title');
64
+ }
65
+
66
+ async sendPasswordResetMail(user: <%= user.dtoClass %>): Promise<void> {
67
+ this.logger.debug(`Sending password reset email to '${user.email}'`);
68
+ await this.sendEmailFromTemplate(user, 'passwordResetEmail', 'email.reset.title');
69
+ }
70
+
71
+ /**
72
+ * The mail of a template of templates/mail, like the sendEmailFromTemplate of JHipster Spring Boot: rendered with the
73
+ * user, the base URL of the client and the messages of the language of the user (the message helper of the templates).
74
+ */
75
+ async sendEmailFromTemplate(user: <%= user.dtoClass %>, template: string, titleKey: string): Promise<void> {
76
+ if (!user.email) {
77
+ this.logger.debug(`Email doesn't exist for user '${user.login}'`);
78
+ return;
79
+ }
80
+ const messages = this.messages(user.langKey);
81
+ const message = (key: string, ...args: string[]): string =>
82
+ (messages[key] ?? this.defaultMessages[key] ?? key).replace(/\{(\d+)\}/g, (_, index: string) => args[Number(index)] ?? '');
83
+ const subject = message(titleKey);
84
+ this.logger.debug(`Send email to '${user.email}' with subject '${subject}'`);
85
+ try {
86
+ await this.mailerService.sendMail({
87
+ to: user.email,
88
+ subject,
89
+ template,
90
+ context: {
91
+ user,
92
+ baseUrl: this.configService.get<string>('jhipster.mail.base-url') ?? '',
93
+ langKey: user.langKey ?? 'en',
94
+ messages: { ...this.defaultMessages, ...messages },
95
+ },
96
+ });
97
+ this.logger.debug(`Sent email to User '${user.email}'`);
98
+ } catch (error) {
99
+ this.logger.warn(`Email could not be sent to user '${user.email}': ${(error as Error).message}`);
100
+ }
101
+ }
102
+
103
+ /**
104
+ * The messages of a language, from its file named by its language tag (messages_pt-br.properties, written by the
105
+ * server:i18n generator of JHipster), the default ones (messages.properties) for a language without its own file,
106
+ * like a language added after the generation of the application.
107
+ */
108
+ private messages(langKey?: string): Record<string, string> {
109
+ const fileName = langKey && LANGUAGE_TAG.test(langKey) ? `messages_${langKey}.properties` : undefined;
110
+ if (!fileName || !existsSync(path.join(i18nFolder, fileName))) {
111
+ return this.defaultMessages;
112
+ }
113
+ let messages = this.languageMessages.get(fileName);
114
+ if (!messages) {
115
+ messages = parseProperties(readFileSync(path.join(i18nFolder, fileName), 'utf8'));
116
+ this.languageMessages.set(fileName, messages);
117
+ }
118
+ return messages;
119
+ }
120
+ }
@@ -0,0 +1,114 @@
1
+ // The .env file, loaded before the configuration (an import runs before the code of this module).
2
+ import 'dotenv/config';
3
+ import { NestFactory } from '@nestjs/core';
4
+ <%_ if (serviceDiscoveryEureka) { _%>
5
+ import cloudConfigClient from 'cloud-config-client';
6
+ <%_ } _%>
7
+ import { AppModule } from './app.module.ts';
8
+ import { configureApp } from './app.config.ts';
9
+ import { setupSwagger } from './swagger.ts';
10
+ import { <% if (serviceDiscoveryEureka) { %>activeProfiles, <% } %>config, isProfileActive } from './config.ts';
11
+ import { httpsOptions } from './tls.ts';
12
+ <%_ if (serviceDiscoveryEureka) { _%>
13
+ import { EurekaService } from './registry/eureka.service.ts';
14
+ <%_ } _%>
15
+ <%_ if (serviceDiscoveryConsul) { _%>
16
+ import { ConsulService } from './registry/consul.service.ts';
17
+ <%_ } _%>
18
+ import { Logger } from '@nestjs/common';
19
+ import { LevelsConsoleLogger, loggerLevels } from './common/logging.ts';
20
+ <%_ if (!skipClient) { _%>
21
+ import * as fs from 'fs';
22
+ <%_ } _%>
23
+ <%_ if (authenticationType === 'oauth2') { _%>
24
+ import passport from 'passport';
25
+ <%_ } _%>
26
+ // The levels of the loggers (logging.level.* of the configuration), like Spring Boot, the loggers endpoint changes them.
27
+ loggerLevels.configure(config);
28
+ const appLogger = new LevelsConsoleLogger();
29
+ Logger.overrideLogger(appLogger);
30
+ const logger: Logger = new Logger('Main');
31
+ const port = process.env.NODE_SERVER_PORT || config.get('server.port');
32
+ <%_ if (serviceDiscoveryEureka) { _%>
33
+ const useJHipsterRegistry = config.get('eureka.client.enabled');
34
+ <%_ } _%>
35
+
36
+ async function bootstrap(): Promise<void> {
37
+ <%_ if (serviceDiscoveryEureka) { _%>
38
+ await loadCloudConfig();
39
+ loggerLevels.configure(config);
40
+ <%_ } _%>
41
+
42
+ // abortOnError: false: an error of the initialization (the database still unreachable after the retries) rejects
43
+ // to the catch of bootstrap() below, instead of Nest stopping the process by itself.
44
+ const tlsOptions = httpsOptions();
45
+ const app = await NestFactory.create(AppModule, { abortOnError: false, logger: appLogger, httpsOptions: tlsOptions });
46
+ // Close the application (HTTP server, database connections) on SIGTERM, the signal docker stop sends.
47
+ app.enableShutdownHooks();
48
+ // CORS, global validation<% if (authenticationUsesCsrf) { %>, HTTP settings and sessions<% } else { %> and HTTP settings<% } %>, shared with the e2e tests.
49
+ configureApp(app);
50
+
51
+ <%_ if (authenticationType === 'oauth2') { _%>
52
+
53
+ app.use(passport.initialize());
54
+ app.use(passport.session());
55
+ <%_ } _%>
56
+
57
+ <%_ if (!skipClient) { _%>
58
+ const staticClientPath = config.getClientPath();
59
+ if (fs.existsSync(staticClientPath)) {
60
+ logger.log(`Serving static client resources on ${staticClientPath}`);
61
+ } else {
62
+ logger.log(`No client it has been found`);
63
+ }
64
+ <%_ } else { _%>
65
+ logger.log(`The client is not been generated`);
66
+ <%_ } _%>
67
+ // The API documentation of the api-docs profile, like JHipster Spring Boot.
68
+ if (isProfileActive('api-docs')) {
69
+ setupSwagger(app);
70
+ }
71
+
72
+ await app.listen(port);
73
+ logger.log(`Application listening on ${tlsOptions ? 'https' : 'http'} port ${port}`);
74
+ <%_ if (serviceDiscoveryEureka) { _%>
75
+ // Registered once it listens, so a gateway routes to the application once it answers.
76
+ app.get(EurekaService).register(Number(port));
77
+ <%_ } _%>
78
+ <%_ if (serviceDiscoveryConsul) { _%>
79
+ // Registered once it listens, so a gateway routes to the application once it answers.
80
+ await app.get(ConsulService).register(Number(port));
81
+ <%_ } _%>
82
+ }
83
+
84
+ <%_ if (serviceDiscoveryEureka) { _%>
85
+ async function loadCloudConfig(): Promise<void> {
86
+ if (useJHipsterRegistry) {
87
+ const endpoint = config.get('cloud.config.uri') || 'http://admin:admin@localhost:8761/config';
88
+ logger.log(`Loading cloud config from ${endpoint}`);
89
+
90
+ const cloudConfig = await cloudConfigClient.load({
91
+ context: process.env,
92
+ endpoint,
93
+ name: config.get('cloud.config.name'),
94
+ // The active profiles, like Spring Cloud Config.
95
+ profiles: activeProfiles,
96
+ // The label (git branch, tag or commit) of the configuration, like spring.cloud.config.label.
97
+ label: config.get('cloud.config.label'),
98
+ // auth: {
99
+ // user: config.get('jhipster.registry.username') || 'admin',
100
+ // pass: config.get('jhipster.registry.password') || 'admin'
101
+ // }
102
+ });
103
+ config.addAll(cloudConfig.properties);
104
+ }
105
+ }
106
+
107
+ <%_ } _%>
108
+
109
+ bootstrap().catch((error: unknown) => {
110
+ // A failed start (database unreachable after the retries, port in use, cloud config not loaded, ...) stops the process
111
+ // with a failure exit code, for the container orchestrator or the process manager to see it and restart it.
112
+ logger.error(`Application failed to start: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error.stack : undefined);
113
+ process.exit(1);
114
+ });
@@ -0,0 +1,27 @@
1
+ import { Controller, Get, NotFoundException, UseGuards } from '@nestjs/common';
2
+ import { ApiExcludeController, OpenAPIObject } from '@nestjs/swagger';
3
+
4
+ import { AuthGuard, Roles, RolesGuard, RoleType } from '../auth/index.ts';
5
+ import { ApiDocsService } from './api-docs.service.ts';
6
+
7
+ /**
8
+ * The OpenAPI document of the api-docs profile at the path of springdoc, which the API page of the JHipster clients
9
+ * reads, for the administrators like JHipster Spring Boot.
10
+ */
11
+ @ApiExcludeController()
12
+ @Controller('v3')
13
+ @UseGuards(AuthGuard, RolesGuard)
14
+ @Roles(RoleType.ADMIN)
15
+ export class ApiDocsController {
16
+ constructor(private readonly apiDocsService: ApiDocsService) {}
17
+
18
+ @Get('/api-docs')
19
+ apiDocs(): OpenAPIObject {
20
+ const document = this.apiDocsService.document;
21
+ if (!document) {
22
+ // Without the api-docs profile.
23
+ throw new NotFoundException();
24
+ }
25
+ return document;
26
+ }
27
+ }
@@ -0,0 +1,8 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import { OpenAPIObject } from '@nestjs/swagger';
3
+
4
+ /** The OpenAPI document of the application, created by setupSwagger with the api-docs profile. */
5
+ @Injectable()
6
+ export class ApiDocsService {
7
+ document?: OpenAPIObject;
8
+ }