@things-factory/auth-base 10.0.0 → 10.0.4

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 (36) hide show
  1. package/dist-server/index.d.ts +3 -0
  2. package/dist-server/index.js +3 -0
  3. package/dist-server/index.js.map +1 -1
  4. package/dist-server/middlewares/domain-authenticate-middleware.js +26 -29
  5. package/dist-server/middlewares/domain-authenticate-middleware.js.map +1 -1
  6. package/dist-server/service/domain-generator/domain-generator-mutation.js +8 -4
  7. package/dist-server/service/domain-generator/domain-generator-mutation.js.map +1 -1
  8. package/dist-server/service/index.d.ts +1 -1
  9. package/dist-server/service/user/user-mutation.js +9 -5
  10. package/dist-server/service/user/user-mutation.js.map +1 -1
  11. package/dist-server/service/user/user-query.js +4 -1
  12. package/dist-server/service/user/user-query.js.map +1 -1
  13. package/dist-server/service/user/user.d.ts +12 -0
  14. package/dist-server/service/user/user.js +22 -9
  15. package/dist-server/service/user/user.js.map +1 -1
  16. package/dist-server/tsconfig.tsbuildinfo +1 -1
  17. package/dist-server/utils/can-user-checkin-domain.d.ts +15 -0
  18. package/dist-server/utils/can-user-checkin-domain.js +28 -0
  19. package/dist-server/utils/can-user-checkin-domain.js.map +1 -0
  20. package/dist-server/utils/checkin-domain-facts.d.ts +37 -0
  21. package/dist-server/utils/checkin-domain-facts.js +223 -0
  22. package/dist-server/utils/checkin-domain-facts.js.map +1 -0
  23. package/dist-server/utils/checkin-domain-rule.d.ts +72 -0
  24. package/dist-server/utils/checkin-domain-rule.js +76 -0
  25. package/dist-server/utils/checkin-domain-rule.js.map +1 -0
  26. package/dist-server/utils/domain-ownership.d.ts +36 -0
  27. package/dist-server/utils/domain-ownership.js +64 -0
  28. package/dist-server/utils/domain-ownership.js.map +1 -0
  29. package/dist-server/utils/get-user-domains.d.ts +16 -0
  30. package/dist-server/utils/get-user-domains.js +47 -89
  31. package/dist-server/utils/get-user-domains.js.map +1 -1
  32. package/package.json +4 -4
  33. package/spec/unit/checkin-domain.spec.ts +307 -0
  34. package/spec/unit/checkin-privilege.spec.ts +205 -0
  35. package/spec/unit/domain-ownership.spec.ts +188 -0
  36. package/tests/checkin-domain-rule.test.ts +128 -0
@@ -6,6 +6,9 @@ export * from './router/index.js';
6
6
  export * from './routes.js';
7
7
  export * from './utils/get-domain-users.js';
8
8
  export * from './utils/get-user-domains.js';
9
+ export * from './utils/checkin-domain-rule.js';
10
+ export * from './utils/can-user-checkin-domain.js';
11
+ export * from './utils/domain-ownership.js';
9
12
  export * from './utils/get-secret.js';
10
13
  export * from './utils/check-user-belongs-domain.js';
11
14
  export * from './utils/access-token-cookie.js';
@@ -11,6 +11,9 @@ tslib_1.__exportStar(require("./router/index.js"), exports);
11
11
  tslib_1.__exportStar(require("./routes.js"), exports);
12
12
  tslib_1.__exportStar(require("./utils/get-domain-users.js"), exports);
13
13
  tslib_1.__exportStar(require("./utils/get-user-domains.js"), exports);
14
+ tslib_1.__exportStar(require("./utils/checkin-domain-rule.js"), exports);
15
+ tslib_1.__exportStar(require("./utils/can-user-checkin-domain.js"), exports);
16
+ tslib_1.__exportStar(require("./utils/domain-ownership.js"), exports);
14
17
  tslib_1.__exportStar(require("./utils/get-secret.js"), exports);
15
18
  tslib_1.__exportStar(require("./utils/check-user-belongs-domain.js"), exports);
