@things-factory/auth-base 8.0.0-alpha.29 โ†’ 8.0.0-alpha.36

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 (85) hide show
  1. package/dist-client/tsconfig.tsbuildinfo +1 -1
  2. package/dist-server/constants/error-code.d.ts +2 -0
  3. package/dist-server/constants/error-code.js +3 -1
  4. package/dist-server/constants/error-code.js.map +1 -1
  5. package/dist-server/controllers/change-pwd.js +2 -2
  6. package/dist-server/controllers/change-pwd.js.map +1 -1
  7. package/dist-server/controllers/delete-user.js +13 -12
  8. package/dist-server/controllers/delete-user.js.map +1 -1
  9. package/dist-server/controllers/invitation.d.ts +2 -1
  10. package/dist-server/controllers/invitation.js +30 -5
  11. package/dist-server/controllers/invitation.js.map +1 -1
  12. package/dist-server/controllers/profile.d.ts +4 -3
  13. package/dist-server/controllers/profile.js +20 -2
  14. package/dist-server/controllers/profile.js.map +1 -1
  15. package/dist-server/controllers/signin.d.ts +4 -1
  16. package/dist-server/controllers/signin.js +17 -1
  17. package/dist-server/controllers/signin.js.map +1 -1
  18. package/dist-server/controllers/signup.js +13 -4
  19. package/dist-server/controllers/signup.js.map +1 -1
  20. package/dist-server/controllers/unlock-user.js +1 -0
  21. package/dist-server/controllers/unlock-user.js.map +1 -1
  22. package/dist-server/controllers/verification.js +1 -0
  23. package/dist-server/controllers/verification.js.map +1 -1
  24. package/dist-server/middlewares/signin-middleware.js +3 -3
  25. package/dist-server/middlewares/signin-middleware.js.map +1 -1
  26. package/dist-server/migrations/1548206416130-SeedUser.js +2 -1
  27. package/dist-server/migrations/1548206416130-SeedUser.js.map +1 -1
  28. package/dist-server/router/auth-checkin-router.js +8 -2
  29. package/dist-server/router/auth-checkin-router.js.map +1 -1
  30. package/dist-server/router/auth-private-process-router.js +12 -7
  31. package/dist-server/router/auth-private-process-router.js.map +1 -1
  32. package/dist-server/router/auth-public-process-router.js +20 -9
  33. package/dist-server/router/auth-public-process-router.js.map +1 -1
  34. package/dist-server/router/auth-signin-router.js +3 -3
  35. package/dist-server/router/auth-signin-router.js.map +1 -1
  36. package/dist-server/service/invitation/invitation-mutation.d.ts +3 -2
  37. package/dist-server/service/invitation/invitation-mutation.js +20 -8
  38. package/dist-server/service/invitation/invitation-mutation.js.map +1 -1
  39. package/dist-server/service/user/user-mutation.d.ts +10 -9
  40. package/dist-server/service/user/user-mutation.js +112 -54
  41. package/dist-server/service/user/user-mutation.js.map +1 -1
  42. package/dist-server/service/user/user-types.d.ts +1 -0
  43. package/dist-server/service/user/user-types.js +4 -0
  44. package/dist-server/service/user/user-types.js.map +1 -1
  45. package/dist-server/service/user/user.d.ts +1 -0
  46. package/dist-server/service/user/user.js +40 -14
  47. package/dist-server/service/user/user.js.map +1 -1
  48. package/dist-server/templates/account-unlock-email.d.ts +2 -1
  49. package/dist-server/templates/account-unlock-email.js +1 -1
  50. package/dist-server/templates/account-unlock-email.js.map +1 -1
  51. package/dist-server/templates/invitation-email.d.ts +2 -1
  52. package/dist-server/templates/invitation-email.js +1 -1
  53. package/dist-server/templates/invitation-email.js.map +1 -1
  54. package/dist-server/templates/verification-email.d.ts +2 -1
  55. package/dist-server/templates/verification-email.js +1 -1
  56. package/dist-server/templates/verification-email.js.map +1 -1
  57. package/dist-server/tsconfig.tsbuildinfo +1 -1
  58. package/package.json +2 -2
  59. package/server/constants/error-code.ts +2 -0
  60. package/server/controllers/change-pwd.ts +3 -2
  61. package/server/controllers/delete-user.ts +16 -13
  62. package/server/controllers/invitation.ts +36 -5
  63. package/server/controllers/profile.ts +29 -2
  64. package/server/controllers/signin.ts +21 -2
  65. package/server/controllers/signup.ts +16 -4
  66. package/server/controllers/unlock-user.ts +1 -0
  67. package/server/controllers/verification.ts +1 -0
  68. package/server/middlewares/signin-middleware.ts +3 -3
  69. package/server/migrations/1548206416130-SeedUser.ts +2 -1
  70. package/server/router/auth-checkin-router.ts +11 -5
  71. package/server/router/auth-private-process-router.ts +14 -7
  72. package/server/router/auth-public-process-router.ts +22 -10
  73. package/server/router/auth-signin-router.ts +3 -3
  74. package/server/service/invitation/invitation-mutation.ts +24 -9
  75. package/server/service/user/user-mutation.ts +123 -54
  76. package/server/service/user/user-types.ts +3 -0
  77. package/server/service/user/user.ts +41 -14
  78. package/server/templates/account-unlock-email.ts +1 -1
  79. package/server/templates/invitation-email.ts +1 -1
  80. package/server/templates/verification-email.ts +1 -1
  81. package/translations/en.json +5 -1
  82. package/translations/ja.json +5 -1
  83. package/translations/ko.json +6 -3
  84. package/translations/ms.json +5 -1
  85. package/translations/zh.json +5 -1
@@ -10,6 +10,7 @@ import { buildDomainUsersQueryBuilder } from '../../utils/get-domain-users'
10
10
  import { Role } from '../role/role'
11
11
  import { User, UserStatus } from './user'
12
12
  import { NewUser, UserPatch } from './user-types'
13
+ import { USERNAME_ALREADY_EXISTS, EMAIL_ALREADY_EXISTS } from '../../constants/error-code'
13
14
 
14
15
  @Resolver(User)
