@things-factory/auth-base 10.1.213 → 10.1.218

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 (114) hide show
  1. package/config/config.development.js +2 -4
  2. package/config/config.production.js +1 -2
  3. package/dist-client/actions/auth.d.ts +1 -0
  4. package/dist-client/actions/auth.js +6 -0
  5. package/dist-client/actions/auth.js.map +1 -1
  6. package/dist-client/reducers/auth.d.ts +8 -0
  7. package/dist-client/reducers/auth.js +8 -2
  8. package/dist-client/reducers/auth.js.map +1 -1
  9. package/dist-client/tsconfig.tsbuildinfo +1 -1
  10. package/dist-server/constants/error-code.d.ts +1 -0
  11. package/dist-server/constants/error-code.js +2 -1
  12. package/dist-server/constants/error-code.js.map +1 -1
  13. package/dist-server/controllers/auth.d.ts +0 -1
  14. package/dist-server/controllers/auth.js +0 -1
  15. package/dist-server/controllers/auth.js.map +1 -1
  16. package/dist-server/controllers/password-setup.d.ts +33 -0
  17. package/dist-server/controllers/password-setup.js +77 -0
  18. package/dist-server/controllers/password-setup.js.map +1 -0
  19. package/dist-server/controllers/reset-password.d.ts +8 -1
  20. package/dist-server/controllers/reset-password.js +21 -11
  21. package/dist-server/controllers/reset-password.js.map +1 -1
  22. package/dist-server/controllers/signin.js +10 -0
  23. package/dist-server/controllers/signin.js.map +1 -1
  24. package/dist-server/index.d.ts +1 -0
  25. package/dist-server/index.js +2 -0
  26. package/dist-server/index.js.map +1 -1
  27. package/dist-server/middlewares/jwt-authenticate-middleware.js +8 -25
  28. package/dist-server/middlewares/jwt-authenticate-middleware.js.map +1 -1
  29. package/dist-server/router/auth-public-process-router.js +3 -41
  30. package/dist-server/router/auth-public-process-router.js.map +1 -1
  31. package/dist-server/service/access-request/access-request.js +2 -2
  32. package/dist-server/service/access-request/access-request.js.map +1 -1
  33. package/dist-server/service/audit/audit-kinds.js +1 -0
  34. package/dist-server/service/audit/audit-kinds.js.map +1 -1
  35. package/dist-server/service/audit/audit-subscriber.d.ts +1 -7
  36. package/dist-server/service/audit/audit-subscriber.js +2 -33
  37. package/dist-server/service/audit/audit-subscriber.js.map +1 -1
  38. package/dist-server/service/audit/index.d.ts +1 -1
  39. package/dist-server/service/index.d.ts +2 -4
  40. package/dist-server/service/index.js +22 -27
  41. package/dist-server/service/index.js.map +1 -1
  42. package/dist-server/service/open-fields.js +0 -2
  43. package/dist-server/service/open-fields.js.map +1 -1
  44. package/dist-server/service/user/user-mutation.d.ts +27 -6
  45. package/dist-server/service/user/user-mutation.js +32 -114
  46. package/dist-server/service/user/user-mutation.js.map +1 -1
  47. package/dist-server/service/user/user-query.d.ts +3 -2
  48. package/dist-server/service/user/user-query.js +17 -21
  49. package/dist-server/service/user/user-query.js.map +1 -1
  50. package/dist-server/service/user/user-types.d.ts +6 -2
  51. package/dist-server/service/user/user-types.js +20 -9
  52. package/dist-server/service/user/user-types.js.map +1 -1
  53. package/dist-server/service/user/user.js +17 -8
  54. package/dist-server/service/user/user.js.map +1 -1
  55. package/dist-server/service/verification-token/verification-token.d.ts +1 -0
  56. package/dist-server/service/verification-token/verification-token.js +1 -0
  57. package/dist-server/service/verification-token/verification-token.js.map +1 -1
  58. package/dist-server/templates/reset-password-email.d.ts +10 -3
  59. package/dist-server/templates/reset-password-email.js +8 -4
  60. package/dist-server/templates/reset-password-email.js.map +1 -1
  61. package/dist-server/tsconfig.tsbuildinfo +1 -1
  62. package/dist-server/utils/password-reset-rule.d.ts +15 -0
  63. package/dist-server/utils/password-reset-rule.js +34 -0
  64. package/dist-server/utils/password-reset-rule.js.map +1 -0
  65. package/dist-server/utils/verification-token-rule.js +3 -1
  66. package/dist-server/utils/verification-token-rule.js.map +1 -1
  67. package/package.json +2 -2
  68. package/tests/add-user-gates.test.ts +34 -0
  69. package/tests/list-inheritance-db.test.ts +0 -15
  70. package/tests/lock-recovery.test.ts +2 -2
  71. package/tests/open-doors.test.ts +2 -5
  72. package/tests/password-reset-rule-db.test.ts +159 -0
  73. package/tests/password-setup-db.test.ts +213 -0
  74. package/tests/picture-reducer.test.ts +25 -0
  75. package/tests/verification-token-db.test.ts +12 -7
  76. package/translations/en.json +4 -2
  77. package/translations/es.json +4 -2
  78. package/translations/ja.json +4 -2
  79. package/translations/ko.json +4 -2
  80. package/translations/ms.json +4 -2
  81. package/translations/zh.json +4 -2
  82. package/dist-server/controllers/invitation.d.ts +0 -75
  83. package/dist-server/controllers/invitation.js +0 -195
  84. package/dist-server/controllers/invitation.js.map +0 -1
  85. package/dist-server/controllers/utils/make-invitation-token.d.ts +0 -1
  86. package/dist-server/controllers/utils/make-invitation-token.js +0 -9
  87. package/dist-server/controllers/utils/make-invitation-token.js.map +0 -1
  88. package/dist-server/controllers/utils/save-invitation-token.d.ts +0 -5
  89. package/dist-server/controllers/utils/save-invitation-token.js +0 -12
  90. package/dist-server/controllers/utils/save-invitation-token.js.map +0 -1
  91. package/dist-server/service/invitation/index.d.ts +0 -5
  92. package/dist-server/service/invitation/index.js +0 -9
  93. package/dist-server/service/invitation/index.js.map +0 -1
  94. package/dist-server/service/invitation/invitation-mutation.d.ts +0 -20
  95. package/dist-server/service/invitation/invitation-mutation.js +0 -109
  96. package/dist-server/service/invitation/invitation-mutation.js.map +0 -1
  97. package/dist-server/service/invitation/invitation-query.d.ts +0 -23
  98. package/dist-server/service/invitation/invitation-query.js +0 -89
  99. package/dist-server/service/invitation/invitation-query.js.map +0 -1
  100. package/dist-server/service/invitation/invitation-types.d.ts +0 -5
  101. package/dist-server/service/invitation/invitation-types.js +0 -21
  102. package/dist-server/service/invitation/invitation-types.js.map +0 -1
  103. package/dist-server/service/invitation/invitation.d.ts +0 -26
  104. package/dist-server/service/invitation/invitation.js +0 -142
  105. package/dist-server/service/invitation/invitation.js.map +0 -1
  106. package/dist-server/templates/invitation-email.d.ts +0 -6
  107. package/dist-server/templates/invitation-email.js +0 -82
  108. package/dist-server/templates/invitation-email.js.map +0 -1
  109. package/dist-server/utils/invitation-state.d.ts +0 -52
  110. package/dist-server/utils/invitation-state.js +0 -76
  111. package/dist-server/utils/invitation-state.js.map +0 -1
  112. package/tests/invitation-db.test.ts +0 -416
  113. package/tests/invitation-route.test.ts +0 -116
  114. package/tests/invitation-state.test.ts +0 -92
@@ -5,12 +5,13 @@ const tslib_1 = require("tslib");
5
5
  const type_graphql_1 = require("type-graphql");
6
6
  const graphql_scalars_1 = require("graphql-scalars");
7
7
  const typeorm_1 = require("typeorm");
8
- const env_1 = require("@things-factory/env");
9
8
  const shell_1 = require("@things-factory/shell");
10
9
  const delete_user_js_1 = require("../../controllers/delete-user.js");
11
10
  const assignable_roles_js_1 = require("../../utils/assignable-roles.js");
12
11
  const get_domain_users_js_1 = require("../../utils/get-domain-users.js");
13
12
  const domain_ownership_js_1 = require("../../utils/domain-ownership.js");
13
+ const password_reset_rule_js_1 = require("../../utils/password-reset-rule.js");
14
+ const password_setup_js_1 = require("../../controllers/password-setup.js");
14
15
  const role_js_1 = require("../role/role.js");
15
16
  const user_js_1 = require("./user.js");
16
17
  const user_types_js_1 = require("./user-types.js");