16
19
  tslib_1.__exportStar(require("./utils/access-token-cookie.js"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;AAAA,iDAAqD;AACrD,mEAA4D;AAE5D,uBAAoB;AAEpB,6DAAkC;AAClC,gEAAqC;AAErC,iEAAsC;AACtC,4DAAiC;AACjC,sDAA2B;AAE3B,sEAA2C;AAC3C,sEAA2C;AAC3C,gEAAqC;AACrC,+EAAoD;AACpD,yEAA8C;AAC9C,mEAAwC;AACxC,sEAA2C;AAC3C,yEAA8C;AAE9C,4DAAiC;AAEjC,qDAA0B;AAE1B,OAAO,CAAC,EAAE,CAAC,wBAA+B,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAO,EAAE,EAAE;IACjF,MAAM,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IACxC,MAAM,mBAAmB,GAAG,IAAA,qBAAa,EAAC,wBAAS,CAAC,CAAA;IAEpD,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,UAA8B,CAAC,EAAE,CAAC;QAC7E,IAAI,CAAC,IAAI,CAAC,MAAM,mBAAmB,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;YAC1E,MAAM,mBAAmB,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;QACpD,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,2EAA2E,CAAC,CAAA;AAC1F,CAAC,CAAC,CAAA","sourcesContent":["import { getRepository } from '@things-factory/shell'\nimport { Privilege } from './service/privilege/privilege.js'\n\nimport './routes.js'\n\nexport * from './service/index.js'\nexport * from './migrations/index.js'\n\nexport * from './middlewares/index.js'\nexport * from './router/index.js'\nexport * from './routes.js'\n\nexport * from './utils/get-domain-users.js'\nexport * from './utils/get-user-domains.js'\nexport * from './utils/get-secret.js'\nexport * from './utils/check-user-belongs-domain.js'\nexport * from './utils/access-token-cookie.js'\nexport * from './utils/encrypt-state.js'\nexport * from './utils/check-permission.js'\nexport * from './utils/check-user-has-role.js'\n\nexport * from './errors/index.js'\n\nexport * from './types.js'\n\nprocess.on('bootstrap-module-start' as any, async ({ app, config, client }: any) => {\n const privileges = process['PRIVILEGES']\n const privilegeRepository = getRepository(Privilege)\n\n for (const [category, name] of Object.values(privileges as [string, string])) {\n if (0 == (await privilegeRepository.count({ where: { category, name } }))) {\n await privilegeRepository.save({ category, name })\n }\n }\n\n console.log('[auth-base:bootstrap] Synchronization for privilege master has just done.')\n})\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;AAAA,iDAAqD;AACrD,mEAA4D;AAE5D,uBAAoB;AAEpB,6DAAkC;AAClC,gEAAqC;AAErC,iEAAsC;AACtC,4DAAiC;AACjC,sDAA2B;AAE3B,sEAA2C;AAC3C,sEAA2C;AAC3C,yEAA8C;AAC9C,6EAAkD;AAClD,sEAA2C;AAC3C,gEAAqC;AACrC,+EAAoD;AACpD,yEAA8C;AAC9C,mEAAwC;AACxC,sEAA2C;AAC3C,yEAA8C;AAE9C,4DAAiC;AAEjC,qDAA0B;AAE1B,OAAO,CAAC,EAAE,CAAC,wBAA+B,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAO,EAAE,EAAE;IACjF,MAAM,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IACxC,MAAM,mBAAmB,GAAG,IAAA,qBAAa,EAAC,wBAAS,CAAC,CAAA;IAEpD,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,UAA8B,CAAC,EAAE,CAAC;QAC7E,IAAI,CAAC,IAAI,CAAC,MAAM,mBAAmB,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;YAC1E,MAAM,mBAAmB,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;QACpD,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,2EAA2E,CAAC,CAAA;AAC1F,CAAC,CAAC,CAAA","sourcesContent":["import { getRepository } from '@things-factory/shell'\nimport { Privilege } from './service/privilege/privilege.js'\n\nimport './routes.js'\n\nexport * from './service/index.js'\nexport * from './migrations/index.js'\n\nexport * from './middlewares/index.js'\nexport * from './router/index.js'\nexport * from './routes.js'\n\nexport * from './utils/get-domain-users.js'\nexport * from './utils/get-user-domains.js'\nexport * from './utils/checkin-domain-rule.js'\nexport * from './utils/can-user-checkin-domain.js'\nexport * from './utils/domain-ownership.js'\nexport * from './utils/get-secret.js'\nexport * from './utils/check-user-belongs-domain.js'\nexport * from './utils/access-token-cookie.js'\nexport * from './utils/encrypt-state.js'\nexport * from './utils/check-permission.js'\nexport * from './utils/check-user-has-role.js'\n\nexport * from './errors/index.js'\n\nexport * from './types.js'\n\nprocess.on('bootstrap-module-start' as any, async ({ app, config, client }: any) => {\n const privileges = process['PRIVILEGES']\n const privilegeRepository = getRepository(Privilege)\n\n for (const [category, name] of Object.values(privileges as [string, string])) {\n if (0 == (await privilegeRepository.count({ where: { category, name } }))) {\n await privilegeRepository.save({ category, name })\n }\n }\n\n console.log('[auth-base:bootstrap] Synchronization for privilege master has just done.')\n})\n"]}
@@ -3,24 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.domainAuthenticateMiddleware = domainAuthenticateMiddleware;
4
4
  const shell_1 = require("@things-factory/shell");
5
5
  const auth_error_js_1 = require("../errors/auth-error.js");
6
- const domain_owner_js_1 = require("../service/domain-owner/domain-owner.js");
7
6
  const user_js_1 = require("../service/user/user.js");
8
- const get_user_domains_js_1 = require("../utils/get-user-domains.js");
7
+ const can_user_checkin_domain_js_1 = require("../utils/can-user-checkin-domain.js");
8
+ const domain_ownership_js_1 = require("../utils/domain-ownership.js");
9
9
  /**
10
- * 도메인 소유권 확인.
11
- *
12
- * 소유권은 두 가지 경로 중 하나로 인식된다:
13
- * 1) 하위 호환: `Domain.owner` 컬럼에 user.id 일치 (마이그레이션 이전 데이터
14
- * 또는 "대표 owner 표시용 캐시")
15
- * 2) `DomainOwner` 테이블에 (domainId, userId) 엔트리 존재 (정식 멀티 owner)
16
- *
17
- * 둘 중 하나라도 만족하면 owner로 인정 — 마이그레이션 기간/기존 API 호환을
18
- * 끊어뜨리지 않기 위함.
10
+ * 도메인 소유권 확인. 판정 규칙은 `isDomainOwner` 가 단일 소스이며
11
+ * (`Domain.owner` 캐시 컬럼 OR `DomainOwner` 테이블), 여기서는 요청 단위 메모이제이션만 더한다.
19
12
  */
20
13
  process.domainOwnerGranted = async (domain, user) => {
21
14
  if (!user || !domain)
22
15
  return false;
23
- // (1) 하위 호환: Domain.owner 캐시 필드
16
+ // 조회가 필요 없는 캐시 필드 경로는 메모이제이션 이전에 판정된다.
24
17
  if (domain.owner === user.id)
25
18
  return true;
26
19
  // Request-level 메모이제이션 — 한 요청 안에서 @privilege directive 가
@@ -31,17 +24,21 @@ process.domainOwnerGranted = async (domain, user) => {
31
24
  const cached = user[cacheKey];
32
25
  if (cached !== undefined)
33
26
  return cached;
34
- // (2) DomainOwner join table
35
- const exists = await (0, shell_1.getRepository)(domain_owner_js_1.DomainOwner)
36
- .createQueryBuilder('ow')
37
- .where('ow.domain_id = :domainId AND ow.user_id = :userId', {
38
- domainId: domain.id,
39
- userId: user.id
40
- })
41
- .getExists();
42
- user[cacheKey] = exists;
43
- return exists;
27
+ const owned = await (0, domain_ownership_js_1.isDomainOwner)(domain, user);
28
+ user[cacheKey] = owned;
29
+ return owned;
44
30
  };
31
+ /**
32
+ * 수퍼유저 확인 — 모든 도메인을 통과하는 전역 특권이므로 의도적으로 좁게 정의한다.
33
+ *
34
+ * SYSTEM 도메인에 소속되고, 그 도메인의 **대표 오너(`Domain.owner` 컬럼)** 인 한 사람만
35
+ * 수퍼유저다. SYSTEM 도메인의 공동 오너(`DomainOwner` 테이블)는 SYSTEM 도메인의 오너로서만
36
+ * 권한을 가지며 수퍼유저가 되지 않는다 — 그래서 여기서는 `isDomainOwner` 를 쓰지 않는다.
37
+ *
38
+ * 주의: `Domain.owner` 컬럼은 오너 제거 시 남은 공동 오너 중 가장 먼저 추가된 사람으로
39
+ * 자동 재설정된다(`removeDomainOwner`). SYSTEM 도메인에서는 그 재설정이 곧 수퍼유저 이전을
40
+ * 뜻한다.
41
+ */
45
42
  process.superUserGranted = async (domain, user) => {
46
43
  if (!user) {
47
44
  return false;
@@ -59,16 +56,17 @@ process.superUserGranted = async (domain, user) => {
59
56
  return systemDomain.owner === user.id;
60
57
  };
61
58
  /*
62
- * 현재 subdomain user의 domain list와의 비교를 통해서,
59
+ * 현재 도메인에 대한 사용자의 체크인 자격을 판단해서,
63
60
  * 인증 성공 또는 인증 에러를 발생시킬 것인지를 결정한다.
64
61
  * 1. 현재 subdomain 이 결정되지 않은 경우.
65
62
  * - checkin로 이동한다.
66
- * 2. superUser 판단
67
- * 3. 현재 subdomain 이 결정된 경우.
68
- * - user의 domains 리스트에 해당 subdomain이 없다면, 인증 오류를 발생한다.
63
+ * 2. 현재 도메인에 체크인할 자격이 있는지 판단한다 (`canUserCheckinDomain`).
64
+ * 3. superUser 판단.
65
+ *
66
+ * 매 요청 통과하는 경로이므로 체크인 가능 도메인 "목록" 을 계산하지 않고 현재 도메인
67
+ * 하나만 판정한다.
69
68
  */
70
69
  async function domainAuthenticateMiddleware(context, next) {
71
- const { t } = context;
72
70
  const { domain, user } = context.state;
73
71
  const subdomain = domain?.subdomain;
74
72
  // 1. 현재 subdomain 이 결정되지 않은 경우.
@@ -79,8 +77,7 @@ async function domainAuthenticateMiddleware(context, next) {
79
77
  });
80
78
  }
81
79
  // 2. 현재 subdomain 이 결정된 경우.
82
- const userDomains = await (0, get_user_domains_js_1.getUserDomains)(user);
83
- if (userDomains.find(domain => domain.subdomain == subdomain) || (await process.superUserGranted(domain, user))) {
80
+ if ((await (0, can_user_checkin_domain_js_1.canUserCheckinDomain)(user, domain)) || (await process.superUserGranted(domain, user))) {
84
81
  return await next();
85
82
  }
86
83
  throw new auth_error_js_1.AuthError({
@@ -1 +1 @@
1
- {"version":3,"file":"domain-authenticate-middleware.js","sourceRoot":"","sources":["../../server/middlewares/domain-authenticate-middleware.ts"],"names":[],"mappings":"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","sourcesContent":["import { Domain, getRepository } from '@things-factory/shell'\n\nimport { AuthError } from '../errors/auth-error.js'\nimport { DomainOwner } from '../service/domain-owner/domain-owner.js'\nimport { User } from '../service/user/user.js'\nimport { getUserDomains } from '../utils/get-user-domains.js'\n\ndeclare global {\n namespace NodeJS {\n interface Process {\n domainOwnerGranted: (domain: Domain, user: User) => Promise<boolean>\n superUserGranted: (domain: Domain, user: User) => Promise<boolean>\n }\n }\n}\n\n/**\n * 도메인 소유권 확인.\n *\n * 소유권은 가지 경로 중 하나로 인식된다:\n * 1) 하위 호환: `Domain.owner` 컬럼에 user.id 일치 (마이그레이션 이전 데이터\n * 또는 \"대표 owner 표시용 캐시\")\n * 2) `DomainOwner` 테이블에 (domainId, userId) 엔트리 존재 (정식 멀티 owner)\n *\n * 둘 중 하나라도 만족하면 owner로 인정 — 마이그레이션 기간/기존 API 호환을\n * 끊어뜨리지 않기 위함.\n */\nprocess.domainOwnerGranted = async (domain: Domain, user: User): Promise<boolean> => {\n if (!user || !domain) return false\n\n // (1) 하위 호환: Domain.owner 캐시 필드\n if (domain.owner === user.id) return true\n\n // Request-level 메모이제이션 — 한 요청 안에서 @privilege directive 가\n // 걸린 field 마다 이 함수가 호출될 수 있는데 (list 쿼리의 경우 N 번),\n // 같은 (domain, user) 조합은 DB 조회를 1 번만 수행.\n // user 객체는 request-scoped 이므로 request 종료 시 자연스럽게 소멸.\n const cacheKey = `__domainOwnerGranted:${domain.id}`\n const cached = (user as any)[cacheKey]\n if (cached !== undefined) return cached\n\n // (2) DomainOwner join table\n const exists = await getRepository(DomainOwner)\n .createQueryBuilder('ow')\n .where('ow.domain_id = :domainId AND ow.user_id = :userId', {\n domainId: domain.id,\n userId: user.id\n })\n .getExists()\n ;(user as any)[cacheKey] = exists\n return exists\n}\n\nprocess.superUserGranted = async (domain: Domain, user: User): Promise<boolean> => {\n if (!user) {\n return false\n }\n\n if (!user.domains.length) {\n user = await getRepository(User).findOne({\n where: { id: user.id },\n relations: ['domains']\n })\n }\n\n const systemDomain: Domain = user.domains.find((domain: Domain) => domain.subdomain === 'system')\n if (!systemDomain) {\n return false\n }\n\n return systemDomain.owner === user.id\n}\n\n/*\n * 현재 subdomain user의 domain list와의 비교를 통해서,\n * 인증 성공 또는 인증 에러를 발생시킬 것인지를 결정한다.\n * 1. 현재 subdomain 이 결정되지 않은 경우.\n * - checkin로 이동한다.\n * 2. superUser 판단\n * 3. 현재 subdomain 이 결정된 경우.\n * - user의 domains 리스트에 해당 subdomain이 없다면, 인증 오류를 발생한다.\n */\n\nexport async function domainAuthenticateMiddleware(context: any, next: any) {\n const { t } = context\n const { domain, user } = context.state\n\n const subdomain: string = domain?.subdomain\n\n // 1. 현재 subdomain 이 결정되지 않은 경우.\n // - checkin로 이동한다.\n if (!subdomain) {\n throw new AuthError({\n errorCode: AuthError.ERROR_CODES.SUBDOMAIN_NOTFOUND\n })\n }\n\n // 2. 현재 subdomain 이 결정된 경우.\n const userDomains: Partial<Domain>[] = await getUserDomains(user)\n if (userDomains.find(domain => domain.subdomain == subdomain) || (await process.superUserGranted(domain, user))) {\n return await next()\n }\n\n throw new AuthError({\n errorCode: AuthError.ERROR_CODES.SUBDOMAIN_NOTFOUND\n })\n}\n"]}
1
+ {"version":3,"file":"domain-authenticate-middleware.js","sourceRoot":"","sources":["../../server/middlewares/domain-authenticate-middleware.ts"],"names":[],"mappings":";;AAkFA,oEAqBC;AAvGD,iDAA6D;AAE7D,2DAAmD;AACnD,qDAA8C;AAC9C,oFAA0E;AAC1E,sEAA4D;AAW5D;;;GAGG;AACH,OAAO,CAAC,kBAAkB,GAAG,KAAK,EAAE,MAAc,EAAE,IAAU,EAAoB,EAAE;IAClF,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IAElC,uCAAuC;IACvC,IAAI,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC,EAAE;QAAE,OAAO,IAAI,CAAA;IAEzC,yDAAyD;IACzD,iDAAiD;IACjD,wCAAwC;IACxC,qDAAqD;IACrD,MAAM,QAAQ,GAAG,wBAAwB,MAAM,CAAC,EAAE,EAAE,CAAA;IACpD,MAAM,MAAM,GAAI,IAAY,CAAC,QAAQ,CAAC,CAAA;IACtC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAA;IAEvC,MAAM,KAAK,GAAG,MAAM,IAAA,mCAAa,EAAC,MAAM,EAAE,IAAI,CAAC,CAC9C;IAAC,IAAY,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAA;IAChC,OAAO,KAAK,CAAA;AACd,CAAC,CAAA;AAED;;;;;;;;;;GAUG;AACH,OAAO,CAAC,gBAAgB,GAAG,KAAK,EAAE,MAAc,EAAE,IAAU,EAAoB,EAAE;IAChF,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,KAAK,CAAA;IACd,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACzB,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,cAAI,CAAC,CAAC,OAAO,CAAC;YACvC,KAAK,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE;YACtB,SAAS,EAAE,CAAC,SAAS,CAAC;SACvB,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,YAAY,GAAW,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAc,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAA;IACjG,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,KAAK,CAAA;IACd,CAAC;IAED,OAAO,YAAY,CAAC,KAAK,KAAK,IAAI,CAAC,EAAE,CAAA;AACvC,CAAC,CAAA;AAED;;;;;;;;;;GAUG;AAEI,KAAK,UAAU,4BAA4B,CAAC,OAAY,EAAE,IAAS;IACxE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAEtC,MAAM,SAAS,GAAW,MAAM,EAAE,SAAS,CAAA;IAE3C,gCAAgC;IAChC,mBAAmB;IACnB,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,yBAAS,CAAC;YAClB,SAAS,EAAE,yBAAS,CAAC,WAAW,CAAC,kBAAkB;SACpD,CAAC,CAAA;IACJ,CAAC;IAED,4BAA4B;IAC5B,IAAI,CAAC,MAAM,IAAA,iDAAoB,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,gBAAgB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC;QACjG,OAAO,MAAM,IAAI,EAAE,CAAA;IACrB,CAAC;IAED,MAAM,IAAI,yBAAS,CAAC;QAClB,SAAS,EAAE,yBAAS,CAAC,WAAW,CAAC,kBAAkB;KACpD,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { Domain, getRepository } from '@things-factory/shell'\n\nimport { AuthError } from '../errors/auth-error.js'\nimport { User } from '../service/user/user.js'\nimport { canUserCheckinDomain } from '../utils/can-user-checkin-domain.js'\nimport { isDomainOwner } from '../utils/domain-ownership.js'\n\ndeclare global {\n namespace NodeJS {\n interface Process {\n domainOwnerGranted: (domain: Domain, user: User) => Promise<boolean>\n superUserGranted: (domain: Domain, user: User) => Promise<boolean>\n }\n }\n}\n\n/**\n * 도메인 소유권 확인. 판정 규칙은 `isDomainOwner` 단일 소스이며\n * (`Domain.owner` 캐시 컬럼 OR `DomainOwner` 테이블), 여기서는 요청 단위 메모이제이션만 더한다.\n */\nprocess.domainOwnerGranted = async (domain: Domain, user: User): Promise<boolean> => {\n if (!user || !domain) return false\n\n // 조회가 필요 없는 캐시 필드 경로는 메모이제이션 이전에 판정된다.\n if (domain.owner === user.id) return true\n\n // Request-level 메모이제이션 — 한 요청 안에서 @privilege directive 가\n // 걸린 field 마다 이 함수가 호출될 수 있는데 (list 쿼리의 경우 N 번),\n // 같은 (domain, user) 조합은 DB 조회를 1 번만 수행.\n // user 객체는 request-scoped 이므로 request 종료 시 자연스럽게 소멸.\n const cacheKey = `__domainOwnerGranted:${domain.id}`\n const cached = (user as any)[cacheKey]\n if (cached !== undefined) return cached\n\n const owned = await isDomainOwner(domain, user)\n ;(user as any)[cacheKey] = owned\n return owned\n}\n\n/**\n * 수퍼유저 확인 모든 도메인을 통과하는 전역 특권이므로 의도적으로 좁게 정의한다.\n *\n * SYSTEM 도메인에 소속되고, 그 도메인의 **대표 오너(`Domain.owner` 컬럼)** 인 한 사람만\n * 수퍼유저다. SYSTEM 도메인의 공동 오너(`DomainOwner` 테이블)는 SYSTEM 도메인의 오너로서만\n * 권한을 가지며 수퍼유저가 되지 않는다 — 그래서 여기서는 `isDomainOwner` 를 쓰지 않는다.\n *\n * 주의: `Domain.owner` 컬럼은 오너 제거 시 남은 공동 오너 중 가장 먼저 추가된 사람으로\n * 자동 재설정된다(`removeDomainOwner`). SYSTEM 도메인에서는 그 재설정이 곧 수퍼유저 이전을\n * 뜻한다.\n */\nprocess.superUserGranted = async (domain: Domain, user: User): Promise<boolean> => {\n if (!user) {\n return false\n }\n\n if (!user.domains.length) {\n user = await getRepository(User).findOne({\n where: { id: user.id },\n relations: ['domains']\n })\n }\n\n const systemDomain: Domain = user.domains.find((domain: Domain) => domain.subdomain === 'system')\n if (!systemDomain) {\n return false\n }\n\n return systemDomain.owner === user.id\n}\n\n/*\n * 현재 도메인에 대한 사용자의 체크인 자격을 판단해서,\n * 인증 성공 또는 인증 에러를 발생시킬 것인지를 결정한다.\n * 1. 현재 subdomain 이 결정되지 않은 경우.\n * - checkin로 이동한다.\n * 2. 현재 도메인에 체크인할 자격이 있는지 판단한다 (`canUserCheckinDomain`).\n * 3. superUser 판단.\n *\n * 요청 통과하는 경로이므로 체크인 가능 도메인 \"목록\" 계산하지 않고 현재 도메인\n * 하나만 판정한다.\n */\n\nexport async function domainAuthenticateMiddleware(context: any, next: any) {\n const { domain, user } = context.state\n\n const subdomain: string = domain?.subdomain\n\n // 1. 현재 subdomain 이 결정되지 않은 경우.\n // - checkin로 이동한다.\n if (!subdomain) {\n throw new AuthError({\n errorCode: AuthError.ERROR_CODES.SUBDOMAIN_NOTFOUND\n })\n }\n\n // 2. 현재 subdomain 이 결정된 경우.\n if ((await canUserCheckinDomain(user, domain)) || (await process.superUserGranted(domain, user))) {\n return await next()\n }\n\n throw new AuthError({\n errorCode: AuthError.ERROR_CODES.SUBDOMAIN_NOTFOUND\n })\n}\n"]}
@@ -6,6 +6,7 @@ const type_graphql_1 = require("type-graphql");
6
6
  const typeorm_1 = require("typeorm");
7
7
  const shell_1 = require("@things-factory/shell");
8
8
  const utils_1 = require("@things-factory/utils");
9
+ const domain_ownership_js_1 = require("../../utils/domain-ownership.js");
9
10
  const privilege_js_1 = require("../privilege/privilege.js");
10
11
  const role_js_1 = require("../role/role.js");
11
12
  const user_js_1 = require("../user/user.js");
@@ -20,7 +21,10 @@ let DomainGeneratorMutation = class DomainGeneratorMutation {
20
21
  if (domain) {
21
22
  throw new Error('domain is duplicated');
22
23
  }
23
- return await domainRepo.save({ name, description, subdomain, owner: user.id });
24
+ const newDomain = await domainRepo.save({ name, description, subdomain });
25
+ /* 대표 오너 컬럼과 `DomainOwner` 테이블을 함께 세팅한다 (컬럼만 쓰면 오너 목록에 나오지 않는다). */
26
+ await (0, domain_ownership_js_1.setPrimaryDomainOwner)(newDomain, user.id, user);
27
+ return await domainRepo.findOneBy({ id: newDomain.id });
24
28
  }
25
29
  async domainUserRoleRegister(newDomainInfo, context) {
26
30
  const { tx } = context.state;
@@ -72,10 +76,10 @@ let DomainGeneratorMutation = class DomainGeneratorMutation {
72
76
  user.roles = [...user.roles, ...filterUserRoles(inviteUser.roles, newRoles)];
73
77
  return await userRepository.save(user);
74
78
  }));
75
- // domain owner
79
+ // domain owner — 대표 오너 컬럼과 `DomainOwner` 테이블을 함께 세팅한다.
76
80
  const { id } = await userRepository.findOne({ where: { email: (0, typeorm_1.ILike)(domainOwner.email) } });
77
- newDomain.owner = id;
78
- return await domainRepository.save(newDomain);
81
+ await (0, domain_ownership_js_1.setPrimaryDomainOwner)(newDomain, id, context.state.user, tx);
82
+ return await domainRepository.findOneBy({ id: newDomain.id });
79
83
  }
80
84
  };
81
85
  exports.DomainGeneratorMutation = DomainGeneratorMutation;
@@ -1 +1 @@
1
- {"version":3,"file":"domain-generator-mutation.js","sourceRoot":"","sources":["../../../server/service/domain-generator/domain-generator-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'\nimport { ILike, In, Repository } from 'typeorm'\n\nimport { Domain, getRepository } from '@things-factory/shell'\nimport { slugger } from '@things-factory/utils'\n\nimport { Privilege } from '../privilege/privilege.js'\nimport { Role } from '../role/role.js'\nimport { User } from '../user/user.js'\nimport { DomainGeneratorInput, DomainUserRoleInput } from './domain-generator-types.js'\n\n@Resolver()\nexport class DomainGeneratorMutation {\n @Directive('@privilege(superUserGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Domain)\n async domainRegister(\n @Arg('domainInput') domainInput: DomainGeneratorInput,\n @Ctx() context: ResolverContext\n ): Promise<Domain> {\n const { user } = context.state\n const { name, description } = domainInput\n const domainRepo: Repository<Domain> = getRepository(Domain)\n const subdomain: string = slugger(name)\n\n const domain: Domain = await domainRepo.findOneBy({ subdomain })\n if (domain) {\n throw new Error('domain is duplicated')\n }\n\n return await domainRepo.save({ name, description, subdomain, owner: user.id })\n }\n\n @Directive('@transaction')\n @Mutation(returns => Domain)\n async domainUserRoleRegister(\n @Arg('newDomainInfo') newDomainInfo: DomainUserRoleInput,\n @Ctx() context: ResolverContext\n ): Promise<Domain> {\n const { tx } = context.state\n // 도메인 생성\n const { domain, users, roles } = newDomainInfo\n const domainOwner = users.find(user => user.owner === true)\n\n const domainRepository: Repository<Domain> = tx.getRepository(Domain)\n const roleRepository: Repository<Role> = tx.getRepository(Role)\n const userRepository: Repository<User> = tx.getRepository(User)\n const privilegeRepository: Repository<Privilege> = tx.getRepository(Privilege)\n\n const subdomain: string = slugger(domain.name)\n\n const newDomain = await domainRepository.save({\n name: domain.name,\n description: domain.description,\n subdomain\n })\n\n // 역할 생성\n const newRoles: Role[] = await Promise.all(\n roles.map(async (role: Role) => {\n if (role.privileges?.length) {\n const privilegeIds: string[] = role.privileges.map((p: Privilege) => p.id)\n role.privileges = await privilegeRepository.findBy({\n id: In(privilegeIds)\n })\n }\n\n role.domain = newDomain\n return await roleRepository.save(role)\n })\n )\n\n // 사용자 생성\n let inviteUsers = []\n let createUsers = []\n users.forEach(user => (user.isInvitee ? inviteUsers.push(user) : createUsers.push(user)))\n\n // create user\n await Promise.all(\n createUsers.map(async user => {\n user.domains = [newDomain]\n user.password = User.encode(user.password, user.salt)\n user.salt = User.generateSalt()\n user.passwordUpdatedAt = new Date()\n user.userType = 'user'\n user.roles = filterUserRoles(user.roles, newRoles)\n\n return await userRepository.save(user)\n })\n )\n\n // invite user\n await Promise.all(\n inviteUsers.map(async inviteUser => {\n const user: User = await userRepository.findOne({\n where: { email: inviteUser.email },\n relations: ['domains', 'roles']\n })\n\n user.domains = [...user.domains, newDomain]\n user.roles = [...user.roles, ...filterUserRoles(inviteUser.roles, newRoles)]\n\n return await userRepository.save(user)\n })\n )\n\n // domain owner\n const { id } = await userRepository.findOne({ where: { email: ILike(domainOwner.email) } })\n newDomain.owner = id\n return await domainRepository.save(newDomain)\n }\n}\n\nfunction filterUserRoles(userRoles: Role[], newRoles: Role[]): Role[] {\n const userRoleNames: string[] = userRoles.map((r: Role) => r.name)\n return newRoles.filter((r: Role) => userRoleNames.indexOf(r.name) >= 0)\n}\n"]}
1
+ {"version":3,"file":"domain-generator-mutation.js","sourceRoot":"","sources":["../../../server/service/domain-generator/domain-generator-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'\nimport { ILike, In, Repository } from 'typeorm'\n\nimport { Domain, getRepository } from '@things-factory/shell'\nimport { slugger } from '@things-factory/utils'\n\nimport { setPrimaryDomainOwner } from '../../utils/domain-ownership.js'\nimport { Privilege } from '../privilege/privilege.js'\nimport { Role } from '../role/role.js'\nimport { User } from '../user/user.js'\nimport { DomainGeneratorInput, DomainUserRoleInput } from './domain-generator-types.js'\n\n@Resolver()\nexport class DomainGeneratorMutation {\n @Directive('@privilege(superUserGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Domain)\n async domainRegister(\n @Arg('domainInput') domainInput: DomainGeneratorInput,\n @Ctx() context: ResolverContext\n ): Promise<Domain> {\n const { user } = context.state\n const { name, description } = domainInput\n const domainRepo: Repository<Domain> = getRepository(Domain)\n const subdomain: string = slugger(name)\n\n const domain: Domain = await domainRepo.findOneBy({ subdomain })\n if (domain) {\n throw new Error('domain is duplicated')\n }\n\n const newDomain: Domain = await domainRepo.save({ name, description, subdomain })\n\n /* 대표 오너 컬럼과 `DomainOwner` 테이블을 함께 세팅한다 (컬럼만 쓰면 오너 목록에 나오지 않는다). */\n await setPrimaryDomainOwner(newDomain, user.id, user)\n\n return await domainRepo.findOneBy({ id: newDomain.id })\n }\n\n @Directive('@transaction')\n @Mutation(returns => Domain)\n async domainUserRoleRegister(\n @Arg('newDomainInfo') newDomainInfo: DomainUserRoleInput,\n @Ctx() context: ResolverContext\n ): Promise<Domain> {\n const { tx } = context.state\n // 도메인 생성\n const { domain, users, roles } = newDomainInfo\n const domainOwner = users.find(user => user.owner === true)\n\n const domainRepository: Repository<Domain> = tx.getRepository(Domain)\n const roleRepository: Repository<Role> = tx.getRepository(Role)\n const userRepository: Repository<User> = tx.getRepository(User)\n const privilegeRepository: Repository<Privilege> = tx.getRepository(Privilege)\n\n const subdomain: string = slugger(domain.name)\n\n const newDomain = await domainRepository.save({\n name: domain.name,\n description: domain.description,\n subdomain\n })\n\n // 역할 생성\n const newRoles: Role[] = await Promise.all(\n roles.map(async (role: Role) => {\n if (role.privileges?.length) {\n const privilegeIds: string[] = role.privileges.map((p: Privilege) => p.id)\n role.privileges = await privilegeRepository.findBy({\n id: In(privilegeIds)\n })\n }\n\n role.domain = newDomain\n return await roleRepository.save(role)\n })\n )\n\n // 사용자 생성\n let inviteUsers = []\n let createUsers = []\n users.forEach(user => (user.isInvitee ? inviteUsers.push(user) : createUsers.push(user)))\n\n // create user\n await Promise.all(\n createUsers.map(async user => {\n user.domains = [newDomain]\n user.password = User.encode(user.password, user.salt)\n user.salt = User.generateSalt()\n user.passwordUpdatedAt = new Date()\n user.userType = 'user'\n user.roles = filterUserRoles(user.roles, newRoles)\n\n return await userRepository.save(user)\n })\n )\n\n // invite user\n await Promise.all(\n inviteUsers.map(async inviteUser => {\n const user: User = await userRepository.findOne({\n where: { email: inviteUser.email },\n relations: ['domains', 'roles']\n })\n\n user.domains = [...user.domains, newDomain]\n user.roles = [...user.roles, ...filterUserRoles(inviteUser.roles, newRoles)]\n\n return await userRepository.save(user)\n })\n )\n\n // domain owner — 대표 오너 컬럼과 `DomainOwner` 테이블을 함께 세팅한다.\n const { id } = await userRepository.findOne({ where: { email: ILike(domainOwner.email) } })\n await setPrimaryDomainOwner(newDomain, id, context.state.user, tx)\n\n return await domainRepository.findOneBy({ id: newDomain.id })\n }\n}\n\nfunction filterUserRoles(userRoles: Role[], newRoles: Role[]): Role[] {\n const userRoleNames: string[] = userRoles.map((r: Role) => r.name)\n return newRoles.filter((r: Role) => userRoleNames.indexOf(r.name) >= 0)\n}\n"]}
@@ -25,7 +25,7 @@ export * from './privilege/privilege-types.js';
25
25
  export * from './role/role-types.js';
26
26
  export * from './user/user-types.js';
27
27
  export * from './domain-link/domain-link-types.js';
28
- export declare const entities: (typeof import("./web-auth-credential/web-auth-credential.js").WebAuthCredential | typeof import("./user/user.js").User | typeof import("./auth-provider/auth-provider.js").AuthProvider | typeof import("./users-auth-providers/users-auth-providers.js").UsersAuthProviders | typeof import("./role/role.js").Role | typeof import("./privilege/privilege.js").Privilege | typeof import("./domain-owner/domain-owner.js").DomainOwner | typeof import("./verification-token/verification-token.js").VerificationToken | typeof import("./verification-token/verification-token.js").VerificationTokenType | typeof import("./password-history/password-history.js").PasswordHistory | typeof import("./invitation/invitation.js").Invitation | typeof import("./application/application.js").Application | typeof import("./login-history/login-history.js").LoginHistory | typeof import("./appliance/appliance.js").Appliance | typeof import("./granted-role/granted-role.js").GrantedRole | typeof import("./partner/partner.js").Partner | typeof import("./domain-link/domain-link.js").DomainLink)[];
28
+ export declare const entities: (typeof import("./web-auth-credential/web-auth-credential.js").WebAuthCredential | typeof import("./user/user.js").User | typeof import("./auth-provider/auth-provider.js").AuthProvider | typeof import("./users-auth-providers/users-auth-providers.js").UsersAuthProviders | typeof import("./domain-owner/domain-owner.js").DomainOwner | typeof import("./granted-role/granted-role.js").GrantedRole | typeof import("./role/role.js").Role | typeof import("./privilege/privilege.js").Privilege | typeof import("./verification-token/verification-token.js").VerificationToken | typeof import("./verification-token/verification-token.js").VerificationTokenType | typeof import("./password-history/password-history.js").PasswordHistory | typeof import("./invitation/invitation.js").Invitation | typeof import("./application/application.js").Application | typeof import("./login-history/login-history.js").LoginHistory | typeof import("./appliance/appliance.js").Appliance | typeof import("./partner/partner.js").Partner | typeof import("./domain-link/domain-link.js").DomainLink)[];
29
29
  export declare const schema: {
30
30
  typeDefs: {
31
31
  privilegeDirectiveTypeDefs: import("graphql").DocumentNode;
@@ -9,6 +9,7 @@ const env_1 = require("@things-factory/env");
9
9
  const shell_1 = require("@things-factory/shell");
10
10
  const delete_user_js_1 = require("../../controllers/delete-user.js");
11
11
  const get_domain_users_js_1 = require("../../utils/get-domain-users.js");
12
+ const domain_ownership_js_1 = require("../../utils/domain-ownership.js");
12
13
  const role_js_1 = require("../role/role.js");
13
14
  const user_js_1 = require("./user.js");
14
15
  const user_types_js_1 = require("./user-types.js");
@@ -213,7 +214,7 @@ let UserMutation = class UserMutation {
213
214
  return true;
214
215
  }
215
216
  async transferOwner(username, context) {
216
- const { domain, tx } = context.state;
217
+ const { domain, tx, user: actor } = context.state;
217
218
  const userRepository = (0, shell_1.getRepository)(user_js_1.User, tx);
218
219
  var user = await userRepository.findOne({
219
220
  where: { username },
@@ -234,11 +235,13 @@ let UserMutation = class UserMutation {
234
235
  if (user.domains.map((d) => d.id).indexOf(domain.id) < 0) {
235
236
  throw new Error(`User is not belongs to current domain`);
236
237
  }
237
- if (user.roles.filter((r) => r.domainId == domain.id).length == 0) {
238
+ /* 역할은 부모 도메인으로부터 상속될 있으므로 부여된 상속 역할도 자격으로 인정한다. */
239
+ const grantableRoleDomainIds = [domain.id, domain.parentId].filter(Boolean);
240
+ if (user.roles.filter((r) => grantableRoleDomainIds.includes(r.domainId)).length == 0) {
238
241
  throw new Error(`Only users with at least one role in this domain are eligible to receive admin privileges.`);
239
242
  }
240
- domain.owner = user.id;
241
- await (0, shell_1.getRepository)(shell_1.Domain, tx).save(domain);
243
+ /* 대표 오너 컬럼과 `DomainOwner` 테이블을 함께 갱신한다 (기존 오너 엔트리는 유지). */
244
+ await (0, domain_ownership_js_1.setPrimaryDomainOwner)(domain, user.id, actor, tx);
242
245
  return true;
243
246
  }
244
247
  async activateUser(username, context) {
@@ -284,7 +287,8 @@ let UserMutation = class UserMutation {
284
287
  if (!targetUser?.domains?.find((userDomain) => userDomain.id === domain.id)) {
285
288
  throw new Error('User is not belong to domain');
286
289
  }
287
- if (targetUser.userType == 'admin' || targetUser.id === domain.owner) {
290
+ /* 공동 오너(`DomainOwner` 테이블)도 도메인 관리자이므로 같은 보호를 받는다. */
291
+ if (targetUser.userType == 'admin' || (await (0, domain_ownership_js_1.isDomainOwner)(domain, targetUser, tx))) {
288
292
  throw new Error('Admin deactivation not allowed');
289
293
  }
290
294
  targetUser.status = user_js_1.UserStatus.INACTIVE;
@@ -1 +1 @@
1
- {"version":3,"file":"user-mutation.js","sourceRoot":"","sources":["../../../server/service/user/user-mutation.ts"],"names":[],"mappings":";;;;AAAA,+CAAsE;AACtE,qDAAqD;AACrD,qCAAsE;AAEtE,6CAA4C;AAC5C,iDAAwE;AAExE,qEAAmH;AACnH,yEAA8E;AAC9E,6CAAsC;AACtC,uCAA4C;AAC5C,mDAAoD;AACpD,iEAA+G;AAGxG,IAAM,YAAY,GAAlB,MAAM,YAAY;IAOjB,AAAN,KAAK,CAAC,UAAU,CACqE,IAAa,EACzF,OAAwB;QAE/B,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QACpC,MAAM,EAAE,eAAe,EAAE,GAAG,YAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;QAClD,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,IAAI,CAAA;QAChC,MAAM,cAAc,GAAG,IAAA,qBAAa,EAAC,cAAI,EAAE,EAAE,CAAC,CAAA;QAE9C,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAA;QAC/B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;QAEzB,IAAI,MAAM,cAAc,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC;YACzE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,GAAG,uCAAuB,CAAC,CAAC,CAAA;QAChE,CAAC;QAED,IAAI,MAAM,cAAc,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,IAAA,eAAK,EAAC,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YAC1E,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,GAAG,oCAAoB,CAAC,CAAC,CAAA;QAC7D,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,eAAe,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAA;QAC9E,CAAC;QAED,6DAA6D;QAC7D,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,GAAG,gCAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;QACtF,CAAC;QAED,mDAAmD;QACnD,6CAA6C;QAC7C,0DAA0D;QAE1D,MAAM,IAAI,GAAG,cAAI,CAAC,YAAY,EAAE,CAAA;QAEhC,OAAO,MAAM,cAAc,CAAC,IAAI,CAAC;YAC/B,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI;YAC3B,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI;YAC3B,GAAG,IAAI;YACP,OAAO,EAAE,CAAC,MAAM,CAAC;YACjB,KAAK,EACH,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM;gBAC7B,CAAC,CAAC,MAAM,IAAA,qBAAa,EAAC,cAAI,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC;oBACnC,EAAE,EAAE,IAAA,YAAE,EAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBACvC,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE;iBAC1B,CAAC;gBACJ,CAAC,CAAC,EAAE;YACR,IAAI;YACJ,iBAAiB,EAAE,IAAI,IAAI,EAAE;YAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,cAAI,CAAC,MAAM,CAAC,eAAe,EAAE,IAAI,CAAC;SAChG,CAAC,CAAA;IACJ,CAAC;IAQK,AAAN,KAAK,CAAC,UAAU,CAEd,KAAa,EACsE,KAAgB,EAC5F,OAAwB;QAE/B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,GAAuD,OAAO,CAAC,KAAK,CAAA;QACvG,MAAM,EAAE,GAA6B,IAAA,kDAA4B,EAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;QACpF,MAAM,IAAI,GAAS,MAAM,EAAE;aACxB,QAAQ,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;aACpF,iBAAiB,CAAC,YAAY,EAAE,OAAO,CAAC;aACxC,iBAAiB,CAAC,cAAc,EAAE,UAAU,CAAC;aAC7C,MAAM,EAAE,CAAA;QAEX,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAChB,KAAK,CAAC,KAAK,GAAG,MAAM,IAAA,qBAAa,EAAC,cAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC;gBAC/C,KAAK,EAAE,EAAE,EAAE,EAAE,IAAA,YAAE,EAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAgB,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;aAC/D,CAAC,CAAA;QACJ,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YACjD,IAAI,CAAC,MAAM,GAAG,oBAAU,CAAC,SAAS,CAAA;QACpC,CAAC;QAED,OAAO,MAAM,IAAA,qBAAa,EAAC,cAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC;YACxC,GAAG,IAAI;YACP,GAAG,KAAK;YACR,OAAO;SACD,CAAC,CAAA;IACX,CAAC;IAQK,AAAN,KAAK,CAAC,kBAAkB,CAEtB,OAAoB,EACb,OAAwB;QAE/B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAC1C,MAAM,QAAQ,GAAG,IAAA,qBAAa,EAAC,cAAI,EAAE,EAAE,CAAC,CAAA;QAExC,IAAI,OAAO,GAAG,EAAE,CAAA;QAChB,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,CAAA;QACzF,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,CAAA;QAEzF,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC/C,MAAM,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,CAAA;gBAEnC,mDAAmD;gBACnD,6CAA6C;gBAC7C,+DAA+D;gBAE/D,MAAM,IAAI,GAAG,cAAI,CAAC,YAAY,EAAE,CAAA;gBAChC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC;oBACjC,GAAI,SAAiB;oBACrB,OAAO,EAAE,CAAC,MAAM,CAAC;oBACjB,IAAI;oBACJ,QAAQ,EAAE,cAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC;oBAC/C,iBAAiB,EAAE,IAAI,IAAI,EAAE;oBAC7B,OAAO,EAAE,IAAI;oBACb,OAAO,EAAE,IAAI;iBACd,CAAC,CAAA;gBAEF,2BAA2B;gBAC3B,WAAW;gBACX,0BAA0B;gBAC1B,cAAc;gBACd,2BAA2B;gBAC3B,cAAc;gBACd,0BAA0B;gBAC1B,2BAA2B;gBAC3B,OAAO;gBACP,eAAe;gBAEf,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;YAC1C,CAAC;QACH,CAAC;QAED,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC/C,MAAM,YAAY,GAAG,cAAc,CAAC,CAAC,CAAC,CAAA;gBACtC,mDAAmD;gBACnD,6CAA6C;gBAC7C,kEAAkE;gBAElE,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,YAAY,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;gBAC/F,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;gBAEnG,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC;oBACjC,GAAG,IAAI;oBACP,GAAI,YAAoB;oBACxB,OAAO;oBACP,QAAQ,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAI,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ;oBAC/F,OAAO,EAAE,IAAI;iBACd,CAAC,CAAA;gBAEF,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;oBACzB,SAAQ;gBACV,CAAC;gBAED,mCAAmC;gBACnC,iBAAiB;gBACjB,aAAa;gBACb,IAAI;gBAEJ,6BAA6B;gBAC7B,qCAAqC;gBACrC,wDAAwD;gBACxD,aAAa;gBACb,4BAA4B;gBAC5B,gBAAgB;gBAChB,6BAA6B;gBAC7B,gBAAgB;gBAChB,0BAA0B;gBAC1B,6BAA6B;gBAC7B,SAAS;gBACT,iBAAiB;gBACjB,IAAI;gBAEJ,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;YAC1C,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAA;IAChB,CAAC;IAQK,AAAN,KAAK,CAAC,UAAU,CAC2D,QAAgB,EAClF,OAAwB;QAE/B,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAE5B,MAAM,IAAA,2BAAgB,EAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAA;QAExC,OAAO,IAAI,CAAA;IACb,CAAC;IAQK,AAAN,KAAK,CAAC,WAAW,CAC0E,SAAmB,EACrG,OAAwB;QAE/B,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAC5B,MAAM,IAAA,4BAAiB,EAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAA;QAE1C,OAAO,IAAI,CAAA;IACb,CAAC;IAOK,AAAN,KAAK,CAAC,UAAU,CACoE,QAAgB,EAC3F,OAAwB;QAE/B,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QACpC,MAAM,cAAc,GAAG,IAAA,qBAAa,EAAC,cAAI,EAAE,EAAE,CAAC,CAAA;QAE9C,IAAI,OAAO,GAAS,MAAM,cAAc,CAAC,OAAO,CAAC;YAC/C,KAAK,EAAE,EAAE,QAAQ,EAAE;YACnB,SAAS,EAAE,CAAC,SAAS,CAAC;SACvB,CAAC,CAAA;QAEF,IAAI,CAAC,OAAO,IAAI,4BAA4B,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5D,OAAO,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC;gBACrC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAA,eAAK,EAAC,QAAQ,CAAC,EAAE;gBACjC,SAAS,EAAE,CAAC,SAAS,CAAC;aACvB,CAAC,CAAA;QACJ,CAAC;QAED,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAA;QACtF,CAAC;QAED,MAAM,eAAe,GAAa,OAAO,CAAC,OAAO,CAAA;QACjD,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;YAC5D,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,6BAA6B,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;QAC3G,CAAC;QAED,OAAO,CAAC,OAAO,GAAG,CAAC,GAAG,eAAe,EAAE,MAAM,CAAC,CAAA;QAC9C,MAAM,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAElC,OAAO,IAAI,CAAA;IACb,CAAC;IAQK,AAAN,KAAK,CAAC,gBAAgB,CAC8E,QAAgB,EAC3G,OAAwB;QAE/B,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QACpC,MAAM,cAAc,GAAG,IAAA,qBAAa,EAAC,cAAI,EAAE,EAAE,CAAC,CAAA;QAE9C,IAAI,IAAI,GAAS,MAAM,cAAc,CAAC,OAAO,CAAC;YAC5C,KAAK,EAAE,EAAE,QAAQ,EAAE;YACnB,SAAS,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC;SAChC,CAAC,CAAA;QAEF,IAAI,CAAC,IAAI,IAAI,4BAA4B,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzD,IAAI,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC;gBAClC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAA,eAAK,EAAC,QAAQ,CAAC,EAAE;gBACjC,SAAS,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC;aAChC,CAAC,CAAA;QACJ,CAAC;QAED,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAA;QACtF,CAAC;QAED,MAAM,eAAe,GAAW,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,UAAkB,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,CAAA;QAC3G,IAAI,eAAe,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;QAC9F,CAAC;QAED,mCAAmC;QACnC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC,CAAA;QAEvC,sCAAsC;QACtC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAU,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,EAAE,CAAC,CAAA;QAE3E,MAAM,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAE/B,OAAO,IAAI,CAAA;IACb,CAAC;IAQK,AAAN,KAAK,CAAC,aAAa,CACgF,QAAgB,EAC1G,OAAwB;QAE/B,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QACpC,MAAM,cAAc,GAAG,IAAA,qBAAa,EAAC,cAAI,EAAE,EAAE,CAAC,CAAA;QAE9C,IAAI,IAAI,GAAS,MAAM,cAAc,CAAC,OAAO,CAAC;YAC5C,KAAK,EAAE,EAAE,QAAQ,EAAE;YACnB,SAAS,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC;SAChC,CAAC,CAAA;QAEF,IAAI,CAAC,IAAI,IAAI,4BAA4B,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzD,IAAI,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC;gBAClC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAA,eAAK,EAAC,QAAQ,CAAC,EAAE;gBACjC,SAAS,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC;aAChC,CAAC,CAAA;QACJ,CAAC;QAED,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAA;QACtF,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,KAAK,oBAAU,CAAC,SAAS,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAA;QACnF,CAAC;QAED,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;YACjE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAA;QAC1D,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAO,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACxE,MAAM,IAAI,KAAK,CAAC,4FAA4F,CAAC,CAAA;QAC/G,CAAC;QAED,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAA;QACtB,MAAM,IAAA,qBAAa,EAAC,cAAM,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAE5C,OAAO,IAAI,CAAA;IACb,CAAC;IAQK,AAAN,KAAK,CAAC,YAAY,CACoE,QAAgB,EAC7F,OAAwB;QAE/B,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QACpC,MAAM,cAAc,GAAG,IAAA,qBAAa,EAAC,cAAI,EAAE,EAAE,CAAC,CAAA;QAE9C,IAAI,UAAU,GAAS,MAAM,cAAc,CAAC,OAAO,CAAC;YAClD,KAAK,EAAE,EAAE,QAAQ,EAAE;YACnB,SAAS,EAAE,CAAC,SAAS,CAAC;SACvB,CAAC,CAAA;QAEF,IAAI,CAAC,UAAU,IAAI,4BAA4B,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/D,UAAU,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC;gBACxC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAA,eAAK,EAAC,QAAQ,CAAC,EAAE;gBACjC,SAAS,EAAE,CAAC,SAAS,CAAC;aACvB,CAAC,CAAA;QACJ,CAAC;QAED,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAA;QACtF,CAAC;QAED,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,UAAkB,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;YACpF,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAA;QACjD,CAAC;QAED,UAAU,CAAC,SAAS,GAAG,CAAC,CAAA;QACxB,UAAU,CAAC,MAAM,GAAG,oBAAU,CAAC,SAAS,CAAA;QAExC,MAAM,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAErC,OAAO,IAAI,CAAA;IACb,CAAC;IAQK,AAAN,KAAK,CAAC,cAAc,CACoE,QAAgB,EAC/F,OAAwB;QAE/B,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QACpC,MAAM,cAAc,GAAG,IAAA,qBAAa,EAAC,cAAI,EAAE,EAAE,CAAC,CAAA;QAE9C,IAAI,UAAU,GAAS,MAAM,cAAc,CAAC,OAAO,CAAC;YAClD,KAAK,EAAE,EAAE,QAAQ,EAAE;YACnB,SAAS,EAAE,CAAC,SAAS,CAAC;SACvB,CAAC,CAAA;QAEF,IAAI,CAAC,UAAU,IAAI,4BAA4B,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/D,UAAU,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC;gBACxC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAA,eAAK,EAAC,QAAQ,CAAC,EAAE;gBACjC,SAAS,EAAE,CAAC,SAAS,CAAC;aACvB,CAAC,CAAA;QACJ,CAAC;QAED,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAA;QACtF,CAAC;QAED,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,UAAkB,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;YACpF,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAA;QACjD,CAAC;QAED,IAAI,UAAU,CAAC,QAAQ,IAAI,OAAO,IAAI,UAAU,CAAC,EAAE,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC;YACrE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;QACnD,CAAC;QAED,UAAU,CAAC,MAAM,GAAG,oBAAU,CAAC,QAAQ,CAAA;QAEvC,MAAM,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAErC,OAAO,IAAI,CAAA;IACb,CAAC;IAQK,AAAN,KAAK,CAAC,sBAAsB,CACsE,QAAgB,EACzG,OAAwB;QAE/B,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAEpC,MAAM,EAAE,eAAe,EAAE,GAAG,YAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;QAClD,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;QAC9C,CAAC;QAED,MAAM,cAAc,GAAG,IAAA,qBAAa,EAAC,cAAI,EAAE,EAAE,CAAC,CAAA;QAE9C,IAAI,UAAU,GAAS,MAAM,cAAc,CAAC,OAAO,CAAC;YAClD,KAAK,EAAE,EAAE,QAAQ,EAAE;YACnB,SAAS,EAAE,CAAC,SAAS,CAAC;SACvB,CAAC,CAAA;QAEF,IAAI,CAAC,UAAU,IAAI,4BAA4B,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/D,UAAU,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC;gBACxC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAA,eAAK,EAAC,QAAQ,CAAC,EAAE;gBACjC,SAAS,EAAE,CAAC,SAAS,CAAC;aACvB,CAAC,CAAA;QACJ,CAAC;QAED,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAA;QACtF,CAAC;QAED,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,UAAkB,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;YACpF,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAA;QACjD,CAAC;QAED,UAAU,CAAC,IAAI,GAAG,cAAI,CAAC,YAAY,EAAE,CAAA;QACrC,UAAU,CAAC,QAAQ,GAAG,cAAI,CAAC,MAAM,CAAC,eAAe,EAAE,UAAU,CAAC,IAAI,CAAC,CAAA;QAEnE,MAAM,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAErC,OAAO,IAAI,CAAA;IACb,CAAC;IAQK,AAAN,KAAK,CAAC,eAAe,CAC2E,QAAgB,EAE9G,cAA2B,EAE3B,aAA0B,EACnB,OAAwB;QAE/B,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QACpC,MAAM,cAAc,GAAG,IAAA,qBAAa,EAAC,cAAI,EAAE,EAAE,CAAC,CAAA;QAE9C,IAAI,IAAI,GAAS,MAAM,cAAc,CAAC,OAAO,CAAC;YAC5C,KAAK,EAAE,EAAE,QAAQ,EAAE;YACnB,SAAS,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC;SAChC,CAAC,CAAA;QAEF,IAAI,CAAC,IAAI,IAAI,4BAA4B,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzD,IAAI,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC;gBAClC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAA,eAAK,EAAC,QAAQ,CAAC,EAAE;gBACjC,SAAS,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC;aAChC,CAAC,CAAA;QACJ,CAAC;QAED,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAA;QACtF,CAAC;QAED,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;YACjE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAA;QAC1D,CAAC;QAED,MAAM,gBAAgB,GAAa,cAAc,CAAC,GAAG,CAAC,CAAC,CAAO,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QACxE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAO,EAAE,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;QAC/E,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,aAAuB,CAAC,CAAA;QAEvD,OAAO,MAAM,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACxC,CAAC;CACF,CAAA;AAxhBY,oCAAY;AAOjB;IANL,IAAA,wBAAS,EAAC,+EAA+E,CAAC;IAC1F,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,cAAI,EAAE;QACzB,WAAW,EACT,+HAA+H;KAClI,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,MAAM,EAAE,EAAE,WAAW,EAAE,mDAAmD,EAAE,CAAC,CAAA;IACjF,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CADmF,uBAAO;;8CAkDjG;AAQK;IANL,IAAA,wBAAS,EAAC,+EAA+E,CAAC;IAC1F,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,cAAI,EAAE;QACzB,WAAW,EACT,+HAA+H;KAClI,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,qCAAmB,EAAE,EAAE,WAAW,EAAE,0CAA0C,EAAE,CAAC,CAAA;IAEtG,mBAAA,IAAA,kBAAG,EAAC,OAAO,EAAE,EAAE,WAAW,EAAE,kDAAkD,EAAE,CAAC,CAAA;IACjF,mBAAA,IAAA,kBAAG,GAAE,CAAA;;qDADoF,yBAAS;;8CA0BpG;AAQK;IANL,IAAA,wBAAS,EAAC,+EAA+E,CAAC;IAC1F,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,cAAI,CAAC,EAAE;QAC3B,WAAW,EACT,kHAAkH;KACrH,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,yBAAS,CAAC,EAAE,EAAE,WAAW,EAAE,yDAAyD,EAAE,CAAC,CAAA;IAE/G,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;sDAyFP;AAQK;IANL,IAAA,wBAAS,EAAC,+EAA+E,CAAC;IAC1F,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE;QAC5B,WAAW,EACT,mIAAmI;KACtI,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,UAAU,EAAE,EAAE,WAAW,EAAE,qCAAqC,EAAE,CAAC,CAAA;IACvE,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;8CAOP;AAQK;IANL,IAAA,wBAAS,EAAC,+EAA+E,CAAC;IAC1F,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE;QAC5B,WAAW,EACT,uHAAuH;KAC1H,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,WAAW,EAAE,kCAAkC,EAAE,CAAC,CAAA;IACvF,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;+CAMP;AAOK;IALL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE;QAC5B,WAAW,EACT,uIAAuI;KAC1I,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,UAAU,EAAE,EAAE,WAAW,EAAE,8CAA8C,EAAE,CAAC,CAAA;IAChF,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;8CA8BP;AAQK;IANL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,+EAA+E,CAAC;IAC1F,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE;QAC5B,WAAW,EACT,0IAA0I;KAC7I,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,UAAU,EAAE,EAAE,WAAW,EAAE,8DAA8D,EAAE,CAAC,CAAA;IAChG,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;oDAmCP;AAQK;IANL,IAAA,wBAAS,EAAC,8DAA8D,CAAC;IACzE,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE;QAC5B,WAAW,EACT,+HAA+H;KAClI,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,UAAU,EAAE,EAAE,WAAW,EAAE,6DAA6D,EAAE,CAAC,CAAA;IAC/F,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;iDAqCP;AAQK;IANL,IAAA,wBAAS,EAAC,+EAA+E,CAAC;IAC1F,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE;QAC5B,WAAW,EACT,iHAAiH;KACpH,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,UAAU,EAAE,EAAE,WAAW,EAAE,gDAAgD,EAAE,CAAC,CAAA;IAClF,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;gDA+BP;AAQK;IANL,IAAA,wBAAS,EAAC,+EAA+E,CAAC;IAC1F,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE;QAC5B,WAAW,EACT,sHAAsH;KACzH,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,UAAU,EAAE,EAAE,WAAW,EAAE,kDAAkD,EAAE,CAAC,CAAA;IACpF,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;kDAkCP;AAQK;IANL,IAAA,wBAAS,EAAC,+EAA+E,CAAC;IAC1F,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE;QAC5B,WAAW,EACT,gIAAgI;KACnI,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,UAAU,EAAE,EAAE,WAAW,EAAE,4DAA4D,EAAE,CAAC,CAAA;IAC9F,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;0DAqCP;AAQK;IANL,IAAA,wBAAS,EAAC,+EAA+E,CAAC;IAC1F,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,cAAI,EAAE;QACzB,WAAW,EACT,2GAA2G;KAC9G,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,UAAU,EAAE,EAAE,WAAW,EAAE,0DAA0D,EAAE,CAAC,CAAA;IAC5F,mBAAA,IAAA,kBAAG,EAAC,gBAAgB,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,iBAAS,CAAC,EAAE,EAAE,WAAW,EAAE,qDAAqD,EAAE,CAAC,CAAA;IAElH,mBAAA,IAAA,kBAAG,EAAC,eAAe,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,iBAAS,CAAC,EAAE,EAAE,WAAW,EAAE,+CAA+C,EAAE,CAAC,CAAA;IAE3G,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;mDA8BP;uBAvhBU,YAAY;IADxB,IAAA,uBAAQ,EAAC,cAAI,CAAC;GACF,YAAY,CAwhBxB","sourcesContent":["import { Arg, Ctx, Directive, Mutation, Resolver } 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 } from '@things-factory/shell'\n\nimport { deleteUser as commonDeleteUser, deleteUsers as commonDeleteUsers } from '../../controllers/delete-user.js'\nimport { buildDomainUsersQueryBuilder } from '../../utils/get-domain-users.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 @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 } = 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 if (user.roles.filter((r: Role) => r.domainId == domain.id).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 domain.owner = user.id\n await getRepository(Domain, tx).save(domain)\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 if (targetUser.userType == 'admin' || targetUser.id === domain.owner) {\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 @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 const availableRoleIds: string[] = availableRoles.map((r: Role) => r.id)\n user.roles = user.roles.filter((r: Role) => availableRoleIds.indexOf(r.id) < 0)\n user.roles = user.roles.concat(selectedRoles as Role[])\n\n return await userRepository.save(user)\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 } 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 } from '@things-factory/shell'\n\nimport { deleteUser as commonDeleteUser, deleteUsers as commonDeleteUsers } from '../../controllers/delete-user.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 @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 @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 const availableRoleIds: string[] = availableRoles.map((r: Role) => r.id)\n user.roles = user.roles.filter((r: Role) => availableRoleIds.indexOf(r.id) < 0)\n user.roles = user.roles.concat(selectedRoles as Role[])\n\n return await userRepository.save(user)\n }\n}\n"]}
@@ -8,6 +8,7 @@ const typeorm_1 = require("typeorm");
8
8
  const env_1 = require("@things-factory/env");
9
9
  const shell_1 = require("@things-factory/shell");
10
10
  const check_user_belongs_domain_js_1 = require("../../utils/check-user-belongs-domain.js");
11
+ const domain_ownership_js_1 = require("../../utils/domain-ownership.js");
11
12
  const get_domain_users_js_1 = require("../../utils/get-domain-users.js");
12
13
  const user_js_1 = require("./user.js");
13
14
  const user_types_js_1 = require("./user-types.js");
@@ -50,8 +51,10 @@ let UserQuery = class UserQuery {
50
51
  return 'USER.id IN ' + subQuery;
51
52
  });
52
53
  const [items, total] = await qb.getManyAndCount();
54
+ /* 오너는 여러 명일 수 있다 — 대표 오너 컬럼만 보면 공동 오너가 일반 사용자로 표시된다. */
55
+ const ownerIds = await (0, domain_ownership_js_1.findDomainOwnerUserIds)(domain);
53
56
  const foundUsers = items.map((item) => {
54
- item.owner = item.id === domain.owner;
57
+ item.owner = ownerIds.has(item.id);
55
58
  return item;
56
59
  });
57
60
  return { items: foundUsers, total };
@@ -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 { checkUserBelongsDomain } from '../../utils/check-user-belongs-domain.js'\nimport { buildDomainUsersQueryBuilder } from '../../utils/get-domain-users.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 const foundUsers: User[] = items.map((item: User) => {\n item.owner = item.id === domain.owner\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 @FieldResolver({ description: 'Returns the list of roles assigned to the user.' })\n async roles(@Root() user: User) {\n return (\n await getRepository(User).findOne({\n where: { id: user.id },\n relations: ['roles']\n })\n ).roles\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 { checkUserBelongsDomain } from '../../utils/check-user-belongs-domain.js'\nimport { findDomainOwnerUserIds } from '../../utils/domain-ownership.js'\nimport { buildDomainUsersQueryBuilder } from '../../utils/get-domain-users.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 @FieldResolver({ description: 'Returns the list of roles assigned to the user.' })\n async roles(@Root() user: User) {\n return (\n await getRepository(User).findOne({\n where: { id: user.id },\n relations: ['roles']\n })\n ).roles\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"]}