15
16
  export class UserMutation {
@@ -19,17 +20,27 @@ export class UserMutation {
19
20
  async createUser(@Arg('user') user: NewUser, @Ctx() context: ResolverContext) {
20
21
  const { domain, tx } = context.state
21
22
  const { defaultPassword } = config.get('password')
22
- const { email } = user
23
+ const { username, email } = user
24
+ const userRepository = getRepository(User, tx)
23
25
 
26
+ user.username = username.trim()
24
27
  user.email = email.trim()
25
28
 
26
- const oldUser: User = await getRepository(User, tx).findOne({ where: { email: ILike(user.email) } })
27
- if (oldUser) {
28
- throw new Error(context.t('error.x already exists in y', { x: context.t('field.user'), y: 'operato' }))
29
+ if (await userRepository.findOne({ where: { username: user.username } })) {
30
+ throw new Error(context.t(USERNAME_ALREADY_EXISTS))
31
+ }
32
+
33
+ if (await userRepository.findOne({ where: { email: ILike(user.email) } })) {
34
+ throw new Error(context.t(EMAIL_ALREADY_EXISTS))
29
35
  }
30
36
 
31
37
  if (!user.password && !defaultPassword) {
32
- throw new Error(context.t('error.initial password or default password should be supported'))
38
+ throw new Error('initial password or default password should be supported.')
39
+ }
40
+
41
+ // TODO username์€ ๋‹ค์Œ ํŒจํ„ด์„ ๋”ฐ๋ผ์•ผ ํ•œ๋‹ค. pattern="^[A-Za-z0-9]*$"
42
+ if (!/^[A-Za-z0-9]*$/.test(user.username)) {
43
+ throw new Error(context.t('error.invalid x', { x: context.t('field.username') }))
33
44
  }
34
45
 
35
46
  // consider if validation password rule is required
@@ -38,7 +49,7 @@ export class UserMutation {
38
49
 
39
50
  const salt = User.generateSalt()
40
51
 
41
- return await getRepository(User, tx).save({
52
+ return await userRepository.save({
42
53
  creator: context.state.user,
43
54
  updater: context.state.user,
44
55
  ...user,
@@ -185,10 +196,10 @@ export class UserMutation {
185
196
  @Directive('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)')
186
197
  @Directive('@transaction')
187
198
  @Mutation(returns => Boolean, { description: 'To delete a user' })
188
- async deleteUser(@Arg('email', type => GraphQLEmailAddress) email: string, @Ctx() context: ResolverContext) {
199
+ async deleteUser(@Arg('username') username: string, @Ctx() context: ResolverContext) {
189
200
  const { tx } = context.state
190
201
 
191
- await commonDeleteUser({ email }, tx)
202
+ await commonDeleteUser({ username }, tx)
192
203
 
193
204
  return true
194
205
  }
@@ -196,25 +207,31 @@ export class UserMutation {
196
207
  @Directive('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)')
197
208
  @Directive('@transaction')
198
209
  @Mutation(returns => Boolean, { description: 'To delete some users' })
199
- async deleteUsers(@Arg('emails', type => [String]) emails: string[], @Ctx() context: ResolverContext) {
210
+ async deleteUsers(@Arg('usernames', type => [String]) usernames: string[], @Ctx() context: ResolverContext) {
200
211
  const { tx } = context.state
201
- await commonDeleteUsers({ emails }, tx)
212
+ await commonDeleteUsers({ usernames }, tx)
202
213
 
203
214
  return true
204
215
  }
205
216
 
206
217
  @Directive('@transaction')
207
218
  @Mutation(returns => Boolean, { description: 'To invite new user' })
208
- async inviteUser(
209
- @Arg('email', type => GraphQLEmailAddress) email: string,
210
- @Ctx() context: ResolverContext
211
- ): Promise<boolean> {
219
+ async inviteUser(@Arg('username') username: string, @Ctx() context: ResolverContext): Promise<boolean> {
212
220
  const { domain, tx } = context.state
213
- const invitee: User = await getRepository(User, tx).findOne({
214
- where: { email: ILike(email) },
221
+ const userRepository = getRepository(User, tx)
222
+
223
+ var invitee: User = await userRepository.findOne({
224
+ where: { username },
215
225
  relations: ['domains']
216
226
  })
217
227
 
228
+ if (!invitee && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(username)) {
229
+ invitee = await userRepository.findOne({
230
+ where: { email: ILike(username) },
231
+ relations: ['domains']
232
+ })
233
+ }
234
+
218
235
  if (!invitee) {
219
236
  throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))
220
237
  }
@@ -223,8 +240,9 @@ export class UserMutation {
223
240
  if (existingDomains.find((d: Domain) => d.id === domain.id)) {
224
241
  throw new Error(context.t('error.x already exists in y', { x: context.t('field.user'), y: domain.name }))
225
242
  }
243
+
226
244
  invitee.domains = [...existingDomains, domain]
227
- await getRepository(User, tx).save(invitee)
245
+ await userRepository.save(invitee)
228
246
 
229
247
  return true
230
248
  }
@@ -232,16 +250,22 @@ export class UserMutation {
232
250
  @Directive('@transaction')
233
251
  @Directive('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)')
234
252
  @Mutation(returns => Boolean, { description: 'To delete domain user' })
235
- async deleteDomainUser(
236
- @Arg('email', type => GraphQLEmailAddress) email: string,
237
- @Ctx() context: ResolverContext
238
- ): Promise<boolean> {
253
+ async deleteDomainUser(@Arg('username') username: string, @Ctx() context: ResolverContext): Promise<boolean> {
239
254
  const { tx, domain } = context.state
255
+ const userRepository = getRepository(User, tx)
240
256
 
241
- let user: User = await getRepository(User, tx).findOne({
242
- where: { email: ILike(email) },
243
- relations: ['domains', 'roles', 'roles.domain']
257
+ var user: User = await userRepository.findOne({
258
+ where: { username },
259
+ relations: ['domains', 'roles']
244
260
  })
261
+
262
+ if (!user && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(username)) {
263
+ user = await userRepository.findOne({
264
+ where: { email: ILike(username) },
265
+ relations: ['domains', 'roles']
266
+ })
267
+ }
268
+
245
269
  if (!user) {
246
270
  throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))
247
271
  }
@@ -255,9 +279,9 @@ export class UserMutation {
255
279
  user.domains.splice(targetDomainIdx, 1)
256
280
 
257
281
  // Remove domain's roles that user has
258
- user.roles = user.roles.filter((role: Role) => role.domain.id !== domain.id)
282
+ user.roles = user.roles.filter((role: Role) => role.domainId !== domain.id)
259
283
 
260
- await getRepository(User, tx).save(user)
284
+ await userRepository.save(user)
261
285
 
262
286
  return true
263
287
  }
@@ -265,18 +289,24 @@ export class UserMutation {
265
289
  @Directive('@privilege(domainOwnerGranted: true, superUserGranted: true)')
266
290
  @Directive('@transaction')
267
291
  @Mutation(returns => Boolean, { description: 'To transfer owner of domain' })
268
- async transferOwner(
269
- @Arg('email', type => GraphQLEmailAddress) email: string,
270
- @Ctx() context: ResolverContext
271
- ): Promise<boolean> {
292
+ async transferOwner(@Arg('username') username: string, @Ctx() context: ResolverContext): Promise<boolean> {
272
293
  const { domain, tx } = context.state
273
- const user: User = await getRepository(User, tx).findOne({
274
- where: { email: ILike(email) },
275
- relations: ['domains', 'roles']
294
+ const userRepository = getRepository(User, tx)
295
+
296
+ var user: User = await userRepository.findOne({
297
+ where: { username },
298
+ relations: ['domains']
276
299
  })
277
300
 
301
+ if (!user && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(username)) {
302
+ user = await userRepository.findOne({
303
+ where: { email: ILike(username) },
304
+ relations: ['domains']
305
+ })
306
+ }
307
+
278
308
  if (!user) {
279
- throw new Error('Failed to find user')
309
+ throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))
280
310
  }
281
311
 
282
312
  if (user.status !== UserStatus.ACTIVATED) {
@@ -300,15 +330,24 @@ export class UserMutation {
300
330
  @Directive('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)')
301
331
  @Directive('@transaction')
302
332
  @Mutation(returns => Boolean, { description: 'To activate user' })
303
- async activateUser(@Arg('userId') userId: string, @Ctx() context: ResolverContext): Promise<boolean> {
333
+ async activateUser(@Arg('username') username: string, @Ctx() context: ResolverContext): Promise<boolean> {
304
334
  const { tx, domain } = context.state
335
+ const userRepository = getRepository(User, tx)
305
336
 
306
- const targetUser: User = await getRepository(User, tx).findOne({
307
- where: { id: userId },
337
+ var targetUser: User = await userRepository.findOne({
338
+ where: { username },
308
339
  relations: ['domains']
309
340
  })
341
+
342
+ if (!targetUser && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(username)) {
343
+ targetUser = await userRepository.findOne({
344
+ where: { email: ILike(username) },
345
+ relations: ['domains']
346
+ })
347
+ }
348
+
310
349
  if (!targetUser) {
311
- throw new Error('No user found')
350
+ throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))
312
351
  }
313
352
 
314
353
  if (!targetUser?.domains?.find((userDomain: Domain) => userDomain.id === domain.id)) {
@@ -318,7 +357,7 @@ export class UserMutation {
318
357
  targetUser.failCount = 0
319
358
  targetUser.status = UserStatus.ACTIVATED
320
359
 
321
- await getRepository(User, tx).save(targetUser)
360
+ await userRepository.save(targetUser)
322
361
 
323
362
  return true
324
363
  }
@@ -326,15 +365,24 @@ export class UserMutation {
326
365
  @Directive('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)')
327
366
  @Directive('@transaction')
328
367
  @Mutation(returns => Boolean, { description: 'To inactivate user' })
329
- async inactivateUser(@Arg('userId') userId: string, @Ctx() context: ResolverContext): Promise<boolean> {
368
+ async inactivateUser(@Arg('username') username: string, @Ctx() context: ResolverContext): Promise<boolean> {
330
369
  const { tx, domain } = context.state
370
+ const userRepository = getRepository(User, tx)
331
371
 
332
- const targetUser: User = await getRepository(User, tx).findOne({
333
- where: { id: userId },
372
+ var targetUser: User = await userRepository.findOne({
373
+ where: { username },
334
374
  relations: ['domains']
335
375
  })
376
+
377
+ if (!targetUser && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(username)) {
378
+ targetUser = await userRepository.findOne({
379
+ where: { email: ILike(username) },
380
+ relations: ['domains']
381
+ })
382
+ }
383
+
336
384
  if (!targetUser) {
337
- throw new Error('No user found')
385
+ throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))
338
386
  }
339
387
 
340
388
  if (!targetUser?.domains?.find((userDomain: Domain) => userDomain.id === domain.id)) {
@@ -347,7 +395,7 @@ export class UserMutation {
347
395
 
348
396
  targetUser.status = UserStatus.INACTIVE
349
397
 
350
- await getRepository(User, tx).save(targetUser)
398
+ await userRepository.save(targetUser)
351
399
 
352
400
  return true
353
401
  }
@@ -355,7 +403,7 @@ export class UserMutation {
355
403
  @Directive('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)')
356
404
  @Directive('@transaction')
357
405
  @Mutation(returns => Boolean, { description: 'To reset password to default' })
358
- async resetPasswordToDefault(@Arg('userId') userId: string, @Ctx() context: ResolverContext): Promise<boolean> {
406
+ async resetPasswordToDefault(@Arg('username') username: string, @Ctx() context: ResolverContext): Promise<boolean> {
359
407
  const { tx, domain } = context.state
360
408
 
361
409
  const { defaultPassword } = config.get('password')
@@ -363,12 +411,22 @@ export class UserMutation {
363
411
  throw new Error('No default password found')
364
412
  }
365
413
 
366
- const targetUser: User = await getRepository(User, tx).findOne({
367
- where: { id: userId },
414
+ const userRepository = getRepository(User, tx)
415
+
416
+ var targetUser: User = await userRepository.findOne({
417
+ where: { username },
368
418
  relations: ['domains']
369
419
  })
420
+
421
+ if (!targetUser && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(username)) {
422
+ targetUser = await userRepository.findOne({
423
+ where: { email: ILike(username) },
424
+ relations: ['domains']
425
+ })
426
+ }
427
+
370
428
  if (!targetUser) {
371
- throw new Error('No user found')
429
+ throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))
372
430
  }
373
431
 
374
432
  if (!targetUser?.domains?.find((userDomain: Domain) => userDomain.id === domain.id)) {
@@ -377,7 +435,8 @@ export class UserMutation {
377
435
 
378
436
  targetUser.salt = User.generateSalt()
379
437
  targetUser.password = User.encode(defaultPassword, targetUser.salt)
380
- await getRepository(User, tx).save(targetUser)
438
+
439
+ await userRepository.save(targetUser)
381
440
 
382
441
  return true
383
442
  }
@@ -386,18 +445,28 @@ export class UserMutation {
386
445
  @Directive('@transaction')
387
446
  @Mutation(returns => User, { description: 'To update roles for a user' })
388
447
  async updateUserRoles(
389
- @Arg('userId') userId: string,
448
+ @Arg('username') username: string,
390
449
  @Arg('availableRoles', type => [ObjectRef]) availableRoles: ObjectRef[],
391
450
  @Arg('selectedRoles', type => [ObjectRef]) selectedRoles: ObjectRef[],
392
451
  @Ctx() context: ResolverContext
393
452
  ) {
394
453
  const { domain, tx } = context.state
395
- let user: User = await getRepository(User, tx).findOne({
396
- where: { id: userId },
454
+ const userRepository = getRepository(User, tx)
455
+
456
+ var user: User = await userRepository.findOne({
457
+ where: { username },
397
458
  relations: ['domains', 'roles']
398
459
  })
460
+
461
+ if (!user && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(username)) {
462
+ user = await userRepository.findOne({
463
+ where: { email: ILike(username) },
464
+ relations: ['domains', 'roles']
465
+ })
466
+ }
467
+
399
468
  if (!user) {
400
- throw new Error('Failed to find user')
469
+ throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))
401
470
  }
402
471
 
403
472
  if (user.domains.map((d: Domain) => d.id).indexOf(domain.id) < 0) {
@@ -408,6 +477,6 @@ export class UserMutation {
408
477
  user.roles = user.roles.filter((r: Role) => availableRoleIds.indexOf(r.id) < 0)
409
478
  user.roles = user.roles.concat(selectedRoles as Role[])
410
479
 
411
- return await getRepository(User, tx).save(user)
480
+ return await userRepository.save(user)
412
481
  }
413
482
  }
@@ -35,6 +35,9 @@ export class PasswordRule {
35
35
 
36
36
  @InputType()
37
37
  export class NewUser {
38
+ @Field()
39
+ username: string
40
+
38
41
  @Field()
39
42
  name: string
40
43
 
@@ -6,6 +6,7 @@ import {
6
6
  Column,
7
7
  CreateDateColumn,
8
8
  Entity,
9
+ ILike,
9
10
  Index,
10
11
  JoinTable,
11
12
  ManyToMany,
@@ -43,13 +44,23 @@ export enum UserStatus {
43
44
  }
44
45
 
45
46
  @Entity()
46
- @Index('ix_user_0', (user: User) => [user.email], { unique: true })
47
+ @Index('ix_user_0', (user: User) => [user.email], {
48
+ unique: true
49
+ })
50
+ @Index('ix_user_1', (user: User) => [user.username], {
51
+ unique: true,
52
+ where: '"username" IS NOT NULL'
53
+ })
47
54
  @ObjectType()
48
55
  export class User {
49
56
  @PrimaryGeneratedColumn('uuid')
50
57
  @Field(type => ID)
51
58
  readonly id: string
52
59
 
60
+ @Column({ nullable: true })
61
+ @Field({ nullable: true })
62
+ username: string
63
+
53
64
  @Column()
54
65
  @Field({ nullable: true })
55
66
  name: string
@@ -165,15 +176,10 @@ export class User {
165
176
 
166
177
  /* signing for jsonwebtoken */
167
178
  async sign(options?) {
168
- var { expiresIn = sessionExpirySeconds, subdomain } = options || {}
179
+ var { expiresIn = sessionExpirySeconds } = options || {}
169
180
 
170
181
  var user = {
171
- id: this.id,
172
- userType: this.userType,
173
- status: this.status,
174
- domain: {
175
- subdomain
176
- }
182
+ username: this.username || this.email
177
183
  }
178
184
 
179
185
  return await jwt.sign(user, SECRET, {
@@ -262,18 +268,39 @@ export class User {
262
268
  }
263
269
 
264
270
  static async checkAuth(decoded) {
265
- if (decoded?.id === undefined) {
271
+ // id ๋Š” ํ•˜์œ„ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด ๋‹จ๊ธฐ์ ์œผ๋กœ ์œ ์ง€ํ•จ
272
+ const { id, username } = decoded || {}
273
+
274
+ if (!id && !username) {
266
275
  throw new AuthError({
267
276
  errorCode: AuthError.ERROR_CODES.USER_NOT_FOUND
268
277
  })
269
278
  }
270
279
 
271
280
  const repository = getRepository(User)
272
- var user = await repository.findOne({
273
- where: { id: decoded.id },
274
- relations: ['domains', 'credentials'],
275
- cache: true
276
- })
281
+ if (id) {
282
+ var user = await repository.findOne({
283
+ where: { id },
284
+ relations: ['domains', 'credentials'],
285
+ cache: true
286
+ })
287
+ } else {
288
+ var user = await repository.findOne({
289
+ where: { username },
290
+ relations: ['domains', 'credentials'],
291
+ cache: true
292
+ })
293
+
294
+ if (!user && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(username)) {
295
+ user = await repository.findOne({
296
+ where: {
297
+ email: ILike(username)
298
+ },
299
+ relations: ['domains', 'credentials'],
300
+ cache: true
301
+ })
302
+ }
303
+ }
277
304
 
278
305
  if (!user)
279
306
  throw new AuthError({
@@ -1,4 +1,4 @@
1
- export function getUnlockUserEmailForm({ name, resetUrl }) {
1
+ export function getUnlockUserEmailForm({ username, name, resetUrl }) {
2
2
  return `
3
3
  <html lang="en">
4
4
  <head>
@@ -1,4 +1,4 @@
1
- export function getInvitationEmailForm({ email, acceptUrl }) {
1
+ export function getInvitationEmailForm({ username, email, acceptUrl }) {
2
2
  return `
3
3
  <html lang="en">
4
4
  <head>
@@ -1,4 +1,4 @@
1
- export function getVerificationEmailForm({ name, verifyUrl }) {
1
+ export function getVerificationEmailForm({ username, name, verifyUrl }) {
2
2
  return `
3
3
  <html lang="en">
4
4
  <head>
@@ -4,6 +4,7 @@
4
4
  "error.confirm password not matched": "new password and confirm password is not matched",
5
5
  "error.domain mismatch": "certificate is not for this domain",
6
6
  "error.domain not allowed": "user not allowed domain `{subdomain}`",
7
+ "error.email already exists": "email already used by another user",
7
8
  "error.failed to find x": "failed to find {x}",
8
9
  "error.password should be supported": "initial password or default password should be supported",
9
10
  "error.password should match the rule": "password should match following rule. ${rule}",
@@ -11,13 +12,15 @@
11
12
  "error.subdomain not found": "domain not found",
12
13
  "error.token or password is invalid": "token or password is invalid",
13
14
  "error.unavailable-domain": "unavailable domain",
15
+ "error.user credential not found": "user credential not found. You need to register device to use biometric authentication.",
14
16
  "error.user credential registeration failed": "user credential registration failed. It may be an already registered credential.",
15
17
  "error.user credential registration not allowed": "user credential registration failed. The registration timed out or was not allowed.",
16
- "error.user duplicated": "user duplicated",
18
+ "error.user duplicated.": "there is a user account using same email or user ID.",
17
19
  "error.user not activated": "user is not activated",
18
20
  "error.user not found": "user not found",
19
21
  "error.user or verification token not found": "user or verification token not found",
20
22
  "error.user validation failed": "user validation failed",
23
+ "error.username already exists": "username already used by another user",
21
24
  "error.x is not a member of y": "{x} is not a member of {y}",
22
25
  "field.active": "active",
23
26
  "field.appliance_id": "appliance id",
@@ -56,6 +59,7 @@
56
59
  "text.signout successfully": "signout successfully",
57
60
  "text.user activated successfully": "user activated successfully",
58
61
  "text.user credential registered successfully": "device registration has been successfully completed. You can now use biometric authentication.",
62
+ "text.user inactivated successfully": "user inactivated successfully",
59
63
  "text.user registered successfully": "user registered successfully. find your email to activate account",
60
64
  "text.verification email sent": "verification email sent"
61
65
  }
@@ -4,6 +4,7 @@
4
4
  "error.confirm password not matched": "ๆ–ฐใ—ใ„ใƒ‘ใ‚นใƒฏใƒผใƒ‰ใจ็ขบ่ชใƒ‘ใ‚นใƒฏใƒผใƒ‰ใŒไธ€่‡ดใ—ใพใ›ใ‚“.",
5
5
  "error.domain mismatch": "่จผๆ˜Žๆ›ธใฎใƒ‰ใƒกใ‚คใƒณใจ็พๅœจใฎใƒ‰ใƒกใ‚คใƒณใŒไธ€่‡ดใ—ใพใ›ใ‚“.",
6
6
  "error.domain not allowed": "'{subdomain}' ้ ˜ๅŸŸใฏใ“ใฎใƒฆใƒผใ‚ถใซ่จฑๅฏใ•ใ‚Œใฆใ„ใพใ›ใ‚“.",
7
+ "error.email already exists": "ใƒกใƒผใƒซใฏใ™ใงใซไป–ใฎใƒฆใƒผใ‚ถใƒผใซใ‚ˆใฃใฆไฝฟ็”จใ•ใ‚Œใฆใ„ใพใ™.",
7
8
  "error.failed to find x": "{x}ใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“.",
8
9
  "error.password should be supported": "ๅˆๆœŸใƒ‘ใ‚นใƒฏใƒผใƒ‰ใพใŸใฏใƒ‡ใƒ•ใ‚ฉใƒซใƒˆใƒ‘ใ‚นใƒฏใƒผใƒ‰ใŒใ‚ตใƒใƒผใƒˆใ•ใ‚Œใ‚‹ในใใงใ™",
9
10
  "error.password should match the rule": "ใƒ‘ใ‚นใƒฏใƒผใƒ‰ใฏๆฌกใฎ่ฆๅ‰‡ใ‚’ๅฎˆใ‚‰ใชใ‘ใ‚Œใฐใชใ‚Šใพใ›ใ‚“. {rule}",
@@ -11,13 +12,15 @@
11
12
  "error.subdomain not found": "ใ‚ตใƒ–ใƒ‰ใƒกใ‚คใƒณใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“.",
12
13
  "error.token or password is invalid": "ใƒˆใƒผใ‚ฏใƒณใพใŸใฏใƒ‘ใ‚นใƒฏใƒผใƒ‰ใŒ็„กๅŠนใงใ™.",
13
14
  "error.unavailable-domain": "ไฝฟ็”จใงใใชใ„ใƒ‰ใƒกใ‚คใƒณใงใ™.",
15
+ "error.user credential not found": "ใƒฆใƒผใ‚ถใƒผ่ณ‡ๆ ผๆƒ…ๅ ฑใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“. ็”Ÿไฝ“่ช่จผใ‚’ไฝฟ็”จใ™ใ‚‹ใซใฏใƒ‡ใƒใ‚คใ‚นใ‚’็™ป้Œฒใ™ใ‚‹ๅฟ…่ฆใŒใ‚ใ‚Šใพใ™.",
14
16
  "error.user credential registeration failed": "ใƒฆใƒผใ‚ถใƒผ่ณ‡ๆ ผๆƒ…ๅ ฑใฎ็™ป้Œฒใซๅคฑๆ•—ใ—ใพใ—ใŸใ€‚ๆ—ขใซ็™ป้Œฒใ•ใ‚Œใฆใ„ใ‚‹่ณ‡ๆ ผๆƒ…ๅ ฑใฎๅฏ่ƒฝๆ€งใŒใ‚ใ‚Šใพใ™ใ€‚",
15
17
  "error.user credential registration not allowed": "ใƒฆใƒผใ‚ถใƒผ่ณ‡ๆ ผๆƒ…ๅ ฑใฎ็™ป้Œฒใซๅคฑๆ•—ใ—ใพใ—ใŸใ€‚็™ป้Œฒใฎใ‚ฟใ‚คใƒ ใ‚ขใ‚ฆใƒˆใพใŸใฏ็™ป้ŒฒใŒ่จฑๅฏใ•ใ‚Œใฆใ„ใพใ›ใ‚“ใ€‚",
16
- "error.user duplicated": "ๅŒใ˜ใƒกใƒผใƒซใง็™ป้Œฒใ•ใ‚ŒใŸใ‚ขใ‚ซใ‚ฆใƒณใƒˆใŒๅญ˜ๅœจใ—ใพใ™.",
18
+ "error.user duplicated.": "ใƒฆใƒผใ‚ถใƒผใŒ้‡่ค‡ใ—ใฆใ„ใพใ™.",
17
19
  "error.user not activated": "ใƒฆใƒผใ‚ถใƒผใŒใ‚ขใ‚ฏใƒ†ใ‚ฃใƒ–ๅŒ–ใ•ใ‚Œใฆใ„ใพใ›ใ‚“.",
18
20
  "error.user not found": "ใƒฆใƒผใ‚ถใƒผใŒๅญ˜ๅœจใ—ใพใ›ใ‚“.",
19
21
  "error.user or verification token not found": "ใƒฆใƒผใ‚ถใƒผใพใŸใฏ็ขบ่ชใƒˆใƒผใ‚ฏใƒณใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“.",
20
22
  "error.user validation failed": "ใƒฆใƒผใ‚ถใƒผ็ขบ่ชใซๅคฑๆ•—ใ—ใพใ—ใŸ.",
23
+ "error.username already exists": "ใƒฆใƒผใ‚ถใƒผๅใฏใ™ใงใซไป–ใฎใƒฆใƒผใ‚ถใƒผใซใ‚ˆใฃใฆไฝฟ็”จใ•ใ‚Œใฆใ„ใพใ™.",
21
24
  "error.x is not a member of y": "{x}ใฏ{y}ใฎใƒกใƒณใƒใƒผใงใฏใ‚ใ‚Šใพใ›ใ‚“.",
22
25
  "field.active": "ใ‚ขใ‚ฏใƒ†ใ‚ฃใƒ–",
23
26
  "field.appliance_id": "ๅ™จๅ…ทID",
@@ -56,6 +59,7 @@
56
59
  "text.signout successfully": "ใƒญใ‚ฐใ‚ขใ‚ฆใƒˆใซๆˆๅŠŸใ—ใพใ—ใŸ.",
57
60
  "text.user activated successfully": "ใƒฆใƒผใ‚ถใƒผใŒๆญฃๅธธใซๆดปๆ€งๅŒ–ใ•ใ‚Œใพใ—ใŸ.",
58
61
  "text.user credential registered successfully": "ใƒ‡ใƒใ‚คใ‚นใฎ็™ป้ŒฒใŒๆญฃๅธธใซๅฎŒไบ†ใ—ใพใ—ใŸใ€‚ไปŠๅพŒใฏ็”Ÿไฝ“่ช่จผใ‚’ไฝฟ็”จใงใใพใ™ใ€‚",
62
+ "text.user inactivated successfully": "ใƒฆใƒผใ‚ถใƒผใŒๆญฃๅธธใซ้žใ‚ขใ‚ฏใƒ†ใ‚ฃใƒ–ๅŒ–ใ•ใ‚Œใพใ—ใŸ.",
59
63
  "text.user registered successfully": "ใƒฆใƒผใ‚ถใƒผใŒๆญฃๅธธใซ็™ป้Œฒใ•ใ‚Œใพใ—ใŸ. ็ขบ่ชใƒกใƒผใƒซใงใ‚ขใ‚ซใ‚ฆใƒณใƒˆใ‚’ๆœ‰ๅŠนใซใ—ใฆใใ ใ•ใ„.",
60
64
  "text.verification email sent": "็ขบ่ชใƒกใƒผใƒซใ‚’้€ใ‚Šใพใ—ใŸ."
61
65
  }
@@ -4,6 +4,7 @@
4
4
  "error.confirm password not matched": "์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ์™€ ํ™•์ธ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.",
5
5
  "error.domain mismatch": "์ธ์ฆ์„œ์˜ ๋„๋ฉ”์ธ๊ณผ ํ˜„์žฌ ๋„๋ฉ”์ธ์ด ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.",
6
6
  "error.domain not allowed": "'{subdomain}' ์˜์—ญ์€ ์ด ์‚ฌ์šฉ์ž์—๊ฒŒ ํ—ˆ๊ฐ€๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.",
7
+ "error.email already exists": "์ด๋ฉ”์ผ์ด ์ด๋ฏธ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.",
7
8
  "error.failed to find x": "{x}์„(๋ฅผ) ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.",
8
9
  "error.password should be supported": "์ดˆ๊ธฐ ๋น„๋ฐ€๋ฒˆํ˜ธ๋‚˜ ๋””ํดํŠธ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ œ๊ณต๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.",
9
10
  "error.password should match the rule": "๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๋‹ค์Œ ๊ทœ์น™์„ ์ง€์ผœ์•ผ ํ•ฉ๋‹ˆ๋‹ค. {rule}",
@@ -12,13 +13,14 @@
12
13
  "error.token or password is invalid": "ํ† ํฐ ๋˜๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.",
13
14
  "error.unavailable-domain": "์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๋„๋ฉ”์ธ์ž…๋‹ˆ๋‹ค.",
14
15
  "error.user credential not found": "์‚ฌ์šฉ์ž ์ž๊ฒฉ ์ฆ๋ช…์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ฐ”์ด์˜ค๋ฉ”ํŠธ๋ฆญ ์ธ์ฆ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋จผ์ € ๊ธฐ๊ธฐ๋ฅผ ๋“ฑ๋กํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.",
15
- "error.user duplicated": "๋™์ผํ•œ ์ด๋ฉ”์ผ๋กœ ๊ฐ€์ž…๋œ ๊ณ„์ •์ด ์ด๋ฏธ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.",
16
+ "error.user credential registeration failed": "์‚ฌ์šฉ์ž ์ธ์ฆ์„œ ๋“ฑ๋ก์ด ์‹คํŒจํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ด๋ฏธ ๋“ฑ๋ก๋œ ์ธ์ฆ์„œ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.",
17
+ "error.user credential registration not allowed": "์‚ฌ์šฉ์ž ์ธ์ฆ์„œ ๋“ฑ๋ก์ด ์‹คํŒจํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๋“ฑ๋ก ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋˜์—ˆ๊ฑฐ๋‚˜ ๋“ฑ๋ก์ด ํ—ˆ์šฉ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.",
18
+ "error.user duplicated": "๋™์ผํ•œ ์ด๋ฉ”์ผ์ด๋‚˜ ์‚ฌ์šฉ์ž์•„์ด๋””๋กœ ๊ฐ€์ž…๋œ ๊ณ„์ •์ด ์ด๋ฏธ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.",
16
19
  "error.user not activated": "์‚ฌ์šฉ์ž๊ฐ€ ํ™œ์„ฑํ™”๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.",
17
20
  "error.user not found": "์‚ฌ์šฉ์ž๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.",
18
21
  "error.user or verification token not found": "์‚ฌ์šฉ์ž ๋˜๋Š” ํ™•์ธํ† ํฐ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.",
19
- "error.user credential registeration failed": "์‚ฌ์šฉ์ž ์ธ์ฆ์„œ ๋“ฑ๋ก์ด ์‹คํŒจํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ด๋ฏธ ๋“ฑ๋ก๋œ ์ธ์ฆ์„œ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.",
20
- "error.user credential registration not allowed": "์‚ฌ์šฉ์ž ์ธ์ฆ์„œ ๋“ฑ๋ก์ด ์‹คํŒจํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๋“ฑ๋ก ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋˜์—ˆ๊ฑฐ๋‚˜ ๋“ฑ๋ก์ด ํ—ˆ์šฉ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.",
21
22
  "error.user validation failed": "์‚ฌ์šฉ์ž ํ™•์ธ์— ์‹คํŒจํ•˜์˜€์Šต๋‹ˆ๋‹ค.",
23
+ "error.username already exists": "์‚ฌ์šฉ์ž ์•„์ด๋””๊ฐ€ ์ด๋ฏธ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.",
22
24
  "error.x is not a member of y": "{x}์€(๋Š”) {y}์˜ ๋ฉค๋ฒ„๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.",
23
25
  "field.active": "ํ™œ์„ฑํ™”",
24
26
  "field.appliance_id": "๊ธฐ๊ตฌ ์•„์ด๋””",
@@ -57,6 +59,7 @@
57
59
  "text.signout successfully": "์„ฑ๊ณต์ ์œผ๋กœ ๋กœ๊ทธ์•„์›ƒ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.",
58
60
  "text.user activated successfully": "์‚ฌ์šฉ์ž๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ํ™œ์„ฑํ™”๋˜์—ˆ์Šต๋‹ˆ๋‹ค.",
59
61
  "text.user credential registered successfully": "๊ธฐ๊ธฐ ๋“ฑ๋ก์ด ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ๋ฐ”์ด์˜ค๋ฉ”ํŠธ๋ฆญ ์ธ์ฆ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.",
62
+ "text.user inactivated successfully": "์‚ฌ์šฉ์ž๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋น„ํ™œ์„ฑํ™”๋˜์—ˆ์Šต๋‹ˆ๋‹ค.",
60
63
  "text.user registered successfully": "์‚ฌ์šฉ์ž๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋“ฑ๋ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ™•์ธ ์ด๋ฉ”์ผ์„ ํ†ตํ•ด์„œ ๊ณ„์ •์„ ํ™œ์„ฑํ™”ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.",
61
64
  "text.verification email sent": "ํ™•์ธ ์ด๋ฉ”์ผ์„ ๋ณด๋ƒˆ์Šต๋‹ˆ๋‹ค."
62
65
  }
@@ -4,6 +4,7 @@
4
4
  "error.confirm password not matched": "Kata laluan baru dan pengesahan kata laluan tidak sepadan",
5
5
  "error.domain mismatch": "Sijil tidak sesuai untuk domain ini",
6
6
  "error.domain not allowed": "Pengguna tidak dibenarkan domain `{subdomain}`",
7
+ "error.email already exists": "Emel telah digunakan oleh pengguna lain",
7
8
  "error.failed to find x": "Gagal mencari {x}",
8
9
  "error.password should be supported": "kata laluan awal atau kata laluan lalai harus disokong",
9
10
  "error.password should match the rule": "Kata laluan harus mematuhi peraturan berikut. ${rule}",
@@ -11,13 +12,15 @@
11
12
  "error.subdomain not found": "Domain tidak ditemui",
12
13
  "error.token or password is invalid": "Token atau kata laluan tidak sah",
13
14
  "error.unavailable-domain": "Domain tidak tersedia",
15
+ "error.user credential not found": "kelayakan pengguna tidak ditemui. Anda perlu mendaftarkan peranti untuk menggunakan pengesahan biometrik.",
14
16
  "error.user credential registeration failed": "pendaftaran kelayakan pengguna gagal. Mungkin kelayakan tersebut sudah didaftarkan.",
15
17
  "error.user credential registration not allowed": "pendaftaran kelayakan pengguna gagal. Masa pendaftaran telah tamat atau pendaftaran tidak dibenarkan.",
16
- "error.user duplicated": "Emel telah digunakan oleh akaun lain",
18
+ "error.user duplicated": "terdapat akaun pengguna yang menggunakan e-mel atau ID pengguna yang sama.",
17
19
  "error.user not activated": "Pengguna tidak diaktifkan",
18
20
  "error.user not found": "Pengguna tidak ditemui",
19
21
  "error.user or verification token not found": "Pengguna atau token pengesahan tidak ditemui",
20
22
  "error.user validation failed": "Validasi pengguna gagal",
23
+ "error.username already exists": "Nama pengguna telah digunakan oleh pengguna lain",
21
24
  "error.x is not a member of y": "{x} bukan ahli {y}",
22
25
  "field.active": "Aktif",
23
26
  "field.appliance_id": "Perkakas",
@@ -56,6 +59,7 @@
56
59
  "text.signout successfully": "Berjaya keluar",
57
60
  "text.user activated successfully": "Pengguna diaktifkan dengan berjaya",
58
61
  "text.user credential registered successfully": "pendaftaran peranti berjaya diselesaikan. Kini anda boleh menggunakan pengesahan biometrik.",
62
+ "text.user inactivated successfully": "Pengguna tidak aktif dengan berjaya",
59
63
  "text.user registered successfully": "Pengguna berjaya didaftarkan. Cari e-mel anda untuk mengaktifkan akaun",
60
64
  "text.verification email sent": "E-mel pengesahan telah dihantar"
61
65
  }
@@ -5,6 +5,7 @@
5
5
  "error.confirm password not matched": "ๆ–ฐๅฏ†็ ไธŽ็กฎ่ฎคๅฏ†็ ไธๅŒน้…๏ผ",
6
6
  "error.domain mismatch": "่ฏไนฆไธ้€‚็”จไบŽ่ฏฅๅŸŸ๏ผ",
7
7
  "error.domain not allowed": "็”จๆˆทๆ— ๆƒ้™ไฝฟ็”จ`{subdomain}`ๅŸŸ๏ผ",
8
+ "error.email already exists": "็”ตๅญ้‚ฎไปถๅทฒ่ขซๅ…ถไป–็”จๆˆทไฝฟ็”จ๏ผ",
8
9
  "error.failed to find x": "ๆŸฅ่ฏข{x}ๅคฑ่ดฅ๏ผ",
9
10
  "error.password should be supported": "ๅบ”ๆ”ฏๆŒๅˆๅง‹ๅฏ†็ ๆˆ–้ป˜่ฎคๅฏ†็ ",
10
11
  "error.password should match the rule": "ๅฏ†็ ๅบ”็ฌฆๅˆไปฅไธ‹่ง„ๅˆ™ใ€‚${rule}",
@@ -12,13 +13,15 @@
12
13
  "error.subdomain not found": "็”จๆˆทๅŸŸๆŸฅ่ฏขๅคฑ่ดฅ๏ผ",
13
14
  "error.token or password is invalid": "ไปค็‰Œๆˆ–ๅฏ†็ ๆ— ๆ•ˆ๏ผ",
14
15
  "error.unavailable-domain": "ไธๅฏ็”จ็š„ๅŸŸๅ",
16
+ "error.user credential not found": "็”จๆˆทๅ‡ญ่ฏๆœชๆ‰พๅˆฐใ€‚ๆ‚จ้œ€่ฆๆณจๅ†Œ่ฎพๅค‡ไปฅไฝฟ็”จ็”Ÿ็‰ฉ่ฏ†ๅˆซ่ฎค่ฏใ€‚",
15
17
  "error.user credential registeration failed": "็”จๆˆทๅ‡ญ่ฏๆณจๅ†Œๅคฑ่ดฅใ€‚ๅฏ่ƒฝๆ˜ฏๅทฒๆณจๅ†Œ็š„ๅ‡ญ่ฏใ€‚",
16
18
  "error.user credential registration not allowed": "็”จๆˆทๅ‡ญ่ฏๆณจๅ†Œๅคฑ่ดฅใ€‚ๆณจๅ†Œ่ถ…ๆ—ถๆˆ–ๆณจๅ†Œไธ่ขซๅ…่ฎธใ€‚",
17
- "error.user duplicated": "ๆœ‰ไธ€ไธช็”จๆˆทๅธๆˆทไฝฟ็”จ็›ธๅŒ็š„็”ตๅญ้‚ฎไปถ",
19
+ "error.user duplicated": "ๅญ˜ๅœจไธ€ไธช็”จๆˆทๅธๆˆทไฝฟ็”จ็›ธๅŒ็š„็”ตๅญ้‚ฎไปถๆˆ–็”จๆˆทIDใ€‚",
18
20
  "error.user not activated": "็”จๆˆทๆœชๆฟ€ๆดป๏ผ",
19
21
  "error.user not found": "ๆ‰พไธๅˆฐ็”จๆˆท",
20
22
  "error.user or verification token not found": "ๆ‰พไธๅˆฐ็”จๆˆทๆˆ–้ชŒ่ฏไปค็‰Œใ€‚",
21
23
  "error.user validation failed": "็”จๆˆท้ชŒ่ฏๅคฑ่ดฅ๏ผ",
24
+ "error.username already exists": "็”จๆˆทๅๅทฒ่ขซๅ…ถไป–็”จๆˆทไฝฟ็”จ",
22
25
  "error.x is not a member of y": "{x}ไธๆ˜ฏ{y}็š„ๆˆๅ‘˜",
23
26
  "field.active": "ๆฟ€ๆดป",
24
27
  "field.appliance_id": "็ปˆ็ซฏๆœบID",
@@ -57,6 +60,7 @@
57
60
  "text.signout successfully": "็™ปๅ‡บๆˆๅŠŸใ€‚",
58
61
  "text.user activated successfully": "็”จๆˆทๆฟ€ๆดปๆˆๅŠŸ",
59
62
  "text.user credential registered successfully": "่ฎพๅค‡ๆณจๅ†ŒๅทฒๆˆๅŠŸๅฎŒๆˆใ€‚็Žฐๅœจๅฏไปฅไฝฟ็”จ็”Ÿ็‰ฉ่ฏ†ๅˆซ่ฎค่ฏใ€‚",
63
+ "text.user inactivated successfully": "็”จๆˆทๅทฒๆˆๅŠŸๅœ็”จ",
60
64
  "text.user registered successfully": "็”จๆˆทๆณจๅ†ŒๆˆๅŠŸใ€‚ ่ฏทๆŸฅ็œ‹็”ตๅญ้‚ฎไปถไปฅๆฟ€ๆดปๅธๆˆทใ€‚",
61
65
  "text.verification email sent": "้ชŒ่ฏ้‚ฎไปถๅทฒๅ‘้€"
62
66
  }