@@ -18,7 +19,6 @@ const error_code_js_1 = require("../../constants/error-code.js");
18
19
  let UserMutation = class UserMutation {
19
20
  async createUser(user, context) {
20
21
  const { domain, tx } = context.state;
21
- const { defaultPassword } = env_1.config.get('password');
22
22
  const { username, email } = user;
23
23
  const userRepository = (0, shell_1.getRepository)(user_js_1.User, tx);
24
24
  user.username = username.trim();
@@ -29,21 +29,18 @@ let UserMutation = class UserMutation {
29
29
  if (await userRepository.findOne({ where: { email: (0, typeorm_1.ILike)(user.email) } })) {
30
30
  throw new Error(context.t('error.' + error_code_js_1.EMAIL_ALREADY_EXISTS));
31
31
  }
32
- if (!user.password && !defaultPassword) {
33
- throw new Error('initial password or default password should be supported.');
34
- }
35
32
  // TODO username은 다음 패턴을 따라야 한다. pattern="^[A-Za-z0-9._@-]+$"
36
33
  if (!/^[A-Za-z0-9._@-]+$/.test(user.username)) {
37
34
  throw new Error(context.t('error.' + error_code_js_1.USERNAME_INVALID, { username: user.username }));
38
35
  }
39
- // consider if validation password rule is required
40
- /* check if password is following the rule */
41
- // User.validatePasswordByRule(user.password, context.lng)
42
- const salt = user_js_1.User.generateSalt();
36
+ /* Nobody sets the new person's password - it waits for them, and `issuePasswordSetupLink` hands them the way in (ADR-0161). */
37
+ const account = {};
38
+ (0, password_setup_js_1.sealPassword)(account);
43
39
  return await userRepository.save({
44
40
  creator: context.state.user,
45
41
  updater: context.state.user,
46
42
  ...user,
43
+ ...account,
47
44
  domains: [domain],
48
45
  roles: user.roles && user.roles.length
49
46
  ? await (0, shell_1.getRepository)(role_js_1.Role, tx).findBy({
@@ -51,9 +48,7 @@ let UserMutation = class UserMutation {
51
48
  domain: { id: domain.id }
52
49
  })
53
50
  : [],
54
- salt,
55
- passwordUpdatedAt: new Date(),
56
- password: user.password ? user_js_1.User.encode(user.password, salt) : user_js_1.User.encode(defaultPassword, salt)
51
+ passwordUpdatedAt: new Date()
57
52
  });
58
53
  }
59
54
  async updateUser(email, patch, context) {
@@ -78,81 +73,6 @@ let UserMutation = class UserMutation {
78
73
  updater
79
74
  });
80
75
  }
81
- async updateMultipleUser(patches, context) {
82
- const { domain, user, tx } = context.state;
83
- const userRepo = (0, shell_1.getRepository)(user_js_1.User, tx);
84
- let results = [];
85
- const _createRecords = patches.filter((patch) => patch.cuFlag.toUpperCase() === '+');
86
- const _updateRecords = patches.filter((patch) => patch.cuFlag.toUpperCase() === 'M');
87
- if (_createRecords.length > 0) {
88
- for (let i = 0; i < _createRecords.length; i++) {
89
- const newRecord = _createRecords[i];
90
- // consider if validation password rule is required
91
- /* check if password is following the rule */
92
- // User.validatePasswordByRule(newRecord.password, context.lng)
93
- const salt = user_js_1.User.generateSalt();
94
- const result = await userRepo.save({
95
- ...newRecord,
96
- domains: [domain],
97
- salt,
98
- password: user_js_1.User.encode(newRecord.password, salt),
99
- passwordUpdatedAt: new Date(),
100
- creator: user,
101
- updater: user
102
- });
103
- // repository api는 작동하지 않음.
104
- // await tx
105
- // .createQueryBuilder()
106
- // .insert()
107
- // .into('users_domains')
108
- // .values({
109
- // usersId: result.id,
110
- // domainsId: domain.id
111
- // })
112
- // .execute()
113
- results.push({ ...result, cuFlag: '+' });
114
- }
115
- }
116
- if (_updateRecords.length > 0) {
117
- for (let i = 0; i < _updateRecords.length; i++) {
118
- const updateRecord = _updateRecords[i];
119
- // consider if validation password rule is required
120
- /* check if password is following the rule */
121
- // User.validatePasswordByRule(updateRecord.password, context.lng)
122
- const user = await userRepo.findOne({ where: { id: updateRecord.id }, relations: ['domains'] });
123
- var domains = user.domains.find(d => d.id === domain.id) ? user.domains : [...user.domains, domain];
124
- const result = await userRepo.save({
125
- ...user,
126
- ...updateRecord,
127
- domains,
128
- password: updateRecord.password ? user_js_1.User.encode(updateRecord.password, user.salt) : user.password,
129
- updater: user
130
- });
131
- if (!updateRecord.status) {
132
- continue;
133
- }
134
- // const domain = await user.domain
135
- // if (!domain) {
136
- // continue
137
- // }
138
- // const domainId = domain.id
139
- // const domains = await user.domains
140
- // if (!domains.find(domain => domain.id == domainId)) {
141
- // await tx
142
- // .createQueryBuilder()
143
- // .insert()
144
- // .into('users_domains')
145
- // .values({
146
- // usersId: user.id,
147
- // domainsId: domain.id
148
- // })
149
- // .execute()
150
- // }
151
- results.push({ ...result, cuFlag: 'M' });
152
- }
153
- }
154
- return results;
155
- }
156
76
  async deleteUser(username, context) {
157
77
  const { tx } = context.state;
158
78
  await (0, delete_user_js_1.deleteUser)({ username }, tx);
@@ -264,6 +184,10 @@ let UserMutation = class UserMutation {
264
184
  if (!targetUser?.domains?.find((userDomain) => userDomain.id === domain.id)) {
265
185
  throw new Error('User is not belong to domain');
266
186
  }
187
+ /* Activating does not give a password - a waiting account opens only through its setup link (ADR-0161). */
188
+ if (targetUser.status === user_js_1.UserStatus.PWD_RESET_REQUIRED) {
189
+ throw new shell_1.Refusal('password-setup-pending', {}, 'This account is waiting for its password. Issue a password setup link.');
190
+ }
267
191
  targetUser.failCount = 0;
268
192
  targetUser.status = user_js_1.UserStatus.ACTIVATED;
269
193
  await userRepository.save(targetUser);
@@ -296,12 +220,14 @@ let UserMutation = class UserMutation {
296
220
  await userRepository.save(targetUser);
297
221
  return true;
298
222
  }
299
- async resetPasswordToDefault(username, context) {
223
+ /**
224
+ * The person sets their own password through a one-time link - an administrator never sets it (ADR-0161).
225
+ *
226
+ * For an account this domain made and one whose password it takes back alike. Who may be handed one from here is
227
+ * `password-reset-rule.ts`: someone wholly of this domain, owning no domain.
228
+ */
229
+ async issuePasswordSetupLink(username, mail, context) {
300
230
  const { tx, domain } = context.state;
301
- const { defaultPassword } = env_1.config.get('password');
302
- if (!defaultPassword) {
303
- throw new Error('No default password found');
304
- }
305
231
  const userRepository = (0, shell_1.getRepository)(user_js_1.User, tx);
306
232
  var targetUser = await userRepository.findOne({
307
233
  where: { username },
@@ -319,10 +245,11 @@ let UserMutation = class UserMutation {
319
245
  if (!targetUser?.domains?.find((userDomain) => userDomain.id === domain.id)) {
320
246
  throw new Error('User is not belong to domain');
321
247
  }
322
- targetUser.salt = user_js_1.User.generateSalt();
323
- targetUser.password = user_js_1.User.encode(defaultPassword, targetUser.salt);
324
- await userRepository.save(targetUser);
325
- return true;
248
+ const refusal = await (0, password_reset_rule_js_1.passwordResetRefusal)(targetUser, domain, tx);
249
+ if (refusal) {
250
+ throw refusal;
251
+ }
252
+ return await (0, password_setup_js_1.issuePasswordSetupLink)({ user: targetUser, mail, context, tx });
326
253
  }
327
254
  async updateUserRoles(username, availableRoles, selectedRoles, context) {
328
255
  const { domain, tx } = context.state;
@@ -374,18 +301,6 @@ tslib_1.__decorate([
374
301
  tslib_1.__metadata("design:paramtypes", [String, user_types_js_1.UserPatch, Object]),
375
302
  tslib_1.__metadata("design:returntype", Promise)
376
303
  ], UserMutation.prototype, "updateUser", null);
377
- tslib_1.__decorate([
378
- (0, type_graphql_1.Directive)('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)'),
379
- (0, type_graphql_1.Directive)('@transaction'),
380
- (0, type_graphql_1.Mutation)(returns => [user_js_1.User], {
381
- description: 'Updates or creates multiple users in a single operation. Use this mutation for batch processing of user records.'
382
- }),
383
- tslib_1.__param(0, (0, type_graphql_1.Arg)('patches', type => [user_types_js_1.UserPatch], { description: 'An array of patch objects for batch update or creation.' })),
384
- tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
385
- tslib_1.__metadata("design:type", Function),
386
- tslib_1.__metadata("design:paramtypes", [Array, Object]),
387
- tslib_1.__metadata("design:returntype", Promise)
388
- ], UserMutation.prototype, "updateMultipleUser", null);
389
304
  tslib_1.__decorate([
390
305
  (0, type_graphql_1.Directive)('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)'),
391
306
  (0, type_graphql_1.Directive)('@transaction'),
@@ -449,6 +364,7 @@ tslib_1.__decorate([
449
364
  tslib_1.__decorate([
450
365
  (0, type_graphql_1.Directive)('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)'),
451
366
  (0, type_graphql_1.Directive)('@transaction'),
367
+ (0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals),
452
368
  (0, type_graphql_1.Mutation)(returns => Boolean, {
453
369
  description: 'Activates a user account in the current domain. Use this mutation to enable a user who was previously inactive.'
454
370
  }),
@@ -473,15 +389,17 @@ tslib_1.__decorate([
473
389
  tslib_1.__decorate([
474
390
  (0, type_graphql_1.Directive)('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)'),
475
391
  (0, type_graphql_1.Directive)('@transaction'),
476
- (0, type_graphql_1.Mutation)(returns => Boolean, {
477
- description: "Resets a user's password to the default value. Use this mutation to restore access to a user who has forgotten their password."
392
+ (0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals),
393
+ (0, type_graphql_1.Mutation)(returns => user_types_js_1.PasswordSetupLink, {
394
+ description: "Puts the user waiting for a password they set themselves and issues the one-time link to it. The current password stops working and open sessions end. Mailed, or returned once for the administrator to hand over."
478
395
  }),
479
- tslib_1.__param(0, (0, type_graphql_1.Arg)('username', { description: 'The username or email of the user whose password to reset.' })),
480
- tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
396
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('username', { description: 'The username or email of the user.' })),
397
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('mail', { description: "True mails the link to the user's address; false returns it once." })),
398
+ tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
481
399
  tslib_1.__metadata("design:type", Function),
482
- tslib_1.__metadata("design:paramtypes", [String, Object]),
400
+ tslib_1.__metadata("design:paramtypes", [String, Boolean, Object]),
483
401
  tslib_1.__metadata("design:returntype", Promise)
484
- ], UserMutation.prototype, "resetPasswordToDefault", null);
402
+ ], UserMutation.prototype, "issuePasswordSetupLink", null);
485
403
  tslib_1.__decorate([
486
404
  (0, type_graphql_1.Directive)('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)'),
487
405
  (0, type_graphql_1.Directive)('@transaction'),
@@ -1 +1 @@
1
- {"version":3,"file":"user-mutation.js","sourceRoot":"","sources":["../../../server/service/user/user-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Mutation, Resolver, UseMiddleware } from 'type-graphql'\nimport { GraphQLEmailAddress } from 'graphql-scalars'\nimport { ILike, In, SelectQueryBuilder, EntityManager } from 'typeorm'\n\nimport { config } from '@things-factory/env'\nimport { Domain, getRepository, ObjectRef, SpeakRefusals } from '@things-factory/shell'\n\nimport { deleteUser as commonDeleteUser, deleteUsers as commonDeleteUsers } from '../../controllers/delete-user.js'\nimport { assignRoles } from '../../utils/assignable-roles.js'\nimport { buildDomainUsersQueryBuilder } from '../../utils/get-domain-users.js'\nimport { isDomainOwner, setPrimaryDomainOwner } from '../../utils/domain-ownership.js'\nimport { Role } from '../role/role.js'\nimport { User, UserStatus } from './user.js'\nimport { NewUser, UserPatch } from './user-types.js'\nimport { USERNAME_ALREADY_EXISTS, EMAIL_ALREADY_EXISTS, USERNAME_INVALID } from '../../constants/error-code.js'\n\n@Resolver(User)\nexport class UserMutation {\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => User, {\n description:\n 'Creates a new user in the system. Use this mutation to register a user with the specified credentials and domain information.'\n })\n async createUser(\n @Arg('user', { description: 'The input object containing new user information.' }) user: NewUser,\n @Ctx() context: ResolverContext\n ) {\n const { domain, tx } = context.state\n const { defaultPassword } = config.get('password')\n const { username, email } = user\n const userRepository = getRepository(User, tx)\n\n user.username = username.trim()\n user.email = email.trim()\n\n if (await userRepository.findOne({ where: { username: user.username } })) {\n throw new Error(context.t('error.' + USERNAME_ALREADY_EXISTS))\n }\n\n if (await userRepository.findOne({ where: { email: ILike(user.email) } })) {\n throw new Error(context.t('error.' + EMAIL_ALREADY_EXISTS))\n }\n\n if (!user.password && !defaultPassword) {\n throw new Error('initial password or default password should be supported.')\n }\n\n // TODO username은 다음 패턴을 따라야 한다. pattern=\"^[A-Za-z0-9._@-]+$\"\n if (!/^[A-Za-z0-9._@-]+$/.test(user.username)) {\n throw new Error(context.t('error.' + USERNAME_INVALID, { username: user.username }))\n }\n\n // consider if validation password rule is required\n /* check if password is following the rule */\n // User.validatePasswordByRule(user.password, context.lng)\n\n const salt = User.generateSalt()\n\n return await userRepository.save({\n creator: context.state.user,\n updater: context.state.user,\n ...user,\n domains: [domain],\n roles:\n user.roles && user.roles.length\n ? await getRepository(Role, tx).findBy({\n id: In(user.roles.map(role => role.id)),\n domain: { id: domain.id }\n })\n : [],\n salt,\n passwordUpdatedAt: new Date(),\n password: user.password ? User.encode(user.password, salt) : User.encode(defaultPassword, salt)\n })\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => User, {\n description:\n 'Updates the information of an existing user. Use this mutation to modify user profile details, such as name, email, or roles.'\n })\n async updateUser(\n @Arg('email', type => GraphQLEmailAddress, { description: 'The email address of the user to update.' })\n email: string,\n @Arg('patch', { description: 'The patch object containing updated user fields.' }) patch: UserPatch,\n @Ctx() context: ResolverContext\n ) {\n const { domain, user: updater, tx }: { domain: Domain; user: User; tx?: EntityManager } = context.state\n const qb: SelectQueryBuilder<User> = buildDomainUsersQueryBuilder(domain.id, 'USER')\n const user: User = await qb\n .andWhere('LOWER(USER.email) = :email', { email: email?.toLowerCase().trim() || '' })\n .leftJoinAndSelect('USER.roles', 'ROLES')\n .leftJoinAndSelect('ROLES.domain', 'R_DOMAIN')\n .getOne()\n\n if (patch.roles) {\n patch.roles = await getRepository(Role, tx).find({\n where: { id: In(patch.roles.map((r: Partial<Role>) => r.id)) }\n })\n }\n\n if (patch.status && patch.status === 'activated') {\n user.status = UserStatus.ACTIVATED\n }\n\n return await getRepository(User, tx).save({\n ...user,\n ...patch,\n updater\n } as any)\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [User], {\n description:\n 'Updates or creates multiple users in a single operation. Use this mutation for batch processing of user records.'\n })\n async updateMultipleUser(\n @Arg('patches', type => [UserPatch], { description: 'An array of patch objects for batch update or creation.' })\n patches: UserPatch[],\n @Ctx() context: ResolverContext\n ) {\n const { domain, user, tx } = context.state\n const userRepo = getRepository(User, tx)\n\n let results = []\n const _createRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === '+')\n const _updateRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === 'M')\n\n if (_createRecords.length > 0) {\n for (let i = 0; i < _createRecords.length; i++) {\n const newRecord = _createRecords[i]\n\n // consider if validation password rule is required\n /* check if password is following the rule */\n // User.validatePasswordByRule(newRecord.password, context.lng)\n\n const salt = User.generateSalt()\n const result = await userRepo.save({\n ...(newRecord as any),\n domains: [domain],\n salt,\n password: User.encode(newRecord.password, salt),\n passwordUpdatedAt: new Date(),\n creator: user,\n updater: user\n })\n\n // repository api는 작동하지 않음.\n // await tx\n // .createQueryBuilder()\n // .insert()\n // .into('users_domains')\n // .values({\n // usersId: result.id,\n // domainsId: domain.id\n // })\n // .execute()\n\n results.push({ ...result, cuFlag: '+' })\n }\n }\n\n if (_updateRecords.length > 0) {\n for (let i = 0; i < _updateRecords.length; i++) {\n const updateRecord = _updateRecords[i]\n // consider if validation password rule is required\n /* check if password is following the rule */\n // User.validatePasswordByRule(updateRecord.password, context.lng)\n\n const user = await userRepo.findOne({ where: { id: updateRecord.id }, relations: ['domains'] })\n var domains = user.domains.find(d => d.id === domain.id) ? user.domains : [...user.domains, domain]\n\n const result = await userRepo.save({\n ...user,\n ...(updateRecord as any),\n domains,\n password: updateRecord.password ? User.encode(updateRecord.password, user.salt) : user.password,\n updater: user\n })\n\n if (!updateRecord.status) {\n continue\n }\n\n // const domain = await user.domain\n // if (!domain) {\n // continue\n // }\n\n // const domainId = domain.id\n // const domains = await user.domains\n // if (!domains.find(domain => domain.id == domainId)) {\n // await tx\n // .createQueryBuilder()\n // .insert()\n // .into('users_domains')\n // .values({\n // usersId: user.id,\n // domainsId: domain.id\n // })\n // .execute()\n // }\n\n results.push({ ...result, cuFlag: 'M' })\n }\n }\n\n return results\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Boolean, {\n description:\n 'Deletes a user from the system by their username. Use this mutation to permanently remove a user account and revoke their access.'\n })\n async deleteUser(\n @Arg('username', { description: 'The username of the user to delete.' }) username: string,\n @Ctx() context: ResolverContext\n ) {\n const { tx } = context.state\n\n await commonDeleteUser({ username }, tx)\n\n return true\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Boolean, {\n description:\n 'Deletes multiple users from the system by their usernames. Use this mutation to remove several user accounts at once.'\n })\n async deleteUsers(\n @Arg('usernames', type => [String], { description: 'An array of usernames to delete.' }) usernames: string[],\n @Ctx() context: ResolverContext\n ) {\n const { tx } = context.state\n await commonDeleteUsers({ usernames }, tx)\n\n return true\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Boolean, {\n description:\n 'Invites an existing user to join the current domain. Use this mutation to add a user to a domain if they already exist in the system.'\n })\n async inviteUser(\n @Arg('username', { description: 'The username or email of the user to invite.' }) username: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, tx } = context.state\n const userRepository = getRepository(User, tx)\n\n var invitee: User = await userRepository.findOne({\n where: { username },\n relations: ['domains']\n })\n\n if (!invitee && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(username)) {\n invitee = await userRepository.findOne({\n where: { email: ILike(username) },\n relations: ['domains']\n })\n }\n\n if (!invitee) {\n throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))\n }\n\n const existingDomains: Domain[] = invitee.domains\n if (existingDomains.find((d: Domain) => d.id === domain.id)) {\n throw new Error(context.t('error.x already exists in y', { x: context.t('field.user'), y: domain.name }))\n }\n\n invitee.domains = [...existingDomains, domain]\n await userRepository.save(invitee)\n\n return true\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Boolean, {\n description:\n \"Removes a user from the current domain. Use this mutation to revoke a user's access to a specific domain without deleting their account.\"\n })\n async deleteDomainUser(\n @Arg('username', { description: 'The username or email of the user to remove from the domain.' }) username: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { tx, domain } = context.state\n const userRepository = getRepository(User, tx)\n\n var user: User = await userRepository.findOne({\n where: { username },\n relations: ['domains', 'roles']\n })\n\n if (!user && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(username)) {\n user = await userRepository.findOne({\n where: { email: ILike(username) },\n relations: ['domains', 'roles']\n })\n }\n\n if (!user) {\n throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))\n }\n\n const targetDomainIdx: number = user.domains.findIndex((userDomain: Domain) => userDomain.id === domain.id)\n if (targetDomainIdx < 0) {\n throw new Error(context.t('error.x is not a member of y', { x: user.name, y: domain.name }))\n }\n\n // Remove domain relation with user\n user.domains.splice(targetDomainIdx, 1)\n\n // Remove domain's roles that user has\n user.roles = user.roles.filter((role: Role) => role.domainId !== domain.id)\n\n await userRepository.save(user)\n\n return true\n }\n\n @Directive('@privilege(domainOwnerGranted: true, superUserGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Boolean, {\n description:\n 'Transfers domain ownership to another user. Use this mutation to assign the owner role to a different user within the domain.'\n })\n async transferOwner(\n @Arg('username', { description: 'The username or email of the user to transfer ownership to.' }) username: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, tx, user: actor } = context.state\n const userRepository = getRepository(User, tx)\n\n var user: User = await userRepository.findOne({\n where: { username },\n relations: ['domains', 'roles']\n })\n\n if (!user && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(username)) {\n user = await userRepository.findOne({\n where: { email: ILike(username) },\n relations: ['domains', 'roles']\n })\n }\n\n if (!user) {\n throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))\n }\n\n if (user.status !== UserStatus.ACTIVATED) {\n throw new Error('Only activated users are eligible to receive admin privileges.')\n }\n\n if (user.domains.map((d: Domain) => d.id).indexOf(domain.id) < 0) {\n throw new Error(`User is not belongs to current domain`)\n }\n\n /* 역할은 부모 도메인으로부터 상속될 수 있으므로 부여된 상속 역할도 자격으로 인정한다. */\n const grantableRoleDomainIds: string[] = [domain.id, domain.parentId].filter(Boolean)\n if (user.roles.filter((r: Role) => grantableRoleDomainIds.includes(r.domainId)).length == 0) {\n throw new Error(`Only users with at least one role in this domain are eligible to receive admin privileges.`)\n }\n\n /* 대표 오너 컬럼과 `DomainOwner` 테이블을 함께 갱신한다 (기존 오너 엔트리는 유지). */\n await setPrimaryDomainOwner(domain, user.id, actor, tx)\n\n return true\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Boolean, {\n description:\n 'Activates a user account in the current domain. Use this mutation to enable a user who was previously inactive.'\n })\n async activateUser(\n @Arg('username', { description: 'The username or email of the user to activate.' }) username: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { tx, domain } = context.state\n const userRepository = getRepository(User, tx)\n\n var targetUser: User = await userRepository.findOne({\n where: { username },\n relations: ['domains']\n })\n\n if (!targetUser && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(username)) {\n targetUser = await userRepository.findOne({\n where: { email: ILike(username) },\n relations: ['domains']\n })\n }\n\n if (!targetUser) {\n throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))\n }\n\n if (!targetUser?.domains?.find((userDomain: Domain) => userDomain.id === domain.id)) {\n throw new Error('User is not belong to domain')\n }\n\n targetUser.failCount = 0\n targetUser.status = UserStatus.ACTIVATED\n\n await userRepository.save(targetUser)\n\n return true\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Boolean, {\n description:\n 'Inactivates a user account in the current domain. Use this mutation to disable a user, making them unable to log in.'\n })\n async inactivateUser(\n @Arg('username', { description: 'The username or email of the user to inactivate.' }) username: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { tx, domain } = context.state\n const userRepository = getRepository(User, tx)\n\n var targetUser: User = await userRepository.findOne({\n where: { username },\n relations: ['domains']\n })\n\n if (!targetUser && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(username)) {\n targetUser = await userRepository.findOne({\n where: { email: ILike(username) },\n relations: ['domains']\n })\n }\n\n if (!targetUser) {\n throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))\n }\n\n if (!targetUser?.domains?.find((userDomain: Domain) => userDomain.id === domain.id)) {\n throw new Error('User is not belong to domain')\n }\n\n /* 공동 오너(`DomainOwner` 테이블)도 도메인 관리자이므로 같은 보호를 받는다. */\n if (targetUser.userType == 'admin' || (await isDomainOwner(domain, targetUser, tx))) {\n throw new Error('Admin deactivation not allowed')\n }\n\n targetUser.status = UserStatus.INACTIVE\n\n await userRepository.save(targetUser)\n\n return true\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Boolean, {\n description:\n \"Resets a user's password to the default value. Use this mutation to restore access to a user who has forgotten their password.\"\n })\n async resetPasswordToDefault(\n @Arg('username', { description: 'The username or email of the user whose password to reset.' }) username: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { tx, domain } = context.state\n\n const { defaultPassword } = config.get('password')\n if (!defaultPassword) {\n throw new Error('No default password found')\n }\n\n const userRepository = getRepository(User, tx)\n\n var targetUser: User = await userRepository.findOne({\n where: { username },\n relations: ['domains']\n })\n\n if (!targetUser && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(username)) {\n targetUser = await userRepository.findOne({\n where: { email: ILike(username) },\n relations: ['domains']\n })\n }\n\n if (!targetUser) {\n throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))\n }\n\n if (!targetUser?.domains?.find((userDomain: Domain) => userDomain.id === domain.id)) {\n throw new Error('User is not belong to domain')\n }\n\n targetUser.salt = User.generateSalt()\n targetUser.password = User.encode(defaultPassword, targetUser.salt)\n\n await userRepository.save(targetUser)\n\n return true\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @UseMiddleware(SpeakRefusals)\n @Mutation(returns => User, {\n description:\n \"Updates the roles assigned to a user. Use this mutation to change a user's permissions within the domain.\"\n })\n async updateUserRoles(\n @Arg('username', { description: 'The username or email of the user whose roles to update.' }) username: string,\n @Arg('availableRoles', type => [ObjectRef], { description: 'The list of roles that can be assigned to the user.' })\n availableRoles: ObjectRef[],\n @Arg('selectedRoles', type => [ObjectRef], { description: 'The list of roles to be assigned to the user.' })\n selectedRoles: ObjectRef[],\n @Ctx() context: ResolverContext\n ) {\n const { domain, tx } = context.state\n const userRepository = getRepository(User, tx)\n\n var user: User = await userRepository.findOne({\n where: { username },\n relations: ['domains', 'roles']\n })\n\n if (!user && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(username)) {\n user = await userRepository.findOne({\n where: { email: ILike(username) },\n relations: ['domains', 'roles']\n })\n }\n\n if (!user) {\n throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))\n }\n\n if (user.domains.map((d: Domain) => d.id).indexOf(domain.id) < 0) {\n throw new Error(`User is not belongs to current domain`)\n }\n\n /* Found again in this domain's scope - the ids are the client's (utils/assignable-roles.ts, ADR-0103 decision 2). */\n const { user: saved } = await assignRoles(\n user,\n { add: selectedRoles.map(role => role.id), remove: availableRoles.map(role => role.id) },\n domain,\n tx,\n context.state.user\n )\n\n return saved\n }\n}\n"]}
1
+ {"version":3,"file":"user-mutation.js","sourceRoot":"","sources":["../../../server/service/user/user-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Mutation, Resolver, UseMiddleware } from 'type-graphql'\nimport { GraphQLEmailAddress } from 'graphql-scalars'\nimport { ILike, In, SelectQueryBuilder, EntityManager } from 'typeorm'\n\nimport { Domain, getRepository, ObjectRef, Refusal, SpeakRefusals } from '@things-factory/shell'\n\nimport { deleteUser as commonDeleteUser, deleteUsers as commonDeleteUsers } from '../../controllers/delete-user.js'\nimport { assignRoles } from '../../utils/assignable-roles.js'\nimport { buildDomainUsersQueryBuilder } from '../../utils/get-domain-users.js'\nimport { isDomainOwner, setPrimaryDomainOwner } from '../../utils/domain-ownership.js'\nimport { passwordResetRefusal } from '../../utils/password-reset-rule.js'\nimport { issuePasswordSetupLink, sealPassword } from '../../controllers/password-setup.js'\nimport { Role } from '../role/role.js'\nimport { User, UserStatus } from './user.js'\nimport { NewUser, PasswordSetupLink, UserPatch } from './user-types.js'\nimport { USERNAME_ALREADY_EXISTS, EMAIL_ALREADY_EXISTS, USERNAME_INVALID } from '../../constants/error-code.js'\n\n@Resolver(User)\nexport class UserMutation {\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => User, {\n description:\n 'Creates a new user in the system. Use this mutation to register a user with the specified credentials and domain information.'\n })\n async createUser(\n @Arg('user', { description: 'The input object containing new user information.' }) user: NewUser,\n @Ctx() context: ResolverContext\n ) {\n const { domain, tx } = context.state\n const { username, email } = user\n const userRepository = getRepository(User, tx)\n\n user.username = username.trim()\n user.email = email.trim()\n\n if (await userRepository.findOne({ where: { username: user.username } })) {\n throw new Error(context.t('error.' + USERNAME_ALREADY_EXISTS))\n }\n\n if (await userRepository.findOne({ where: { email: ILike(user.email) } })) {\n throw new Error(context.t('error.' + EMAIL_ALREADY_EXISTS))\n }\n\n // TODO username은 다음 패턴을 따라야 한다. pattern=\"^[A-Za-z0-9._@-]+$\"\n if (!/^[A-Za-z0-9._@-]+$/.test(user.username)) {\n throw new Error(context.t('error.' + USERNAME_INVALID, { username: user.username }))\n }\n\n /* Nobody sets the new person's password - it waits for them, and `issuePasswordSetupLink` hands them the way in (ADR-0161). */\n const account: Partial<User> = {}\n sealPassword(account)\n\n return await userRepository.save({\n creator: context.state.user,\n updater: context.state.user,\n ...user,\n ...account,\n domains: [domain],\n roles:\n user.roles && user.roles.length\n ? await getRepository(Role, tx).findBy({\n id: In(user.roles.map(role => role.id)),\n domain: { id: domain.id }\n })\n : [],\n passwordUpdatedAt: new Date()\n })\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => User, {\n description:\n 'Updates the information of an existing user. Use this mutation to modify user profile details, such as name, email, or roles.'\n })\n async updateUser(\n @Arg('email', type => GraphQLEmailAddress, { description: 'The email address of the user to update.' })\n email: string,\n @Arg('patch', { description: 'The patch object containing updated user fields.' }) patch: UserPatch,\n @Ctx() context: ResolverContext\n ) {\n const { domain, user: updater, tx }: { domain: Domain; user: User; tx?: EntityManager } = context.state\n const qb: SelectQueryBuilder<User> = buildDomainUsersQueryBuilder(domain.id, 'USER')\n const user: User = await qb\n .andWhere('LOWER(USER.email) = :email', { email: email?.toLowerCase().trim() || '' })\n .leftJoinAndSelect('USER.roles', 'ROLES')\n .leftJoinAndSelect('ROLES.domain', 'R_DOMAIN')\n .getOne()\n\n if (patch.roles) {\n patch.roles = await getRepository(Role, tx).find({\n where: { id: In(patch.roles.map((r: Partial<Role>) => r.id)) }\n })\n }\n\n if (patch.status && patch.status === 'activated') {\n user.status = UserStatus.ACTIVATED\n }\n\n return await getRepository(User, tx).save({\n ...user,\n ...patch,\n updater\n } as any)\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Boolean, {\n description:\n 'Deletes a user from the system by their username. Use this mutation to permanently remove a user account and revoke their access.'\n })\n async deleteUser(\n @Arg('username', { description: 'The username of the user to delete.' }) username: string,\n @Ctx() context: ResolverContext\n ) {\n const { tx } = context.state\n\n await commonDeleteUser({ username }, tx)\n\n return true\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Boolean, {\n description:\n 'Deletes multiple users from the system by their usernames. Use this mutation to remove several user accounts at once.'\n })\n async deleteUsers(\n @Arg('usernames', type => [String], { description: 'An array of usernames to delete.' }) usernames: string[],\n @Ctx() context: ResolverContext\n ) {\n const { tx } = context.state\n await commonDeleteUsers({ usernames }, tx)\n\n return true\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Boolean, {\n description:\n 'Invites an existing user to join the current domain. Use this mutation to add a user to a domain if they already exist in the system.'\n })\n async inviteUser(\n @Arg('username', { description: 'The username or email of the user to invite.' }) username: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, tx } = context.state\n const userRepository = getRepository(User, tx)\n\n var invitee: User = await userRepository.findOne({\n where: { username },\n relations: ['domains']\n })\n\n if (!invitee && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(username)) {\n invitee = await userRepository.findOne({\n where: { email: ILike(username) },\n relations: ['domains']\n })\n }\n\n if (!invitee) {\n throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))\n }\n\n const existingDomains: Domain[] = invitee.domains\n if (existingDomains.find((d: Domain) => d.id === domain.id)) {\n throw new Error(context.t('error.x already exists in y', { x: context.t('field.user'), y: domain.name }))\n }\n\n invitee.domains = [...existingDomains, domain]\n await userRepository.save(invitee)\n\n return true\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Boolean, {\n description:\n \"Removes a user from the current domain. Use this mutation to revoke a user's access to a specific domain without deleting their account.\"\n })\n async deleteDomainUser(\n @Arg('username', { description: 'The username or email of the user to remove from the domain.' }) username: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { tx, domain } = context.state\n const userRepository = getRepository(User, tx)\n\n var user: User = await userRepository.findOne({\n where: { username },\n relations: ['domains', 'roles']\n })\n\n if (!user && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(username)) {\n user = await userRepository.findOne({\n where: { email: ILike(username) },\n relations: ['domains', 'roles']\n })\n }\n\n if (!user) {\n throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))\n }\n\n const targetDomainIdx: number = user.domains.findIndex((userDomain: Domain) => userDomain.id === domain.id)\n if (targetDomainIdx < 0) {\n throw new Error(context.t('error.x is not a member of y', { x: user.name, y: domain.name }))\n }\n\n // Remove domain relation with user\n user.domains.splice(targetDomainIdx, 1)\n\n // Remove domain's roles that user has\n user.roles = user.roles.filter((role: Role) => role.domainId !== domain.id)\n\n await userRepository.save(user)\n\n return true\n }\n\n @Directive('@privilege(domainOwnerGranted: true, superUserGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Boolean, {\n description:\n 'Transfers domain ownership to another user. Use this mutation to assign the owner role to a different user within the domain.'\n })\n async transferOwner(\n @Arg('username', { description: 'The username or email of the user to transfer ownership to.' }) username: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, tx, user: actor } = context.state\n const userRepository = getRepository(User, tx)\n\n var user: User = await userRepository.findOne({\n where: { username },\n relations: ['domains', 'roles']\n })\n\n if (!user && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(username)) {\n user = await userRepository.findOne({\n where: { email: ILike(username) },\n relations: ['domains', 'roles']\n })\n }\n\n if (!user) {\n throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))\n }\n\n if (user.status !== UserStatus.ACTIVATED) {\n throw new Error('Only activated users are eligible to receive admin privileges.')\n }\n\n if (user.domains.map((d: Domain) => d.id).indexOf(domain.id) < 0) {\n throw new Error(`User is not belongs to current domain`)\n }\n\n /* 역할은 부모 도메인으로부터 상속될 수 있으므로 부여된 상속 역할도 자격으로 인정한다. */\n const grantableRoleDomainIds: string[] = [domain.id, domain.parentId].filter(Boolean)\n if (user.roles.filter((r: Role) => grantableRoleDomainIds.includes(r.domainId)).length == 0) {\n throw new Error(`Only users with at least one role in this domain are eligible to receive admin privileges.`)\n }\n\n /* 대표 오너 컬럼과 `DomainOwner` 테이블을 함께 갱신한다 (기존 오너 엔트리는 유지). */\n await setPrimaryDomainOwner(domain, user.id, actor, tx)\n\n return true\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @UseMiddleware(SpeakRefusals)\n @Mutation(returns => Boolean, {\n description:\n 'Activates a user account in the current domain. Use this mutation to enable a user who was previously inactive.'\n })\n async activateUser(\n @Arg('username', { description: 'The username or email of the user to activate.' }) username: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { tx, domain } = context.state\n const userRepository = getRepository(User, tx)\n\n var targetUser: User = await userRepository.findOne({\n where: { username },\n relations: ['domains']\n })\n\n if (!targetUser && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(username)) {\n targetUser = await userRepository.findOne({\n where: { email: ILike(username) },\n relations: ['domains']\n })\n }\n\n if (!targetUser) {\n throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))\n }\n\n if (!targetUser?.domains?.find((userDomain: Domain) => userDomain.id === domain.id)) {\n throw new Error('User is not belong to domain')\n }\n\n /* Activating does not give a password - a waiting account opens only through its setup link (ADR-0161). */\n if (targetUser.status === UserStatus.PWD_RESET_REQUIRED) {\n throw new Refusal('password-setup-pending', {}, 'This account is waiting for its password. Issue a password setup link.')\n }\n\n targetUser.failCount = 0\n targetUser.status = UserStatus.ACTIVATED\n\n await userRepository.save(targetUser)\n\n return true\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Boolean, {\n description:\n 'Inactivates a user account in the current domain. Use this mutation to disable a user, making them unable to log in.'\n })\n async inactivateUser(\n @Arg('username', { description: 'The username or email of the user to inactivate.' }) username: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { tx, domain } = context.state\n const userRepository = getRepository(User, tx)\n\n var targetUser: User = await userRepository.findOne({\n where: { username },\n relations: ['domains']\n })\n\n if (!targetUser && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(username)) {\n targetUser = await userRepository.findOne({\n where: { email: ILike(username) },\n relations: ['domains']\n })\n }\n\n if (!targetUser) {\n throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))\n }\n\n if (!targetUser?.domains?.find((userDomain: Domain) => userDomain.id === domain.id)) {\n throw new Error('User is not belong to domain')\n }\n\n /* 공동 오너(`DomainOwner` 테이블)도 도메인 관리자이므로 같은 보호를 받는다. */\n if (targetUser.userType == 'admin' || (await isDomainOwner(domain, targetUser, tx))) {\n throw new Error('Admin deactivation not allowed')\n }\n\n targetUser.status = UserStatus.INACTIVE\n\n await userRepository.save(targetUser)\n\n return true\n }\n\n /**\n * The person sets their own password through a one-time link - an administrator never sets it (ADR-0161).\n *\n * For an account this domain made and one whose password it takes back alike. Who may be handed one from here is\n * `password-reset-rule.ts`: someone wholly of this domain, owning no domain.\n */\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @UseMiddleware(SpeakRefusals)\n @Mutation(returns => PasswordSetupLink, {\n description:\n \"Puts the user waiting for a password they set themselves and issues the one-time link to it. The current password stops working and open sessions end. Mailed, or returned once for the administrator to hand over.\"\n })\n async issuePasswordSetupLink(\n @Arg('username', { description: 'The username or email of the user.' }) username: string,\n @Arg('mail', { description: \"True mails the link to the user's address; false returns it once.\" }) mail: boolean,\n @Ctx() context: ResolverContext\n ): Promise<PasswordSetupLink> {\n const { tx, domain } = context.state\n const userRepository = getRepository(User, tx)\n\n var targetUser: User = await userRepository.findOne({\n where: { username },\n relations: ['domains']\n })\n\n if (!targetUser && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(username)) {\n targetUser = await userRepository.findOne({\n where: { email: ILike(username) },\n relations: ['domains']\n })\n }\n\n if (!targetUser) {\n throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))\n }\n\n if (!targetUser?.domains?.find((userDomain: Domain) => userDomain.id === domain.id)) {\n throw new Error('User is not belong to domain')\n }\n\n const refusal = await passwordResetRefusal(targetUser, domain, tx)\n if (refusal) {\n throw refusal\n }\n\n return await issuePasswordSetupLink({ user: targetUser, mail, context, tx })\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @UseMiddleware(SpeakRefusals)\n @Mutation(returns => User, {\n description:\n \"Updates the roles assigned to a user. Use this mutation to change a user's permissions within the domain.\"\n })\n async updateUserRoles(\n @Arg('username', { description: 'The username or email of the user whose roles to update.' }) username: string,\n @Arg('availableRoles', type => [ObjectRef], { description: 'The list of roles that can be assigned to the user.' })\n availableRoles: ObjectRef[],\n @Arg('selectedRoles', type => [ObjectRef], { description: 'The list of roles to be assigned to the user.' })\n selectedRoles: ObjectRef[],\n @Ctx() context: ResolverContext\n ) {\n const { domain, tx } = context.state\n const userRepository = getRepository(User, tx)\n\n var user: User = await userRepository.findOne({\n where: { username },\n relations: ['domains', 'roles']\n })\n\n if (!user && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(username)) {\n user = await userRepository.findOne({\n where: { email: ILike(username) },\n relations: ['domains', 'roles']\n })\n }\n\n if (!user) {\n throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))\n }\n\n if (user.domains.map((d: Domain) => d.id).indexOf(domain.id) < 0) {\n throw new Error(`User is not belongs to current domain`)\n }\n\n /* Found again in this domain's scope - the ids are the client's (utils/assignable-roles.ts, ADR-0103 decision 2). */\n const { user: saved } = await assignRoles(\n user,\n { add: selectedRoles.map(role => role.id), remove: availableRoles.map(role => role.id) },\n domain,\n tx,\n context.state.user\n )\n\n return saved\n }\n}\n"]}
@@ -7,8 +7,9 @@ export declare class UserQuery {
7
7
  user(email: string, context: ResolverContext): Promise<User>;
8
8
  users(params: ListParam, context: ResolverContext): Promise<UserList>;
9
9
  checkUserBelongsDomain(context: ResolverContext): Promise<Boolean>;
10
- checkResettablePasswordToDefault(context: ResolverContext): Promise<Boolean>;
11
- checkDefaultPassword(context: ResolverContext): Promise<Boolean>;
10
+ /** The user screen offers a password setup link only where `issuePasswordSetupLink` would not refuse (`password-reset-rule.ts`). */
11
+ mayIssuePasswordSetupLink(id: string, context: ResolverContext): Promise<boolean>;
12
+ /** Asked only by the add-user popup, before inviteUser / createUser - so it is gated as they are. */
12
13
  checkUserExistence(email: string): Promise<Boolean>;
13
14
  username(user: User): Promise<string>;
14
15
  domains(user: User): Promise<import("@things-factory/shell").Domain[]>;
@@ -11,6 +11,7 @@ const assignable_roles_js_1 = require("../../utils/assignable-roles.js");
11
11
  const check_user_belongs_domain_js_1 = require("../../utils/check-user-belongs-domain.js");
12
12
  const domain_ownership_js_1 = require("../../utils/domain-ownership.js");
13
13
  const get_domain_users_js_1 = require("../../utils/get-domain-users.js");
14
+ const password_reset_rule_js_1 = require("../../utils/password-reset-rule.js");
14
15
  const role_js_1 = require("../role/role.js");
15
16
  const user_js_1 = require("./user.js");
16
17
  const user_types_js_1 = require("./user-types.js");
@@ -70,14 +71,16 @@ let UserQuery = class UserQuery {
70
71
  throw new Error(`Failed to get current user information.`);
71
72
  }
72
73
  }
73
- async checkResettablePasswordToDefault(context) {
74
- const { defaultPassword } = env_1.config.get('password');
75
- return Boolean(defaultPassword);
76
- }
77
- async checkDefaultPassword(context) {
78
- const { defaultPassword } = env_1.config.get('password');
79
- return Boolean(defaultPassword);
74
+ /** The user screen offers a password setup link only where `issuePasswordSetupLink` would not refuse (`password-reset-rule.ts`). */
75
+ async mayIssuePasswordSetupLink(id, context) {
76
+ const { domain } = context.state;
77
+ const target = await (0, shell_1.getRepository)(user_js_1.User).findOne({ where: { id }, relations: ['domains'] });
78
+ if (!target?.domains?.find(userDomain => userDomain.id === domain.id)) {
79
+ return false;
80
+ }
81
+ return !(await (0, password_reset_rule_js_1.passwordResetRefusal)(target, domain));
80
82
  }
83
+ /** Asked only by the add-user popup, before inviteUser / createUser - so it is gated as they are. */
81
84
  async checkUserExistence(email) {
82
85
  return Boolean(await (0, shell_1.getRepository)(user_js_1.User).count({ where: { email: (0, typeorm_1.ILike)(email) } }));
83
86
  }
@@ -158,25 +161,18 @@ tslib_1.__decorate([
158
161
  tslib_1.__metadata("design:returntype", Promise)
159
162
  ], UserQuery.prototype, "checkUserBelongsDomain", null);
160
163
  tslib_1.__decorate([
164
+ (0, type_graphql_1.Directive)('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)'),
161
165
  (0, type_graphql_1.Query)(returns => Boolean, {
162
- description: 'Determines whether the system provides a default password when creating a new user.'
163
- }),
164
- tslib_1.__param(0, (0, type_graphql_1.Ctx)()),
165
- tslib_1.__metadata("design:type", Function),
166
- tslib_1.__metadata("design:paramtypes", [Object]),
167
- tslib_1.__metadata("design:returntype", Promise)
168
- ], UserQuery.prototype, "checkResettablePasswordToDefault", null);
169
- tslib_1.__decorate([
170
- (0, type_graphql_1.Query)(returns => Boolean, {
171
- description: 'Checks if the system is configured to provide a default password for new users.'
166
+ description: "Whether this domain may issue the user a password setup link: the user works in no other domain, owns no domain and is not an administrator."
172
167
  }),
173
- tslib_1.__param(0, (0, type_graphql_1.Ctx)()),
168
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('id', { description: 'The id of the user who would be issued the link.' })),
169
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
174
170
  tslib_1.__metadata("design:type", Function),
175
- tslib_1.__metadata("design:paramtypes", [Object]),
171
+ tslib_1.__metadata("design:paramtypes", [String, Object]),
176
172
  tslib_1.__metadata("design:returntype", Promise)
177
- ], UserQuery.prototype, "checkDefaultPassword", null);
173
+ ], UserQuery.prototype, "mayIssuePasswordSetupLink", null);
178
174
  tslib_1.__decorate([
179
- (0, type_graphql_1.Directive)('@privilege(category: "user", privilege: "query")'),
175
+ (0, type_graphql_1.Directive)('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)'),
180
176
  (0, type_graphql_1.Query)(returns => Boolean, {
181
177
  description: 'Checks if a user with the given email address exists in the system.'
182
178
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"user-query.js","sourceRoot":"","sources":["../../../server/service/user/user-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'\nimport { GraphQLEmailAddress } from 'graphql-scalars'\nimport { ILike, SelectQueryBuilder } from 'typeorm'\n\nimport { config } from '@things-factory/env'\nimport { getRepository, ListParam, getQueryBuilderFromListParams } from '@things-factory/shell'\n\nimport { whereAssignableBy } from '../../utils/assignable-roles.js'\nimport { checkUserBelongsDomain } from '../../utils/check-user-belongs-domain.js'\nimport { findDomainOwnerUserIds } from '../../utils/domain-ownership.js'\nimport { buildDomainUsersQueryBuilder } from '../../utils/get-domain-users.js'\nimport { Role } from '../role/role.js'\nimport { User } from './user.js'\nimport { PasswordRule, UserList } from './user-types.js'\n\nconst passwordRule = config.get('password') || {\n lowerCase: true,\n upperCase: true,\n digit: true,\n specialCharacter: true,\n allowRepeat: false,\n useTightPattern: true,\n useLoosePattern: false,\n tightCharacterLength: 8,\n looseCharacterLength: 15\n}\n\n@Resolver(User)\nexport class UserQuery {\n @Query(returns => PasswordRule, {\n description:\n 'Retrieves the current password rule configuration for the system, such as required character types and minimum length.'\n })\n passwordRule(@Ctx() context: ResolverContext): PasswordRule {\n return passwordRule\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => User, {\n description: 'Fetches a user by their email address within the current domain.'\n })\n async user(\n @Arg('email', type => GraphQLEmailAddress, { description: 'The email address of the user to fetch.' })\n email: string,\n @Ctx() context: ResolverContext\n ): Promise<User> {\n const { domain } = context.state\n\n const qb: SelectQueryBuilder<User> = buildDomainUsersQueryBuilder(domain.id, 'USER')\n qb.andWhere(`LOWER(USER.email) = :email`, { email: email.toLowerCase().trim() })\n\n return qb.getOne()\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => UserList, {\n description: 'Fetches a list of users based on provided search parameters within the current domain.'\n })\n async users(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<UserList> {\n const { domain } = context.state\n\n const qb = getQueryBuilderFromListParams({\n repository: getRepository(User),\n params,\n alias: 'USER',\n searchables: ['name', 'email', 'description']\n })\n\n qb.select().andWhere(qb => {\n const subQuery = qb\n .subQuery()\n .select('USERS_DOMAINS.users_id')\n .from('users_domains', 'USERS_DOMAINS')\n .where('USERS_DOMAINS.domains_id = :domainId', { domainId: domain.id })\n .getQuery()\n\n return 'USER.id IN ' + subQuery\n })\n\n const [items, total] = await qb.getManyAndCount()\n\n /* 오너는 여러 명일 수 있다 — 대표 오너 컬럼만 보면 공동 오너가 일반 사용자로 표시된다. */\n const ownerIds: Set<string> = await findDomainOwnerUserIds(domain)\n\n const foundUsers: User[] = items.map((item: User) => {\n item.owner = ownerIds.has(item.id)\n return item\n })\n\n return { items: foundUsers, total }\n }\n\n @Query(returns => Boolean, {\n description: 'Checks if the current authenticated user belongs to the current domain.'\n })\n async checkUserBelongsDomain(@Ctx() context: ResolverContext): Promise<Boolean> {\n const { user, domain } = context.state\n\n if (user) {\n return await checkUserBelongsDomain(domain, user)\n } else {\n throw new Error(`Failed to get current user information.`)\n }\n }\n\n @Query(returns => Boolean, {\n description: 'Determines whether the system provides a default password when creating a new user.'\n })\n async checkResettablePasswordToDefault(@Ctx() context: ResolverContext): Promise<Boolean> {\n const { defaultPassword } = config.get('password')\n\n return Boolean(defaultPassword)\n }\n\n @Query(returns => Boolean, {\n description: 'Checks if the system is configured to provide a default password for new users.'\n })\n async checkDefaultPassword(@Ctx() context: ResolverContext): Promise<Boolean> {\n const { defaultPassword } = config.get('password')\n\n return Boolean(defaultPassword)\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"query\")')\n @Query(returns => Boolean, {\n description: 'Checks if a user with the given email address exists in the system.'\n })\n async checkUserExistence(\n @Arg('email', type => GraphQLEmailAddress, { description: 'The email address to check for existence.' })\n email: string\n ): Promise<Boolean> {\n return Boolean(await getRepository(User).count({ where: { email: ILike(email) } }))\n }\n\n @FieldResolver({ description: 'Returns the username of the user, or their email if username is not set.' })\n async username(@Root() user: User) {\n return user.username || user.email\n }\n\n @FieldResolver({ description: 'Returns the list of domains the user belongs to.' })\n async domains(@Root() user: User) {\n return (\n await getRepository(User).findOne({\n where: { id: user.id },\n relations: ['domains']\n })\n ).domains\n }\n\n /**\n * 이 도메인에서 본 역할 — 이 도메인이 부여할 수 있는 범위 안의 것만.\n *\n * 범위는 셋이다: 내 도메인의 역할, 부모 1단의 역할(`userRoles` · `myRoles` 와 같다),\n * 파트너가 이 도메인에 grant 한 역할(`grantedRoles`). 사용자 상세(`user-detail`)가 부여할\n * 수 있다고 내놓는 목록이 정확히 이 셋이고, 체크 상태를 이 필드로 채운다. 셋째를 빼면\n * 파트너 역할이 체크 안 된 채 그려지고, 저장하면 **떼어진다**.\n *\n * 예전에는 사용자가 가진 역할을 **전부** 돌려줬다. 도메인 A 와 B 에 함께 속한 사람을\n * A 의 사용자 목록으로 읽으면 B 의 역할 이름이 보였다(`role-query.ts` 의 ③ 과 같은 결함).\n */\n @FieldResolver({\n description: 'Returns the roles the user holds that the current domain can assign: its own, its parent domain\\'s, and roles granted to it by partners.'\n })\n async roles(@Root() user: User, @Ctx() context: ResolverContext): Promise<Role[]> {\n const { domain } = context.state\n\n const qb = getRepository(Role)\n .createQueryBuilder('ROLE')\n .innerJoin('ROLE.users', 'USER', 'USER.id = :userId', { userId: user.id })\n\n /* The same scope the roles are assigned in (utils/assignable-roles.ts) - what is shown is what can be saved. */\n return await whereAssignableBy(qb, 'ROLE', domain).getMany()\n }\n\n @FieldResolver({ description: 'Returns the user who last updated this user record.' })\n async updater(@Root() user: User): Promise<User> {\n return await getRepository(User).findOneBy({ id: user.updaterId })\n }\n\n @FieldResolver({ description: 'Returns the user who originally created this user record.' })\n async creator(@Root() user: User): Promise<User> {\n return await getRepository(User).findOneBy({ id: user.creatorId })\n }\n}\n"]}
1
+ {"version":3,"file":"user-query.js","sourceRoot":"","sources":["../../../server/service/user/user-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'\nimport { GraphQLEmailAddress } from 'graphql-scalars'\nimport { ILike, SelectQueryBuilder } from 'typeorm'\n\nimport { config } from '@things-factory/env'\nimport { getRepository, ListParam, getQueryBuilderFromListParams } from '@things-factory/shell'\n\nimport { whereAssignableBy } from '../../utils/assignable-roles.js'\nimport { checkUserBelongsDomain } from '../../utils/check-user-belongs-domain.js'\nimport { findDomainOwnerUserIds } from '../../utils/domain-ownership.js'\nimport { buildDomainUsersQueryBuilder } from '../../utils/get-domain-users.js'\nimport { passwordResetRefusal } from '../../utils/password-reset-rule.js'\nimport { Role } from '../role/role.js'\nimport { User } from './user.js'\nimport { PasswordRule, UserList } from './user-types.js'\n\nconst passwordRule = config.get('password') || {\n lowerCase: true,\n upperCase: true,\n digit: true,\n specialCharacter: true,\n allowRepeat: false,\n useTightPattern: true,\n useLoosePattern: false,\n tightCharacterLength: 8,\n looseCharacterLength: 15\n}\n\n@Resolver(User)\nexport class UserQuery {\n @Query(returns => PasswordRule, {\n description:\n 'Retrieves the current password rule configuration for the system, such as required character types and minimum length.'\n })\n passwordRule(@Ctx() context: ResolverContext): PasswordRule {\n return passwordRule\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => User, {\n description: 'Fetches a user by their email address within the current domain.'\n })\n async user(\n @Arg('email', type => GraphQLEmailAddress, { description: 'The email address of the user to fetch.' })\n email: string,\n @Ctx() context: ResolverContext\n ): Promise<User> {\n const { domain } = context.state\n\n const qb: SelectQueryBuilder<User> = buildDomainUsersQueryBuilder(domain.id, 'USER')\n qb.andWhere(`LOWER(USER.email) = :email`, { email: email.toLowerCase().trim() })\n\n return qb.getOne()\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => UserList, {\n description: 'Fetches a list of users based on provided search parameters within the current domain.'\n })\n async users(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<UserList> {\n const { domain } = context.state\n\n const qb = getQueryBuilderFromListParams({\n repository: getRepository(User),\n params,\n alias: 'USER',\n searchables: ['name', 'email', 'description']\n })\n\n qb.select().andWhere(qb => {\n const subQuery = qb\n .subQuery()\n .select('USERS_DOMAINS.users_id')\n .from('users_domains', 'USERS_DOMAINS')\n .where('USERS_DOMAINS.domains_id = :domainId', { domainId: domain.id })\n .getQuery()\n\n return 'USER.id IN ' + subQuery\n })\n\n const [items, total] = await qb.getManyAndCount()\n\n /* 오너는 여러 명일 수 있다 — 대표 오너 컬럼만 보면 공동 오너가 일반 사용자로 표시된다. */\n const ownerIds: Set<string> = await findDomainOwnerUserIds(domain)\n\n const foundUsers: User[] = items.map((item: User) => {\n item.owner = ownerIds.has(item.id)\n return item\n })\n\n return { items: foundUsers, total }\n }\n\n @Query(returns => Boolean, {\n description: 'Checks if the current authenticated user belongs to the current domain.'\n })\n async checkUserBelongsDomain(@Ctx() context: ResolverContext): Promise<Boolean> {\n const { user, domain } = context.state\n\n if (user) {\n return await checkUserBelongsDomain(domain, user)\n } else {\n throw new Error(`Failed to get current user information.`)\n }\n }\n\n /** The user screen offers a password setup link only where `issuePasswordSetupLink` would not refuse (`password-reset-rule.ts`). */\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Query(returns => Boolean, {\n description:\n \"Whether this domain may issue the user a password setup link: the user works in no other domain, owns no domain and is not an administrator.\"\n })\n async mayIssuePasswordSetupLink(\n @Arg('id', { description: 'The id of the user who would be issued the link.' }) id: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain } = context.state\n\n const target: User = await getRepository(User).findOne({ where: { id }, relations: ['domains'] })\n if (!target?.domains?.find(userDomain => userDomain.id === domain.id)) {\n return false\n }\n\n return !(await passwordResetRefusal(target, domain))\n }\n\n /** Asked only by the add-user popup, before inviteUser / createUser - so it is gated as they are. */\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Query(returns => Boolean, {\n description: 'Checks if a user with the given email address exists in the system.'\n })\n async checkUserExistence(\n @Arg('email', type => GraphQLEmailAddress, { description: 'The email address to check for existence.' })\n email: string\n ): Promise<Boolean> {\n return Boolean(await getRepository(User).count({ where: { email: ILike(email) } }))\n }\n\n @FieldResolver({ description: 'Returns the username of the user, or their email if username is not set.' })\n async username(@Root() user: User) {\n return user.username || user.email\n }\n\n @FieldResolver({ description: 'Returns the list of domains the user belongs to.' })\n async domains(@Root() user: User) {\n return (\n await getRepository(User).findOne({\n where: { id: user.id },\n relations: ['domains']\n })\n ).domains\n }\n\n /**\n * 이 도메인에서 본 역할 — 이 도메인이 부여할 수 있는 범위 안의 것만.\n *\n * 범위는 셋이다: 내 도메인의 역할, 부모 1단의 역할(`userRoles` · `myRoles` 와 같다),\n * 파트너가 이 도메인에 grant 한 역할(`grantedRoles`). 사용자 상세(`user-detail`)가 부여할\n * 수 있다고 내놓는 목록이 정확히 이 셋이고, 체크 상태를 이 필드로 채운다. 셋째를 빼면\n * 파트너 역할이 체크 안 된 채 그려지고, 저장하면 **떼어진다**.\n *\n * 예전에는 사용자가 가진 역할을 **전부** 돌려줬다. 도메인 A 와 B 에 함께 속한 사람을\n * A 의 사용자 목록으로 읽으면 B 의 역할 이름이 보였다(`role-query.ts` 의 ③ 과 같은 결함).\n */\n @FieldResolver({\n description: 'Returns the roles the user holds that the current domain can assign: its own, its parent domain\\'s, and roles granted to it by partners.'\n })\n async roles(@Root() user: User, @Ctx() context: ResolverContext): Promise<Role[]> {\n const { domain } = context.state\n\n const qb = getRepository(Role)\n .createQueryBuilder('ROLE')\n .innerJoin('ROLE.users', 'USER', 'USER.id = :userId', { userId: user.id })\n\n /* The same scope the roles are assigned in (utils/assignable-roles.ts) - what is shown is what can be saved. */\n return await whereAssignableBy(qb, 'ROLE', domain).getMany()\n }\n\n @FieldResolver({ description: 'Returns the user who last updated this user record.' })\n async updater(@Root() user: User): Promise<User> {\n return await getRepository(User).findOneBy({ id: user.updaterId })\n }\n\n @FieldResolver({ description: 'Returns the user who originally created this user record.' })\n async creator(@Root() user: User): Promise<User> {\n return await getRepository(User).findOneBy({ id: user.creatorId })\n }\n}\n"]}
@@ -16,7 +16,6 @@ export declare class NewUser {
16
16
  name: string;
17
17
  description?: string;
18
18
  email: string;
19
- password?: string;
20
19
  userType?: string;
21
20
  roles?: ObjectRef[];
22
21
  }
@@ -26,12 +25,17 @@ export declare class UserPatch {
26
25
  domains?: [ObjectRef];
27
26
  description?: string;
28
27
  email?: string;
29
- password?: string;
30
28
  status?: string;
31
29
  roles?: ObjectRef[];
32
30
  userType?: string;
33
31
  cuFlag?: string;
34
32
  }
33
+ /** What issuing a password setup link answers (ADR-0161). The link is here only when it was not mailed - and only now. */
34
+ export declare class PasswordSetupLink {
35
+ link?: string;
36
+ mailedTo?: string;
37
+ expiresAt: Date;
38
+ }
35
39
  export declare class UserList {
36
40
  items: User[];
37
41
  total: number;