@things-factory/organization 10.0.19 → 10.1.0

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 (78) hide show
  1. package/dist-client/component/approval-line-brief.js +93 -36
  2. package/dist-client/component/approval-line-brief.js.map +1 -1
  3. package/dist-client/component/approval-line-items-editor-popup.d.ts +2 -0
  4. package/dist-client/component/approval-line-items-editor-popup.js +27 -9
  5. package/dist-client/component/approval-line-items-editor-popup.js.map +1 -1
  6. package/dist-client/component/approval-line-items-editor.d.ts +7 -1
  7. package/dist-client/component/approval-line-items-editor.js +67 -3
  8. package/dist-client/component/approval-line-items-editor.js.map +1 -1
  9. package/dist-client/component/approval-line-selector.d.ts +2 -0
  10. package/dist-client/component/approval-line-selector.js +40 -9
  11. package/dist-client/component/approval-line-selector.js.map +1 -1
  12. package/dist-client/component/approval-line-view.d.ts +15 -0
  13. package/dist-client/component/approval-line-view.js +177 -41
  14. package/dist-client/component/approval-line-view.js.map +1 -1
  15. package/dist-client/component/assignees-editor-popup.d.ts +2 -0
  16. package/dist-client/component/assignees-editor-popup.js +27 -8
  17. package/dist-client/component/assignees-editor-popup.js.map +1 -1
  18. package/dist-client/component/department-selector.d.ts +2 -0
  19. package/dist-client/component/department-selector.js +27 -8
  20. package/dist-client/component/department-selector.js.map +1 -1
  21. package/dist-client/component/recipients-editor-popup.d.ts +2 -0
  22. package/dist-client/component/recipients-editor-popup.js +27 -8
  23. package/dist-client/component/recipients-editor-popup.js.map +1 -1
  24. package/dist-client/filters-form/ox-filter-department-object.js +11 -1
  25. package/dist-client/filters-form/ox-filter-department-object.js.map +1 -1
  26. package/dist-client/pages/approval-line/approval-line-list-page.d.ts +121 -0
  27. package/dist-client/pages/approval-line/approval-line-list-page.js +583 -0
  28. package/dist-client/pages/approval-line/approval-line-list-page.js.map +1 -0
  29. package/dist-client/pages/approval-line/common-approval-line-templates-page.d.ts +0 -2
  30. package/dist-client/pages/approval-line/common-approval-line-templates-page.js +27 -11
  31. package/dist-client/pages/approval-line/common-approval-line-templates-page.js.map +1 -1
  32. package/dist-client/pages/approval-line/my-approval-line-templates-page.d.ts +0 -2
  33. package/dist-client/pages/approval-line/my-approval-line-templates-page.js +33 -9
  34. package/dist-client/pages/approval-line/my-approval-line-templates-page.js.map +1 -1
  35. package/dist-client/pages/department/department-list-page.d.ts +0 -2
  36. package/dist-client/pages/department/department-list-page.js +2 -6
  37. package/dist-client/pages/department/department-list-page.js.map +1 -1
  38. package/dist-client/pages/department/department-tree-page.d.ts +0 -10
  39. package/dist-client/pages/department/department-tree-page.js +35 -16
  40. package/dist-client/pages/department/department-tree-page.js.map +1 -1
  41. package/dist-client/pages/employee/employee-list-page.d.ts +0 -2
  42. package/dist-client/pages/employee/employee-list-page.js +2 -6
  43. package/dist-client/pages/employee/employee-list-page.js.map +1 -1
  44. package/dist-client/route.d.ts +1 -1
  45. package/dist-client/route.js +9 -0
  46. package/dist-client/route.js.map +1 -1
  47. package/dist-client/tsconfig.tsbuildinfo +1 -1
  48. package/dist-client/types/approval-line.d.ts +64 -0
  49. package/dist-client/types/approval-line.js +67 -0
  50. package/dist-client/types/approval-line.js.map +1 -1
  51. package/dist-server/service/approval-line/approval-line-item.d.ts +40 -0
  52. package/dist-server/service/approval-line/approval-line-item.js +42 -2
  53. package/dist-server/service/approval-line/approval-line-item.js.map +1 -1
  54. package/dist-server/service/approval-line/approval-line-mutation.js +24 -33
  55. package/dist-server/service/approval-line/approval-line-mutation.js.map +1 -1
  56. package/dist-server/service/approval-line/approval-line-query.js +36 -21
  57. package/dist-server/service/approval-line/approval-line-query.js.map +1 -1
  58. package/dist-server/service/employee/employee-query.d.ts +25 -0
  59. package/dist-server/service/employee/employee-query.js +41 -0
  60. package/dist-server/service/employee/employee-query.js.map +1 -1
  61. package/dist-server/service/employee/index.d.ts +1 -0
  62. package/dist-server/service/employee/index.js +3 -0
  63. package/dist-server/service/employee/index.js.map +1 -1
  64. package/dist-server/service/employee/my-employee-refusal.d.ts +22 -0
  65. package/dist-server/service/employee/my-employee-refusal.js +56 -0
  66. package/dist-server/service/employee/my-employee-refusal.js.map +1 -0
  67. package/dist-server/service/employee/my-employee.d.ts +22 -0
  68. package/dist-server/service/employee/my-employee.js +43 -0
  69. package/dist-server/service/employee/my-employee.js.map +1 -0
  70. package/dist-server/tsconfig.tsbuildinfo +1 -1
  71. package/package.json +6 -6
  72. package/spec/unit/my-employee.spec.ts +102 -0
  73. package/things-factory.config.js +1 -0
  74. package/translations/en.json +44 -17
  75. package/translations/ja.json +44 -17
  76. package/translations/ko.json +46 -19
  77. package/translations/ms.json +43 -16
  78. package/translations/zh.json +43 -16
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ApprovalLineQuery = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const type_graphql_1 = require("type-graphql");
6
+ const my_employee_js_1 = require("../employee/my-employee.js");
6
7
  const typeorm_1 = require("typeorm");
7
8
  const shell_1 = require("@things-factory/shell");
8
9
  const auth_base_1 = require("@things-factory/auth-base");
@@ -37,7 +38,7 @@ async function getModel(approvalLine, context) {
37
38
  var approvalLineItemList = [];
38
39
  for (let item of model) {
39
40
  /* deprecated "value", use approver */
40
- var { type, value, approver } = item;
41
+ var { type, value, approver, participation, notifyAfter } = item;
41
42
  var id = approver?.id || value;
42
43
  approver = null;
43
44
  switch (type) {
@@ -57,7 +58,21 @@ async function getModel(approvalLine, context) {
57
58
  default:
58
59
  continue;
59
60
  }
60
- approvalLineItemList.push({ type, approver });
61
+ /*
62
+ * ── 같은 결함이 세 겹이었다 ──────────────────────────────────────────────
63
+ * 결재선 항목의 칸을 하나씩 옮겨 적는 자리가 셋이고, 셋 다 `{ type, approver }` 만 알았다.
64
+ *
65
+ * 화면 편집기 값을 모을 때 고쳐도 저장되지 않았다
66
+ * 서버 쓰기 getModelValue 저장할 때 버렸다
67
+ * 서버 읽기 여기 저장된 것을 읽을 때 버렸다
68
+ *
69
+ * 그래서 앞의 둘을 고친 뒤에도 읽으면 여전히 `null` 이었다. **한 겹만 고치면 고쳐진 것으로
70
+ * 보이지 않고, 세 겹을 다 고쳐야 비로소 값이 산다.**
71
+ *
72
+ * `ApprovalLineItem` 에 칸을 더하면 이 셋을 함께 고쳐야 한다. 어느 하나를 빼먹으면 오류 없이
73
+ * 값만 사라진다 — 화면에서는 고쳐지고, 다시 읽으면 없다.
74
+ */
75
+ approvalLineItemList.push({ type, approver, participation, notifyAfter });
61
76
  }
62
77
  return approvalLineItemList;
63
78
  }
@@ -80,43 +95,43 @@ let ApprovalLineQuery = class ApprovalLineQuery {
80
95
  return { items, total };
81
96
  }
82
97
  async approvalLineReferences(params, context) {
83
- const { domain, user } = context.state;
84
- const employees = await (0, shell_1.getRepository)(employee_1.Employee).findBy({
85
- domain: { id: domain.id },
86
- user: { id: user.id }
87
- });
98
+ const { domain } = context.state;
99
+ /* 「이 사용자의 사원」을 여기서 다시 읽지 않는다 — 판정은 한 자리다(§`my-employee.ts`). */
100
+ const mine = await (0, my_employee_js_1.myEmployeeIds)(context);
88
101
  const queryBuilder = (0, shell_1.getQueryBuilderFromListParams)({
89
102
  domain,
90
103
  params,
91
104
  repository: await (0, shell_1.getRepository)(approval_line_1.ApprovalLine),
92
105
  searchables: ['name', 'description']
93
- }).andWhere(employees.length > 0
106
+ }).andWhere(mine.length
94
107
  ? new typeorm_1.Brackets(qb => {
95
108
  qb.where({ ownerType: 'Common' });
96
- qb.orWhere({
97
- ownerType: 'Employee',
98
- ownerValue: (0, typeorm_1.In)(employees.map(employee => employee.id))
99
- });
109
+ qb.orWhere({ ownerType: 'Employee', ownerValue: (0, typeorm_1.In)(mine) });
100
110
  })
101
111
  : { ownerType: 'Common' });
102
112
  const [items, total] = await queryBuilder.getManyAndCount();
103
113
  return { items, total };
104
114
  }
105
115
  async myApprovalLines(params, context) {
106
- const { domain, user } = context.state;
107
- const employees = await (0, shell_1.getRepository)(employee_1.Employee).findBy({
108
- domain: { id: domain.id },
109
- user: { id: user.id }
110
- });
116
+ const { domain } = context.state;
117
+ const mine = await (0, my_employee_js_1.myEmployeeIds)(context);
118
+ /*
119
+ * **사원 기록이 없으면 그 자리에서 빈 목록이다.** 예전에는 `In([])` 을 그대로 넘겼다 — 결과는
120
+ * 같았지만 빈 배열을 `In` 에 넣었을 때 드라이버마다 무엇이 나가는지에 기대고 있었다. 옆의
121
+ * `approvalLineReferences` 는 같은 경우를 명시적으로 갈랐다. 같은 파일에서 같은 사실을 두
122
+ * 방식으로 다루면, 한쪽만 고쳐지는 날이 온다.
123
+ *
124
+ * 그리고 **오류를 내지 않는다.** 이 목록의 참인 답이 0건이다. 「너는 이 화면을 쓸 수 없다」는
125
+ * 자격에 대한 물음이고, 그것은 목록이 아니라 사원 기록을 묻는 자리가 답한다.
126
+ */
127
+ if (!mine.length)
128
+ return { items: [], total: 0 };
111
129
  const queryBuilder = (0, shell_1.getQueryBuilderFromListParams)({
112
130
  domain,
113
131
  params,
114
132
  repository: await (0, shell_1.getRepository)(approval_line_1.ApprovalLine),
115
133
  searchables: ['name', 'description']
116
- }).andWhere({
117
- ownerType: 'Employee',
118
- ownerValue: (0, typeorm_1.In)(employees.map(employee => employee.id))
119
- });
134
+ }).andWhere({ ownerType: 'Employee', ownerValue: (0, typeorm_1.In)(mine) });
120
135
  const [items, total] = await queryBuilder.getManyAndCount();
121
136
  return { items, total };
122
137
  }
@@ -1 +1 @@
1
- {"version":3,"file":"approval-line-query.js","sourceRoot":"","sources":["../../../server/service/approval-line/approval-line-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Directive, Resolver, Query, FieldResolver, Root, Args, Arg, Ctx } from 'type-graphql'\nimport { Brackets, In } from 'typeorm'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'\nimport { Role, User } from '@things-factory/auth-base'\nimport { ApprovalLineItem, OrgMemberTargetType } from './approval-line-item'\nimport { ApprovalLine, ApprovalLineOwner, ApprovalLineOwnerType } from './approval-line'\nimport { ApprovalLineList } from './approval-line-type'\nimport { Employee } from '../employee/employee'\nimport { Department } from '../department/department'\n\nasync function getOwnerValue(approvalLine: ApprovalLine, context: ResolverContext) {\n const { domain } = context.state\n const { ownerType, ownerValue } = approvalLine\n\n if (!ownerType || !ownerValue) {\n /* ownerType이 클리어되거나, owner가 지정되지 않았다면, 클리어시킨다. */\n return null\n }\n\n var ownerObject\n\n switch (ownerType) {\n case ApprovalLineOwnerType.Employee:\n ownerObject = await getRepository(Employee).findOneBy({ domain: { id: domain.id }, id: ownerValue })\n break\n default:\n return null\n }\n\n return ownerObject\n}\n\nasync function getModel(approvalLine: ApprovalLine, context: ResolverContext): Promise<ApprovalLineItem[]> {\n const { domain } = context.state\n const { model } = approvalLine\n\n if (!model || !(model instanceof Array)) {\n return null\n }\n\n var approvalLineItemList = []\n\n for (let item of model) {\n /* deprecated \"value\", use approver */\n var { type, value, approver } = item\n var id = approver?.id || value\n approver = null\n\n switch (type) {\n case OrgMemberTargetType.Employee:\n approver = id && (await getRepository(Employee).findOneBy({ domain: { id: domain.id }, id }))\n break\n case OrgMemberTargetType.Department:\n approver = id && (await getRepository(Department).findOneBy({ domain: { id: domain.id }, id }))\n break\n case OrgMemberTargetType.Role:\n approver = id && (await getRepository(Role).findOneBy({ domain: { id: domain.id }, id }))\n break\n case OrgMemberTargetType.Myself:\n case OrgMemberTargetType.MyDepartment:\n case OrgMemberTargetType.MySupervisor:\n break\n default:\n continue\n }\n\n approvalLineItemList.push({ type, approver })\n }\n\n return approvalLineItemList\n}\n\n@Resolver(ApprovalLine)\nexport class ApprovalLineQuery {\n @Query(returns => ApprovalLine!, { nullable: true, description: 'To fetch a approval line' })\n async approvalLine(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<ApprovalLine> {\n const { domain } = context.state\n\n return await getRepository(ApprovalLine).findOne({\n where: { domain: { id: domain.id }, id }\n })\n }\n\n @Directive('@privilege(category: \"organization\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ApprovalLineList, { description: 'To fetch multiple approval lines' })\n async approvalLines(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<ApprovalLineList> {\n const { domain } = context.state\n\n const queryBuilder = getQueryBuilderFromListParams({\n domain,\n params,\n repository: await getRepository(ApprovalLine),\n searchables: ['name', 'description']\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @Query(returns => ApprovalLineList, { description: 'To fetch referable approval lines for the user' })\n async approvalLineReferences(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<ApprovalLineList> {\n const { domain, user } = context.state\n const employees = await getRepository(Employee).findBy({\n domain: { id: domain.id },\n user: { id: user.id }\n })\n\n const queryBuilder = getQueryBuilderFromListParams({\n domain,\n params,\n repository: await getRepository(ApprovalLine),\n searchables: ['name', 'description']\n }).andWhere(\n employees.length > 0\n ? new Brackets(qb => {\n qb.where({ ownerType: 'Common' })\n qb.orWhere({\n ownerType: 'Employee',\n ownerValue: In(employees.map(employee => employee.id))\n })\n })\n : { ownerType: 'Common' }\n )\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @Query(returns => ApprovalLineList, { description: 'To fetch approval lines only for to the user' })\n async myApprovalLines(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<ApprovalLineList> {\n const { domain, user } = context.state\n const employees = await getRepository(Employee).findBy({\n domain: { id: domain.id },\n user: { id: user.id }\n })\n\n const queryBuilder = getQueryBuilderFromListParams({\n domain,\n params,\n repository: await getRepository(ApprovalLine),\n searchables: ['name', 'description']\n }).andWhere({\n ownerType: 'Employee',\n ownerValue: In(employees.map(employee => employee.id))\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @Query(returns => ApprovalLineList, { description: 'To fetch common approval lines' })\n async commonApprovalLines(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<ApprovalLineList> {\n const { domain, user } = context.state\n\n const queryBuilder = getQueryBuilderFromListParams({\n domain,\n params,\n repository: await getRepository(ApprovalLine),\n searchables: ['name', 'description']\n }).andWhere({\n ownerType: 'Common'\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @FieldResolver(type => [ApprovalLineItem])\n async model(@Root() approvalLine: ApprovalLine, @Ctx() context: ResolverContext): Promise<ApprovalLineItem[]> {\n return await getModel(approvalLine, context)\n }\n\n @FieldResolver(type => ApprovalLineOwner)\n async owner(@Root() approvalLine: ApprovalLine, @Ctx() context: ResolverContext): Promise<ApprovalLineOwner> {\n return await getOwnerValue(approvalLine, context)\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() approvalLine: ApprovalLine): Promise<Domain> {\n return await getRepository(Domain).findOneBy({ id: approvalLine.domainId })\n }\n\n @FieldResolver(type => User)\n async updater(@Root() approvalLine: ApprovalLine): Promise<User> {\n return await getRepository(User).findOneBy({ id: approvalLine.updaterId })\n }\n\n @FieldResolver(type => User)\n async creator(@Root() approvalLine: ApprovalLine): Promise<User> {\n return await getRepository(User).findOneBy({ id: approvalLine.creatorId })\n }\n}\n"]}
1
+ {"version":3,"file":"approval-line-query.js","sourceRoot":"","sources":["../../../server/service/approval-line/approval-line-query.ts"],"names":[],"mappings":";;;;AAAA,+CAA8F;AAC9F,+DAA0D;AAC1D,qCAAsC;AACtC,iDAAuG;AACvG,yDAAsD;AACtD,6DAA4E;AAC5E,mDAAwF;AACxF,6DAAuD;AACvD,mDAA+C;AAC/C,yDAAqD;AAErD,KAAK,UAAU,aAAa,CAAC,YAA0B,EAAE,OAAwB;IAC/E,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAChC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,YAAY,CAAA;IAE9C,IAAI,CAAC,SAAS,IAAI,CAAC,UAAU,EAAE,CAAC;QAC9B,kDAAkD;QAClD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,WAAW,CAAA;IAEf,QAAQ,SAAS,EAAE,CAAC;QAClB,KAAK,qCAAqB,CAAC,QAAQ;YACjC,WAAW,GAAG,MAAM,IAAA,qBAAa,EAAC,mBAAQ,CAAC,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,CAAA;YACpG,MAAK;QACP;YACE,OAAO,IAAI,CAAA;IACf,CAAC;IAED,OAAO,WAAW,CAAA;AACpB,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,YAA0B,EAAE,OAAwB;IAC1E,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAChC,MAAM,EAAE,KAAK,EAAE,GAAG,YAAY,CAAA;IAE9B,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,EAAE,CAAC;QACxC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,oBAAoB,GAAG,EAAE,CAAA;IAE7B,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,sCAAsC;QACtC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,GAAG,IAAI,CAAA;QAChE,IAAI,EAAE,GAAG,QAAQ,EAAE,EAAE,IAAI,KAAK,CAAA;QAC9B,QAAQ,GAAG,IAAI,CAAA;QAEf,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,wCAAmB,CAAC,QAAQ;gBAC/B,QAAQ,GAAG,EAAE,IAAI,CAAC,MAAM,IAAA,qBAAa,EAAC,mBAAQ,CAAC,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAA;gBAC7F,MAAK;YACP,KAAK,wCAAmB,CAAC,UAAU;gBACjC,QAAQ,GAAG,EAAE,IAAI,CAAC,MAAM,IAAA,qBAAa,EAAC,uBAAU,CAAC,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAA;gBAC/F,MAAK;YACP,KAAK,wCAAmB,CAAC,IAAI;gBAC3B,QAAQ,GAAG,EAAE,IAAI,CAAC,MAAM,IAAA,qBAAa,EAAC,gBAAI,CAAC,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAA;gBACzF,MAAK;YACP,KAAK,wCAAmB,CAAC,MAAM,CAAC;YAChC,KAAK,wCAAmB,CAAC,YAAY,CAAC;YACtC,KAAK,wCAAmB,CAAC,YAAY;gBACnC,MAAK;YACP;gBACE,SAAQ;QACZ,CAAC;QAED;;;;;;;;;;;;;WAaG;QACH,oBAAoB,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,CAAA;IAC3E,CAAC;IAED,OAAO,oBAAoB,CAAA;AAC7B,CAAC;AAGM,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAEtB,AAAN,KAAK,CAAC,YAAY,CAAY,EAAU,EAAS,OAAwB;QACvE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAEhC,OAAO,MAAM,IAAA,qBAAa,EAAC,4BAAY,CAAC,CAAC,OAAO,CAAC;YAC/C,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE;SACzC,CAAC,CAAA;IACJ,CAAC;IAIK,AAAN,KAAK,CAAC,aAAa,CACQ,MAAiB,EACnC,OAAwB;QAE/B,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAEhC,MAAM,YAAY,GAAG,IAAA,qCAA6B,EAAC;YACjD,MAAM;YACN,MAAM;YACN,UAAU,EAAE,MAAM,IAAA,qBAAa,EAAC,4BAAY,CAAC;YAC7C,WAAW,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC;SACrC,CAAC,CAAA;QAEF,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,YAAY,CAAC,eAAe,EAAE,CAAA;QAE3D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;IACzB,CAAC;IAGK,AAAN,KAAK,CAAC,sBAAsB,CACD,MAAiB,EACnC,OAAwB;QAE/B,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAChC,gEAAgE;QAChE,MAAM,IAAI,GAAG,MAAM,IAAA,8BAAa,EAAC,OAAO,CAAC,CAAA;QAEzC,MAAM,YAAY,GAAG,IAAA,qCAA6B,EAAC;YACjD,MAAM;YACN,MAAM;YACN,UAAU,EAAE,MAAM,IAAA,qBAAa,EAAC,4BAAY,CAAC;YAC7C,WAAW,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC;SACrC,CAAC,CAAC,QAAQ,CACT,IAAI,CAAC,MAAM;YACT,CAAC,CAAC,IAAI,kBAAQ,CAAC,EAAE,CAAC,EAAE;gBAChB,EAAE,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAA;gBACjC,EAAE,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,IAAA,YAAE,EAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAC7D,CAAC,CAAC;YACJ,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,CAC5B,CAAA;QAED,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,YAAY,CAAC,eAAe,EAAE,CAAA;QAE3D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;IACzB,CAAC;IAGK,AAAN,KAAK,CAAC,eAAe,CACM,MAAiB,EACnC,OAAwB;QAE/B,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAChC,MAAM,IAAI,GAAG,MAAM,IAAA,8BAAa,EAAC,OAAO,CAAC,CAAA;QAEzC;;;;;;;;WAQG;QACH,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAA;QAEhD,MAAM,YAAY,GAAG,IAAA,qCAA6B,EAAC;YACjD,MAAM;YACN,MAAM;YACN,UAAU,EAAE,MAAM,IAAA,qBAAa,EAAC,4BAAY,CAAC;YAC7C,WAAW,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC;SACrC,CAAC,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,IAAA,YAAE,EAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAE5D,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,YAAY,CAAC,eAAe,EAAE,CAAA;QAE3D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;IACzB,CAAC;IAGK,AAAN,KAAK,CAAC,mBAAmB,CACE,MAAiB,EACnC,OAAwB;QAE/B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAEtC,MAAM,YAAY,GAAG,IAAA,qCAA6B,EAAC;YACjD,MAAM;YACN,MAAM;YACN,UAAU,EAAE,MAAM,IAAA,qBAAa,EAAC,4BAAY,CAAC;YAC7C,WAAW,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC;SACrC,CAAC,CAAC,QAAQ,CAAC;YACV,SAAS,EAAE,QAAQ;SACpB,CAAC,CAAA;QAEF,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,YAAY,CAAC,eAAe,EAAE,CAAA;QAE3D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;IACzB,CAAC;IAGK,AAAN,KAAK,CAAC,KAAK,CAAS,YAA0B,EAAS,OAAwB;QAC7E,OAAO,MAAM,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAA;IAC9C,CAAC;IAGK,AAAN,KAAK,CAAC,KAAK,CAAS,YAA0B,EAAS,OAAwB;QAC7E,OAAO,MAAM,aAAa,CAAC,YAAY,EAAE,OAAO,CAAC,CAAA;IACnD,CAAC;IAGK,AAAN,KAAK,CAAC,MAAM,CAAS,YAA0B;QAC7C,OAAO,MAAM,IAAA,qBAAa,EAAC,cAAM,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAA;IAC7E,CAAC;IAGK,AAAN,KAAK,CAAC,OAAO,CAAS,YAA0B;QAC9C,OAAO,MAAM,IAAA,qBAAa,EAAC,gBAAI,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,YAAY,CAAC,SAAS,EAAE,CAAC,CAAA;IAC5E,CAAC;IAGK,AAAN,KAAK,CAAC,OAAO,CAAS,YAA0B;QAC9C,OAAO,MAAM,IAAA,qBAAa,EAAC,gBAAI,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,YAAY,CAAC,SAAS,EAAE,CAAC,CAAA;IAC5E,CAAC;CACF,CAAA;AAtIY,8CAAiB;AAEtB;IADL,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,4BAAa,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,0BAA0B,EAAE,CAAC;IACzE,mBAAA,IAAA,kBAAG,EAAC,IAAI,CAAC,CAAA;IAAc,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;qDAM/C;AAIK;IAFL,IAAA,wBAAS,EAAC,oFAAoF,CAAC;IAC/F,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,qCAAgB,EAAE,EAAE,WAAW,EAAE,kCAAkC,EAAE,CAAC;IAErF,mBAAA,IAAA,mBAAI,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAS,CAAC,CAAA;IACvB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAD2B,iBAAS;;sDAe3C;AAGK;IADL,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,qCAAgB,EAAE,EAAE,WAAW,EAAE,gDAAgD,EAAE,CAAC;IAEnG,mBAAA,IAAA,mBAAI,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAS,CAAC,CAAA;IACvB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAD2B,iBAAS;;+DAwB3C;AAGK;IADL,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,qCAAgB,EAAE,EAAE,WAAW,EAAE,8CAA8C,EAAE,CAAC;IAEjG,mBAAA,IAAA,mBAAI,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAS,CAAC,CAAA;IACvB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAD2B,iBAAS;;wDA2B3C;AAGK;IADL,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,qCAAgB,EAAE,EAAE,WAAW,EAAE,gCAAgC,EAAE,CAAC;IAEnF,mBAAA,IAAA,mBAAI,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAS,CAAC,CAAA;IACvB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAD2B,iBAAS;;4DAiB3C;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,qCAAgB,CAAC,CAAC;IAC7B,mBAAA,IAAA,mBAAI,GAAE,CAAA;IAA8B,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAApB,4BAAY;;8CAE7C;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,iCAAiB,CAAC;IAC5B,mBAAA,IAAA,mBAAI,GAAE,CAAA;IAA8B,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAApB,4BAAY;;8CAE7C;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,cAAM,CAAC;IAChB,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAe,4BAAY;;+CAE9C;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,CAAC;IACb,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAe,4BAAY;;gDAE/C;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,CAAC;IACb,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAe,4BAAY;;gDAE/C;4BArIU,iBAAiB;IAD7B,IAAA,uBAAQ,EAAC,4BAAY,CAAC;GACV,iBAAiB,CAsI7B","sourcesContent":["import { Directive, Resolver, Query, FieldResolver, Root, Args, Arg, Ctx } from 'type-graphql'\nimport { myEmployeeIds } from '../employee/my-employee.js'\nimport { Brackets, In } from 'typeorm'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'\nimport { Role, User } from '@things-factory/auth-base'\nimport { ApprovalLineItem, OrgMemberTargetType } from './approval-line-item'\nimport { ApprovalLine, ApprovalLineOwner, ApprovalLineOwnerType } from './approval-line'\nimport { ApprovalLineList } from './approval-line-type'\nimport { Employee } from '../employee/employee'\nimport { Department } from '../department/department'\n\nasync function getOwnerValue(approvalLine: ApprovalLine, context: ResolverContext) {\n const { domain } = context.state\n const { ownerType, ownerValue } = approvalLine\n\n if (!ownerType || !ownerValue) {\n /* ownerType이 클리어되거나, owner가 지정되지 않았다면, 클리어시킨다. */\n return null\n }\n\n var ownerObject\n\n switch (ownerType) {\n case ApprovalLineOwnerType.Employee:\n ownerObject = await getRepository(Employee).findOneBy({ domain: { id: domain.id }, id: ownerValue })\n break\n default:\n return null\n }\n\n return ownerObject\n}\n\nasync function getModel(approvalLine: ApprovalLine, context: ResolverContext): Promise<ApprovalLineItem[]> {\n const { domain } = context.state\n const { model } = approvalLine\n\n if (!model || !(model instanceof Array)) {\n return null\n }\n\n var approvalLineItemList = []\n\n for (let item of model) {\n /* deprecated \"value\", use approver */\n var { type, value, approver, participation, notifyAfter } = item\n var id = approver?.id || value\n approver = null\n\n switch (type) {\n case OrgMemberTargetType.Employee:\n approver = id && (await getRepository(Employee).findOneBy({ domain: { id: domain.id }, id }))\n break\n case OrgMemberTargetType.Department:\n approver = id && (await getRepository(Department).findOneBy({ domain: { id: domain.id }, id }))\n break\n case OrgMemberTargetType.Role:\n approver = id && (await getRepository(Role).findOneBy({ domain: { id: domain.id }, id }))\n break\n case OrgMemberTargetType.Myself:\n case OrgMemberTargetType.MyDepartment:\n case OrgMemberTargetType.MySupervisor:\n break\n default:\n continue\n }\n\n /*\n * ── 같은 결함이 세 겹이었다 ──────────────────────────────────────────────\n * 결재선 항목의 칸을 하나씩 옮겨 적는 자리가 셋이고, 셋 다 `{ type, approver }` 만 알았다.\n *\n * 화면 편집기 값을 모을 때 고쳐도 저장되지 않았다\n * 서버 쓰기 getModelValue 저장할 때 버렸다\n * 서버 읽기 여기 저장된 것을 읽을 때 버렸다\n *\n * 그래서 앞의 둘을 고친 뒤에도 읽으면 여전히 `null` 이었다. **한 겹만 고치면 고쳐진 것으로\n * 보이지 않고, 세 겹을 다 고쳐야 비로소 값이 산다.**\n *\n * `ApprovalLineItem` 에 칸을 더하면 이 셋을 함께 고쳐야 한다. 어느 하나를 빼먹으면 오류 없이\n * 값만 사라진다 — 화면에서는 고쳐지고, 다시 읽으면 없다.\n */\n approvalLineItemList.push({ type, approver, participation, notifyAfter })\n }\n\n return approvalLineItemList\n}\n\n@Resolver(ApprovalLine)\nexport class ApprovalLineQuery {\n @Query(returns => ApprovalLine!, { nullable: true, description: 'To fetch a approval line' })\n async approvalLine(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<ApprovalLine> {\n const { domain } = context.state\n\n return await getRepository(ApprovalLine).findOne({\n where: { domain: { id: domain.id }, id }\n })\n }\n\n @Directive('@privilege(category: \"organization\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ApprovalLineList, { description: 'To fetch multiple approval lines' })\n async approvalLines(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<ApprovalLineList> {\n const { domain } = context.state\n\n const queryBuilder = getQueryBuilderFromListParams({\n domain,\n params,\n repository: await getRepository(ApprovalLine),\n searchables: ['name', 'description']\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @Query(returns => ApprovalLineList, { description: 'To fetch referable approval lines for the user' })\n async approvalLineReferences(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<ApprovalLineList> {\n const { domain } = context.state\n /* 「이 사용자의 사원」을 여기서 다시 읽지 않는다 — 판정은 한 자리다(§`my-employee.ts`). */\n const mine = await myEmployeeIds(context)\n\n const queryBuilder = getQueryBuilderFromListParams({\n domain,\n params,\n repository: await getRepository(ApprovalLine),\n searchables: ['name', 'description']\n }).andWhere(\n mine.length\n ? new Brackets(qb => {\n qb.where({ ownerType: 'Common' })\n qb.orWhere({ ownerType: 'Employee', ownerValue: In(mine) })\n })\n : { ownerType: 'Common' }\n )\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @Query(returns => ApprovalLineList, { description: 'To fetch approval lines only for to the user' })\n async myApprovalLines(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<ApprovalLineList> {\n const { domain } = context.state\n const mine = await myEmployeeIds(context)\n\n /*\n * **사원 기록이 없으면 그 자리에서 빈 목록이다.** 예전에는 `In([])` 을 그대로 넘겼다 — 결과는\n * 같았지만 빈 배열을 `In` 에 넣었을 때 드라이버마다 무엇이 나가는지에 기대고 있었다. 옆의\n * `approvalLineReferences` 는 같은 경우를 명시적으로 갈랐다. 같은 파일에서 같은 사실을 두\n * 방식으로 다루면, 한쪽만 고쳐지는 날이 온다.\n *\n * 그리고 **오류를 내지 않는다.** 이 목록의 참인 답이 0건이다. 「너는 이 화면을 쓸 수 없다」는\n * 자격에 대한 물음이고, 그것은 목록이 아니라 사원 기록을 묻는 자리가 답한다.\n */\n if (!mine.length) return { items: [], total: 0 }\n\n const queryBuilder = getQueryBuilderFromListParams({\n domain,\n params,\n repository: await getRepository(ApprovalLine),\n searchables: ['name', 'description']\n }).andWhere({ ownerType: 'Employee', ownerValue: In(mine) })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @Query(returns => ApprovalLineList, { description: 'To fetch common approval lines' })\n async commonApprovalLines(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<ApprovalLineList> {\n const { domain, user } = context.state\n\n const queryBuilder = getQueryBuilderFromListParams({\n domain,\n params,\n repository: await getRepository(ApprovalLine),\n searchables: ['name', 'description']\n }).andWhere({\n ownerType: 'Common'\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @FieldResolver(type => [ApprovalLineItem])\n async model(@Root() approvalLine: ApprovalLine, @Ctx() context: ResolverContext): Promise<ApprovalLineItem[]> {\n return await getModel(approvalLine, context)\n }\n\n @FieldResolver(type => ApprovalLineOwner)\n async owner(@Root() approvalLine: ApprovalLine, @Ctx() context: ResolverContext): Promise<ApprovalLineOwner> {\n return await getOwnerValue(approvalLine, context)\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() approvalLine: ApprovalLine): Promise<Domain> {\n return await getRepository(Domain).findOneBy({ id: approvalLine.domainId })\n }\n\n @FieldResolver(type => User)\n async updater(@Root() approvalLine: ApprovalLine): Promise<User> {\n return await getRepository(User).findOneBy({ id: approvalLine.updaterId })\n }\n\n @FieldResolver(type => User)\n async creator(@Root() approvalLine: ApprovalLine): Promise<User> {\n return await getRepository(User).findOneBy({ id: approvalLine.creatorId })\n }\n}\n"]}
@@ -5,6 +5,31 @@ import { Employee } from './employee';
5
5
  import { EmployeeList } from './employee-type';
6
6
  import { Department } from '../department/department';
7
7
  export declare class EmployeeQuery {
8
+ /**
9
+ * 부른 사람 자신의 사원 기록 — **권한을 붙이지 않는다.**
10
+ *
11
+ * ── 왜 필요한가 ──────────────────────────────────────────────────────────
12
+ * 「내 것」 축의 읽기와 쓰기는 이미 권한 없이 있다(`myApprovalLines` · `createMyApprovalLine` ·
13
+ * `updateMyApprovalLine`). 그 자리들이 모두 **사원 기록에 의존하는데, 그것이 있는지 물을 방법이
14
+ * 없었다.**
15
+ *
16
+ * 그래서 사원 기록이 없는 사람에게도 「내 결재선」 화면이 입력을 받았고, 저장을 누른 뒤에야
17
+ * 실패했다. 화면이 알아야 하는 것은 「지금 0건이다」가 아니라 **「너는 이 화면을 쓸 수 없다」**다.
18
+ * 그건 목록이 아니라 자격에 대한 물음이므로 답하는 자리가 따로 있어야 한다.
19
+ *
20
+ * ── 왜 권한이 없나 ──────────────────────────────────────────────────────
21
+ * 「나는 누구인가」는 권한으로 가릴 사실이 아니다. 자기 기록만 답하므로 새는 것이 없다.
22
+ * `employees` 는 `employee:query` 를 요구하는데, 그것으로는 **정작 답이 필요한 일반 사원이 물을 수
23
+ * 없다.**
24
+ *
25
+ * ── 왜 복수인가 ────────────────────────────────────────────────────────
26
+ * `Employee` 에 `(domain, user)` 유일 제약이 없다 — 유일한 것은
27
+ * `(domain, controlNo, deletedAt)` 뿐이다(`employee.ts:36`). 그래서 한 사용자가 한 도메인에서 사원
28
+ * 기록을 둘 이상 가질 수 있고, `myApprovalLines` 도 그것을 전제로 `In(...)` 을 쓴다.
29
+ *
30
+ * 단수로 두면 **없는 제약을 지어내는 것**이 된다. 비어 있으면 빈 배열이다 — 오류가 아니다.
31
+ */
32
+ myEmployees(context: ResolverContext): Promise<Employee[]>;
8
33
  employee(id: string, context: ResolverContext): Promise<Employee>;
9
34
  employees(params: ListParam, context: ResolverContext): Promise<EmployeeList>;
10
35
  photo(employee: Employee): Promise<string | undefined>;
@@ -11,6 +11,7 @@ const contact_1 = require("@things-factory/contact");
11
11
  const employee_1 = require("./employee");
12
12
  const employee_type_1 = require("./employee-type");
13
13
  const department_1 = require("../department/department");
14
+ const my_employee_js_1 = require("./my-employee.js");
14
15
  async function getContactItem(contactId, type, label, context) {
15
16
  const { domain } = context.state;
16
17
  const contact = await (0, shell_1.getRepository)(contact_1.Contact).findOne({ where: { domain: { id: domain.id }, id: contactId } });
@@ -21,6 +22,37 @@ async function getContactItem(contactId, type, label, context) {
21
22
  return items?.find(item => item.type === type && item.label === label)?.value;
22
23
  }
23
24
  let EmployeeQuery = class EmployeeQuery {
25
+ /**
26
+ * 부른 사람 자신의 사원 기록 — **권한을 붙이지 않는다.**
27
+ *
28
+ * ── 왜 필요한가 ──────────────────────────────────────────────────────────
29
+ * 「내 것」 축의 읽기와 쓰기는 이미 권한 없이 있다(`myApprovalLines` · `createMyApprovalLine` ·
30
+ * `updateMyApprovalLine`). 그 자리들이 모두 **사원 기록에 의존하는데, 그것이 있는지 물을 방법이
31
+ * 없었다.**
32
+ *
33
+ * 그래서 사원 기록이 없는 사람에게도 「내 결재선」 화면이 입력을 받았고, 저장을 누른 뒤에야
34
+ * 실패했다. 화면이 알아야 하는 것은 「지금 0건이다」가 아니라 **「너는 이 화면을 쓸 수 없다」**다.
35
+ * 그건 목록이 아니라 자격에 대한 물음이므로 답하는 자리가 따로 있어야 한다.
36
+ *
37
+ * ── 왜 권한이 없나 ──────────────────────────────────────────────────────
38
+ * 「나는 누구인가」는 권한으로 가릴 사실이 아니다. 자기 기록만 답하므로 새는 것이 없다.
39
+ * `employees` 는 `employee:query` 를 요구하는데, 그것으로는 **정작 답이 필요한 일반 사원이 물을 수
40
+ * 없다.**
41
+ *
42
+ * ── 왜 복수인가 ────────────────────────────────────────────────────────
43
+ * `Employee` 에 `(domain, user)` 유일 제약이 없다 — 유일한 것은
44
+ * `(domain, controlNo, deletedAt)` 뿐이다(`employee.ts:36`). 그래서 한 사용자가 한 도메인에서 사원
45
+ * 기록을 둘 이상 가질 수 있고, `myApprovalLines` 도 그것을 전제로 `In(...)` 을 쓴다.
46
+ *
47
+ * 단수로 두면 **없는 제약을 지어내는 것**이 된다. 비어 있으면 빈 배열이다 — 오류가 아니다.
48
+ */
49
+ async myEmployees(context) {
50
+ /*
51
+ * 조회를 여기서 다시 쓰지 않는다. 「이 사용자의 사원 기록」을 판정하는 자리는 `my-employee.ts`
52
+ * 하나다 — 그 자리가 없어서 같은 물음을 네 곳이 각자 다르게 다루던 것이 이 결함의 원인이었다.
53
+ */
54
+ return await (0, my_employee_js_1.myEmployees)(context);
55
+ }
24
56
  async employee(id, context) {
25
57
  const { domain } = context.state;
26
58
  return await (0, shell_1.getRepository)(employee_1.Employee).findOne({
@@ -121,6 +153,15 @@ let EmployeeQuery = class EmployeeQuery {
121
153
  }
122
154
  };
123
155
  exports.EmployeeQuery = EmployeeQuery;
156
+ tslib_1.__decorate([
157
+ (0, type_graphql_1.Query)(returns => [employee_1.Employee], {
158
+ description: "Fetches the caller's own employee records in this domain. Empty when the caller is not an employee."
159
+ }),
160
+ tslib_1.__param(0, (0, type_graphql_1.Ctx)()),
161
+ tslib_1.__metadata("design:type", Function),
162
+ tslib_1.__metadata("design:paramtypes", [Object]),
163
+ tslib_1.__metadata("design:returntype", Promise)
164
+ ], EmployeeQuery.prototype, "myEmployees", null);
124
165
  tslib_1.__decorate([
125
166
  (0, type_graphql_1.Directive)('@privilege(category: "employee", privilege: "query", domainOwnerGranted: true)'),
126
167
  (0, type_graphql_1.Query)(returns => employee_1.Employee, {
@@ -1 +1 @@
1
- {"version":3,"file":"employee-query.js","sourceRoot":"","sources":["../../../server/service/employee/employee-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Resolver, Query, FieldResolver, Root, Args, Arg, Ctx, Directive } from 'type-graphql'\nimport { GraphQLEmailAddress } from 'graphql-scalars'\nimport { Attachment } from '@things-factory/attachment-base'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { Contact, ContactItem, ContactField, Profile } from '@things-factory/contact'\nimport { Employee } from './employee'\nimport { EmployeeList } from './employee-type'\nimport { Department } from '../department/department'\n\nasync function getContactItem(contactId: string, type: string, label: string, context: ResolverContext) {\n const { domain } = context.state\n const contact: Contact = await getRepository(Contact).findOne({ where: { domain: { id: domain.id }, id: contactId } })\n const { items } = contact\n\n if (!items || !(items instanceof Array)) {\n return\n }\n\n return items?.find(item => item.type === type && item.label === label)?.value\n}\n\n@Resolver(Employee)\nexport class EmployeeQuery {\n @Directive('@privilege(category: \"employee\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => Employee!, {\n nullable: true,\n description:\n 'Fetches a specific employee by their unique ID. Returns the employee object if found, or null if not found.'\n })\n async employee(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Employee> {\n const { domain } = context.state\n\n return await getRepository(Employee).findOne({\n where: { domain: { id: domain.id }, id }\n })\n }\n\n @Directive('@privilege(category: \"employee\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => EmployeeList, {\n description:\n 'Fetches a list of employees based on provided query parameters. Supports searching by name, control number, and alias.'\n })\n async employees(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<EmployeeList> {\n const { domain } = context.state\n\n const queryBuilder = getQueryBuilderFromListParams({\n domain,\n params,\n repository: await getRepository(Employee),\n searchables: ['name', 'controlNo', 'alias', 'active', 'userId']\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @FieldResolver(type => String, { nullable: true })\n async photo(@Root() employee: Employee): Promise<string | undefined> {\n const attachment: Attachment = await getRepository(Attachment).findOne({\n where: {\n domain: { id: employee.domainId },\n refType: Employee.name,\n refBy: employee.id\n }\n })\n\n return attachment?.fullpath\n }\n\n @FieldResolver(type => String, { nullable: true })\n async phone(@Root() employee: Employee, @Ctx() context: ResolverContext): Promise<string> {\n if (!employee.contactId) {\n return\n }\n\n return await getContactItem(employee.contactId, ContactField.Phone, 'work', context)\n }\n\n @FieldResolver(type => String, { nullable: true })\n async address(@Root() employee: Employee, @Ctx() context: ResolverContext): Promise<string | undefined> {\n if (!employee.contactId) {\n return\n }\n\n return await getContactItem(employee.contactId, ContactField.Address, 'work', context)\n }\n\n @FieldResolver(type => GraphQLEmailAddress, { nullable: true })\n async email(@Root() employee: Employee, @Ctx() context: ResolverContext): Promise<string | undefined> {\n if (!employee.contactId) {\n return\n }\n\n return await getContactItem(employee.contactId, ContactField.Email, 'work', context)\n }\n\n @FieldResolver(type => Profile)\n async profile(@Root() employee: Employee): Promise<Profile> {\n if (!employee.contactId) {\n return\n }\n\n let contact: Contact = employee.contact\n if (!contact) {\n contact = await getRepository(Contact).findOneBy({\n id: employee.contactId\n })\n\n if (!contact) {\n return\n }\n }\n\n const { id: refBy } = contact\n const { left, top, zoom } = contact.profile || {}\n\n const attachment: Attachment = await getRepository(Attachment).findOne({\n where: {\n domain: { id: contact.domainId },\n refType: Contact.name,\n refBy\n }\n })\n\n return { left, top, zoom, picture: attachment?.fullpath }\n }\n\n @FieldResolver(type => Department)\n async department(@Root() employee: Employee): Promise<Department> {\n if (employee.departmentId) {\n return await getRepository(Department).findOneBy({ id: employee.departmentId })\n }\n }\n\n @FieldResolver(type => User)\n async user(@Root() employee: Employee): Promise<User> {\n if (employee.userId) {\n return await getRepository(User).findOneBy({ id: employee.userId })\n }\n }\n\n @FieldResolver(type => Employee)\n async supervisor(@Root() employee: Employee): Promise<Employee> {\n if (employee.supervisorId) {\n return await getRepository(Employee).findOneBy({ id: employee.supervisorId })\n }\n }\n\n @FieldResolver(type => Contact)\n async contact(@Root() employee: Employee): Promise<Contact> {\n if (employee.contactId) {\n return await getRepository(Contact).findOneBy({ id: employee.contactId })\n }\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() employee: Employee): Promise<Domain> {\n return await getRepository(Domain).findOneBy({ id: employee.domainId })\n }\n\n @FieldResolver(type => User)\n async updater(@Root() employee: Employee): Promise<User> {\n return await getRepository(User).findOneBy({ id: employee.updaterId })\n }\n\n @FieldResolver(type => User)\n async creator(@Root() employee: Employee): Promise<User> {\n return await getRepository(User).findOneBy({ id: employee.creatorId })\n }\n}\n"]}
1
+ {"version":3,"file":"employee-query.js","sourceRoot":"","sources":["../../../server/service/employee/employee-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Resolver, Query, FieldResolver, Root, Args, Arg, Ctx, Directive } from 'type-graphql'\nimport { GraphQLEmailAddress } from 'graphql-scalars'\nimport { Attachment } from '@things-factory/attachment-base'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { Contact, ContactItem, ContactField, Profile } from '@things-factory/contact'\nimport { Employee } from './employee'\nimport { EmployeeList } from './employee-type'\nimport { Department } from '../department/department'\nimport { myEmployees as myEmployeesOf } from './my-employee.js'\n\nasync function getContactItem(contactId: string, type: string, label: string, context: ResolverContext) {\n const { domain } = context.state\n const contact: Contact = await getRepository(Contact).findOne({ where: { domain: { id: domain.id }, id: contactId } })\n const { items } = contact\n\n if (!items || !(items instanceof Array)) {\n return\n }\n\n return items?.find(item => item.type === type && item.label === label)?.value\n}\n\n@Resolver(Employee)\nexport class EmployeeQuery {\n /**\n * 부른 사람 자신의 사원 기록 — **권한을 붙이지 않는다.**\n *\n * ── 왜 필요한가 ──────────────────────────────────────────────────────────\n * 「내 것」 축의 읽기와 쓰기는 이미 권한 없이 있다(`myApprovalLines` · `createMyApprovalLine` ·\n * `updateMyApprovalLine`). 그 자리들이 모두 **사원 기록에 의존하는데, 그것이 있는지 물을 방법이\n * 없었다.**\n *\n * 그래서 사원 기록이 없는 사람에게도 「내 결재선」 화면이 입력을 받았고, 저장을 누른 뒤에야\n * 실패했다. 화면이 알아야 하는 것은 「지금 0건이다」가 아니라 **「너는 이 화면을 쓸 수 없다」**다.\n * 그건 목록이 아니라 자격에 대한 물음이므로 답하는 자리가 따로 있어야 한다.\n *\n * ── 왜 권한이 없나 ──────────────────────────────────────────────────────\n * 「나는 누구인가」는 권한으로 가릴 사실이 아니다. 자기 기록만 답하므로 새는 것이 없다.\n * `employees` 는 `employee:query` 를 요구하는데, 그것으로는 **정작 답이 필요한 일반 사원이 물을 수\n * 없다.**\n *\n * ── 왜 복수인가 ────────────────────────────────────────────────────────\n * `Employee` 에 `(domain, user)` 유일 제약이 없다 — 유일한 것은\n * `(domain, controlNo, deletedAt)` 뿐이다(`employee.ts:36`). 그래서 한 사용자가 한 도메인에서 사원\n * 기록을 둘 이상 가질 수 있고, `myApprovalLines` 도 그것을 전제로 `In(...)` 을 쓴다.\n *\n * 단수로 두면 **없는 제약을 지어내는 것**이 된다. 비어 있으면 빈 배열이다 — 오류가 아니다.\n */\n @Query(returns => [Employee], {\n description: \"Fetches the caller's own employee records in this domain. Empty when the caller is not an employee.\"\n })\n async myEmployees(@Ctx() context: ResolverContext): Promise<Employee[]> {\n /*\n * 조회를 여기서 다시 쓰지 않는다. 「이 사용자의 사원 기록」을 판정하는 자리는 `my-employee.ts`\n * 하나다 — 그 자리가 없어서 같은 물음을 네 곳이 각자 다르게 다루던 것이 이 결함의 원인이었다.\n */\n return await myEmployeesOf(context)\n }\n\n @Directive('@privilege(category: \"employee\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => Employee!, {\n nullable: true,\n description:\n 'Fetches a specific employee by their unique ID. Returns the employee object if found, or null if not found.'\n })\n async employee(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Employee> {\n const { domain } = context.state\n\n return await getRepository(Employee).findOne({\n where: { domain: { id: domain.id }, id }\n })\n }\n\n @Directive('@privilege(category: \"employee\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => EmployeeList, {\n description:\n 'Fetches a list of employees based on provided query parameters. Supports searching by name, control number, and alias.'\n })\n async employees(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<EmployeeList> {\n const { domain } = context.state\n\n const queryBuilder = getQueryBuilderFromListParams({\n domain,\n params,\n repository: await getRepository(Employee),\n searchables: ['name', 'controlNo', 'alias', 'active', 'userId']\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @FieldResolver(type => String, { nullable: true })\n async photo(@Root() employee: Employee): Promise<string | undefined> {\n const attachment: Attachment = await getRepository(Attachment).findOne({\n where: {\n domain: { id: employee.domainId },\n refType: Employee.name,\n refBy: employee.id\n }\n })\n\n return attachment?.fullpath\n }\n\n @FieldResolver(type => String, { nullable: true })\n async phone(@Root() employee: Employee, @Ctx() context: ResolverContext): Promise<string> {\n if (!employee.contactId) {\n return\n }\n\n return await getContactItem(employee.contactId, ContactField.Phone, 'work', context)\n }\n\n @FieldResolver(type => String, { nullable: true })\n async address(@Root() employee: Employee, @Ctx() context: ResolverContext): Promise<string | undefined> {\n if (!employee.contactId) {\n return\n }\n\n return await getContactItem(employee.contactId, ContactField.Address, 'work', context)\n }\n\n @FieldResolver(type => GraphQLEmailAddress, { nullable: true })\n async email(@Root() employee: Employee, @Ctx() context: ResolverContext): Promise<string | undefined> {\n if (!employee.contactId) {\n return\n }\n\n return await getContactItem(employee.contactId, ContactField.Email, 'work', context)\n }\n\n @FieldResolver(type => Profile)\n async profile(@Root() employee: Employee): Promise<Profile> {\n if (!employee.contactId) {\n return\n }\n\n let contact: Contact = employee.contact\n if (!contact) {\n contact = await getRepository(Contact).findOneBy({\n id: employee.contactId\n })\n\n if (!contact) {\n return\n }\n }\n\n const { id: refBy } = contact\n const { left, top, zoom } = contact.profile || {}\n\n const attachment: Attachment = await getRepository(Attachment).findOne({\n where: {\n domain: { id: contact.domainId },\n refType: Contact.name,\n refBy\n }\n })\n\n return { left, top, zoom, picture: attachment?.fullpath }\n }\n\n @FieldResolver(type => Department)\n async department(@Root() employee: Employee): Promise<Department> {\n if (employee.departmentId) {\n return await getRepository(Department).findOneBy({ id: employee.departmentId })\n }\n }\n\n @FieldResolver(type => User)\n async user(@Root() employee: Employee): Promise<User> {\n if (employee.userId) {\n return await getRepository(User).findOneBy({ id: employee.userId })\n }\n }\n\n @FieldResolver(type => Employee)\n async supervisor(@Root() employee: Employee): Promise<Employee> {\n if (employee.supervisorId) {\n return await getRepository(Employee).findOneBy({ id: employee.supervisorId })\n }\n }\n\n @FieldResolver(type => Contact)\n async contact(@Root() employee: Employee): Promise<Contact> {\n if (employee.contactId) {\n return await getRepository(Contact).findOneBy({ id: employee.contactId })\n }\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() employee: Employee): Promise<Domain> {\n return await getRepository(Domain).findOneBy({ id: employee.domainId })\n }\n\n @FieldResolver(type => User)\n async updater(@Root() employee: Employee): Promise<User> {\n return await getRepository(User).findOneBy({ id: employee.updaterId })\n }\n\n @FieldResolver(type => User)\n async creator(@Root() employee: Employee): Promise<User> {\n return await getRepository(User).findOneBy({ id: employee.creatorId })\n }\n}\n"]}
@@ -6,3 +6,4 @@ import { EmployeeHistoryEntitySubscriber } from './event-subscriber';
6
6
  export declare const entities: (typeof Employee | typeof EmployeeHistory)[];
7
7
  export declare const resolvers: (typeof EmployeeQuery | typeof EmployeeMutation)[];
8
8
  export declare const subscribers: (typeof EmployeeHistoryEntitySubscriber)[];
9
+ export * from './my-employee.js';
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.subscribers = exports.resolvers = exports.entities = void 0;
4
+ const tslib_1 = require("tslib");
4
5
  const employee_1 = require("./employee");
5
6
  const employee_history_1 = require("./employee-history");
6
7
  const employee_query_1 = require("./employee-query");
@@ -9,4 +10,6 @@ const event_subscriber_1 = require("./event-subscriber");
9
10
  exports.entities = [employee_1.Employee, employee_history_1.EmployeeHistory];
10
11
  exports.resolvers = [employee_query_1.EmployeeQuery, employee_mutation_1.EmployeeMutation];
11
12
  exports.subscribers = [event_subscriber_1.EmployeeHistoryEntitySubscriber];
13
+ /* 「이 사용자의 사원 기록」 판정 — 소비처가 다시 정하지 않게 밖으로 낸다. */
14
+ tslib_1.__exportStar(require("./my-employee.js"), exports);
12
15
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/employee/index.ts"],"names":[],"mappings":";;;AAAA,yCAAqC;AACrC,yDAAoD;AACpD,qDAAgD;AAChD,2DAAsD;AACtD,yDAAoE;AAEvD,QAAA,QAAQ,GAAG,CAAC,mBAAQ,EAAE,kCAAe,CAAC,CAAA;AACtC,QAAA,SAAS,GAAG,CAAC,8BAAa,EAAE,oCAAgB,CAAC,CAAA;AAC7C,QAAA,WAAW,GAAG,CAAC,kDAA+B,CAAC,CAAA","sourcesContent":["import { Employee } from './employee'\nimport { EmployeeHistory } from './employee-history'\nimport { EmployeeQuery } from './employee-query'\nimport { EmployeeMutation } from './employee-mutation'\nimport { EmployeeHistoryEntitySubscriber } from './event-subscriber'\n\nexport const entities = [Employee, EmployeeHistory]\nexport const resolvers = [EmployeeQuery, EmployeeMutation]\nexport const subscribers = [EmployeeHistoryEntitySubscriber]\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/employee/index.ts"],"names":[],"mappings":";;;;AAAA,yCAAqC;AACrC,yDAAoD;AACpD,qDAAgD;AAChD,2DAAsD;AACtD,yDAAoE;AAEvD,QAAA,QAAQ,GAAG,CAAC,mBAAQ,EAAE,kCAAe,CAAC,CAAA;AACtC,QAAA,SAAS,GAAG,CAAC,8BAAa,EAAE,oCAAgB,CAAC,CAAA;AAC7C,QAAA,WAAW,GAAG,CAAC,kDAA+B,CAAC,CAAA;AAE5D,gDAAgD;AAChD,2DAAgC","sourcesContent":["import { Employee } from './employee'\nimport { EmployeeHistory } from './employee-history'\nimport { EmployeeQuery } from './employee-query'\nimport { EmployeeMutation } from './employee-mutation'\nimport { EmployeeHistoryEntitySubscriber } from './event-subscriber'\n\nexport const entities = [Employee, EmployeeHistory]\nexport const resolvers = [EmployeeQuery, EmployeeMutation]\nexport const subscribers = [EmployeeHistoryEntitySubscriber]\n\n/* 「이 사용자의 사원 기록」 판정 — 소비처가 다시 정하지 않게 밖으로 낸다. */\nexport * from './my-employee.js'\n"]}
@@ -0,0 +1,22 @@
1
+ import { GraphQLError } from 'graphql';
2
+ /** 이 오류를 화면이 문장 파싱 없이 가를 수 있게 — `privilegeRejection` 과 같은 규약. */
3
+ export type EmployeeRequirement = 'no-employee' | 'ambiguous-employee';
4
+ /**
5
+ * 사원 기록이 없어서 못 한다 — **읽는 사람이 무엇을 해야 할지 알 수 있게.**
6
+ *
7
+ * 예전 문장은 `There is no employee object associated with the user.` 였다. 개발자의 말이고, 「누가
8
+ * 붙여 줄 수 있는가」가 없다. 이 오류는 프레임워크 apollo 링크를 타고 **사용자 얼굴까지** 간다.
9
+ */
10
+ export declare function noEmployeeRejection(context: any): GraphQLError;
11
+ /**
12
+ * 사원 기록이 여럿이어서 **어느 것으로 행동하는지 모른다.**
13
+ *
14
+ * 짐작해서 하나를 집지 않는다 — 그러면 개인 결재선이 엉뚱한 사원 기록에 붙고 아무 오류도 안 난다.
15
+ */
16
+ export declare function ambiguousEmployeeRejection(context: any, count: number): GraphQLError;
17
+ /**
18
+ * 여럿 중 **하나**를 고른다 — 고를 수 없으면 거절한다.
19
+ *
20
+ * 저장소를 읽는 쪽과 갈라 둔다. 「몇 개면 무엇을 하는가」가 판정이고, 「몇 개인지 읽는 것」이 배선이다.
21
+ */
22
+ export declare function theOneEmployee<T>(employees: readonly T[], context: any): T;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noEmployeeRejection = noEmployeeRejection;
4
+ exports.ambiguousEmployeeRejection = ambiguousEmployeeRejection;
5
+ exports.theOneEmployee = theOneEmployee;
6
+ const graphql_1 = require("graphql");
7
+ /**
8
+ * 번역이 없으면 영어 문장을 그대로 쓴다(§`privilege-rejection.ts` 와 같은 이유).
9
+ *
10
+ * 키는 이 패키지의 관례를 따른다 — `error.contact-information-required` 처럼 kebab-case 다.
11
+ * `auth-base` 는 띄어쓰기를 쓰는데, 한 패키지 안에서 두 관례를 섞지 않는다.
12
+ */
13
+ function localized(context, key, fallback) {
14
+ const t = typeof context?.t === 'function' ? context.t : null;
15
+ if (!t)
16
+ return fallback;
17
+ let translated;
18
+ try {
19
+ translated = t(key);
20
+ }
21
+ catch {
22
+ return fallback;
23
+ }
24
+ /* i18next 는 키를 못 찾으면 키를 그대로 돌려준다 — 그걸 사용자에게 보이지 않는다. */
25
+ return !translated || translated === key ? fallback : translated;
26
+ }
27
+ /**
28
+ * 사원 기록이 없어서 못 한다 — **읽는 사람이 무엇을 해야 할지 알 수 있게.**
29
+ *
30
+ * 예전 문장은 `There is no employee object associated with the user.` 였다. 개발자의 말이고, 「누가
31
+ * 붙여 줄 수 있는가」가 없다. 이 오류는 프레임워크 apollo 링크를 타고 **사용자 얼굴까지** 간다.
32
+ */
33
+ function noEmployeeRejection(context) {
34
+ return new graphql_1.GraphQLError(localized(context, 'error.no-employee-for-user', 'this account is not linked to an employee record — a domain administrator can link it in the employee list'), { extensions: { code: 'FORBIDDEN', requires: 'no-employee' } });
35
+ }
36
+ /**
37
+ * 사원 기록이 여럿이어서 **어느 것으로 행동하는지 모른다.**
38
+ *
39
+ * 짐작해서 하나를 집지 않는다 — 그러면 개인 결재선이 엉뚱한 사원 기록에 붙고 아무 오류도 안 난다.
40
+ */
41
+ function ambiguousEmployeeRejection(context, count) {
42
+ return new graphql_1.GraphQLError(localized(context, 'error.multiple-employees-for-user', `this account is linked to ${count} employee records, so it is unclear which one is acting — a domain administrator must leave one`), { extensions: { code: 'FORBIDDEN', requires: 'ambiguous-employee', count } });
43
+ }
44
+ /**
45
+ * 여럿 중 **하나**를 고른다 — 고를 수 없으면 거절한다.
46
+ *
47
+ * 저장소를 읽는 쪽과 갈라 둔다. 「몇 개면 무엇을 하는가」가 판정이고, 「몇 개인지 읽는 것」이 배선이다.
48
+ */
49
+ function theOneEmployee(employees, context) {
50
+ if (!employees.length)
51
+ throw noEmployeeRejection(context);
52
+ if (employees.length > 1)
53
+ throw ambiguousEmployeeRejection(context, employees.length);
54
+ return employees[0];
55
+ }
56
+ //# sourceMappingURL=my-employee-refusal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"my-employee-refusal.js","sourceRoot":"","sources":["../../../server/service/employee/my-employee-refusal.ts"],"names":[],"mappings":";;AA6DA,kDASC;AAOD,gEASC;AAQD,wCAKC;AAnGD,qCAAsC;AAmCtC;;;;;GAKG;AACH,SAAS,SAAS,CAAC,OAAY,EAAE,GAAW,EAAE,QAAgB;IAC5D,MAAM,CAAC,GAAG,OAAO,OAAO,EAAE,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC7D,IAAI,CAAC,CAAC;QAAE,OAAO,QAAQ,CAAA;IAEvB,IAAI,UAAkB,CAAA;IACtB,IAAI,CAAC;QACH,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAA;IACjB,CAAC;IACD,wDAAwD;IACxD,OAAO,CAAC,UAAU,IAAI,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAA;AAClE,CAAC;AAED;;;;;GAKG;AACH,SAAgB,mBAAmB,CAAC,OAAY;IAC9C,OAAO,IAAI,sBAAY,CACrB,SAAS,CACP,OAAO,EACP,4BAA4B,EAC5B,4GAA4G,CAC7G,EACD,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,aAA2C,EAAE,EAAE,CAC7F,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,SAAgB,0BAA0B,CAAC,OAAY,EAAE,KAAa;IACpE,OAAO,IAAI,sBAAY,CACrB,SAAS,CACP,OAAO,EACP,mCAAmC,EACnC,6BAA6B,KAAK,iGAAiG,CACpI,EACD,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,oBAAkD,EAAE,KAAK,EAAE,EAAE,CAC3G,CAAA;AACH,CAAC;AAGD;;;;GAIG;AACH,SAAgB,cAAc,CAAI,SAAuB,EAAE,OAAY;IACrE,IAAI,CAAC,SAAS,CAAC,MAAM;QAAE,MAAM,mBAAmB,CAAC,OAAO,CAAC,CAAA;IACzD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,0BAA0B,CAAC,OAAO,EAAE,SAAS,CAAC,MAAM,CAAC,CAAA;IAErF,OAAO,SAAS,CAAC,CAAC,CAAE,CAAA;AACtB,CAAC","sourcesContent":["import { GraphQLError } from 'graphql'\n\n/*\n * **「이 사용자의 사원 기록」 판정** — 순수한 부분. 저장소를 지나지 않는다.\n *\n * 배선(§`my-employee.ts`)에서 갈라 둔 이유는 시험이다. `Employee` 엔티티를 가져오면\n * `@things-factory/contact` 가 딸려 오고 그것이 import 시점에 설정을 읽는다 — 시험이 서지 않는다.\n * 그러면 **이 거절 판정을 아무 시험도 걷지 않고**, 사용자 얼굴까지 가는 문장이 아무도 안 본 채로\n * 나간다. 실제로 그 상태였다(영어 개발자 문장 하나가 네 자리에 복사돼 있었다).\n *\n * ── 같은 사실을 네 가지로 다루고 있었다 (2026-09-03, UX 레인이 겪음) ──────────\n * createMyApprovalLine 외 3곳 findOneBy + 없으면 영어 한 문장을 던진다\n * updateMyApprovalLine 검사가 없다 → `employee.id` 에서 null 참조로 터진다\n * myApprovalLines findBy + In([]) 를 그냥 쓴다\n * approvalLineReferences findBy + length > 0 으로 갈라 쓴다\n *\n * 넷이 각자 옳고 그름이 있는 것이 아니라, **판정할 자리가 없어서** 부르는 사람마다 다시 정한 것이다.\n * 그래서 검사가 있는 줄 알고 고친 사람이 터지는 자리를 남겼고, 사용자는 입력을 다 하고 나서\n * 저장할 때 실패했다.\n *\n * ── 복수가 맞다 ──────────────────────────────────────────────────────────────\n * 표의 유일 제약은 `(domain, controlNo, deletedAt)` 이다 — **`(domain, user)` 에는 없다.** 한 사용자가\n * 한 도메인에서 사원 기록을 둘 이상 가지는 것을 아무것도 막지 않는다.\n *\n * 그런데 뮤테이션 넷이 `findOneBy` 로 읽었다. 여럿이면 **드라이버가 먼저 준 하나**를 집고, 그 사람의\n * 개인 결재선이 엉뚱한 사원 기록에 붙는다. 오류는 안 난다.\n *\n * 그래서 하나여야 하는 부름은 **여럿일 때 거절한다** — 「너는 어느 사원으로 행동하는가」는 우리가\n * 짐작할 수 없는 물음이다. 지금 데이터에는 중복이 없으므로(사용자 12명, 중복 0) 도는 것이 멈추지\n * 않고, 생기는 날 조용히 틀리는 대신 말한다.\n */\n\n/** 이 오류를 화면이 문장 파싱 없이 가를 수 있게 — `privilegeRejection` 과 같은 규약. */\nexport type EmployeeRequirement = 'no-employee' | 'ambiguous-employee'\n\n/**\n * 번역이 없으면 영어 문장을 그대로 쓴다(§`privilege-rejection.ts` 와 같은 이유).\n *\n * 키는 이 패키지의 관례를 따른다 — `error.contact-information-required` 처럼 kebab-case 다.\n * `auth-base` 는 띄어쓰기를 쓰는데, 한 패키지 안에서 두 관례를 섞지 않는다.\n */\nfunction localized(context: any, key: string, fallback: string): string {\n const t = typeof context?.t === 'function' ? context.t : null\n if (!t) return fallback\n\n let translated: string\n try {\n translated = t(key)\n } catch {\n return fallback\n }\n /* i18next 는 키를 못 찾으면 키를 그대로 돌려준다 — 그걸 사용자에게 보이지 않는다. */\n return !translated || translated === key ? fallback : translated\n}\n\n/**\n * 사원 기록이 없어서 못 한다 — **읽는 사람이 무엇을 해야 할지 알 수 있게.**\n *\n * 예전 문장은 `There is no employee object associated with the user.` 였다. 개발자의 말이고, 「누가\n * 붙여 줄 수 있는가」가 없다. 이 오류는 프레임워크 apollo 링크를 타고 **사용자 얼굴까지** 간다.\n */\nexport function noEmployeeRejection(context: any): GraphQLError {\n return new GraphQLError(\n localized(\n context,\n 'error.no-employee-for-user',\n 'this account is not linked to an employee record — a domain administrator can link it in the employee list'\n ),\n { extensions: { code: 'FORBIDDEN', requires: 'no-employee' satisfies EmployeeRequirement } }\n )\n}\n\n/**\n * 사원 기록이 여럿이어서 **어느 것으로 행동하는지 모른다.**\n *\n * 짐작해서 하나를 집지 않는다 — 그러면 개인 결재선이 엉뚱한 사원 기록에 붙고 아무 오류도 안 난다.\n */\nexport function ambiguousEmployeeRejection(context: any, count: number): GraphQLError {\n return new GraphQLError(\n localized(\n context,\n 'error.multiple-employees-for-user',\n `this account is linked to ${count} employee records, so it is unclear which one is acting — a domain administrator must leave one`\n ),\n { extensions: { code: 'FORBIDDEN', requires: 'ambiguous-employee' satisfies EmployeeRequirement, count } }\n )\n}\n\n\n/**\n * 여럿 중 **하나**를 고른다 — 고를 수 없으면 거절한다.\n *\n * 저장소를 읽는 쪽과 갈라 둔다. 「몇 개면 무엇을 하는가」가 판정이고, 「몇 개인지 읽는 것」이 배선이다.\n */\nexport function theOneEmployee<T>(employees: readonly T[], context: any): T {\n if (!employees.length) throw noEmployeeRejection(context)\n if (employees.length > 1) throw ambiguousEmployeeRejection(context, employees.length)\n\n return employees[0]!\n}\n"]}
@@ -0,0 +1,22 @@
1
+ import { Employee } from './employee.js';
2
+ export * from './my-employee-refusal.js';
3
+ /**
4
+ * 이 사용자의 사원 기록들 — **없으면 빈 배열이고, 그것은 오류가 아니다.**
5
+ *
6
+ * 목록이 부른다. 「없다」는 그 목록의 참인 답이므로 여기서 던지지 않는다.
7
+ */
8
+ export declare function myEmployees(context: any): Promise<Employee[]>;
9
+ /**
10
+ * 이 사용자의 사원 **하나** — 없거나 여럿이면 거절한다.
11
+ *
12
+ * 「내 것」을 만들고 고치는 뮤테이션이 부른다. 그 자리들은 사원 하나를 소유자로 적어야 하므로,
13
+ * 답할 수 없는 상태에서 진행하면 소유자가 틀린 행이 남는다.
14
+ */
15
+ export declare function requireMyEmployee(context: any): Promise<Employee>;
16
+ /**
17
+ * 목록 조건에 쓸 사원 id 들 — **빈 배열을 `In` 에 넣지 않게.**
18
+ *
19
+ * `In([])` 이 드라이버마다 무엇을 내보내는지에 기대지 않는다. 부르는 쪽이 「비었나」를 보고 갈라
20
+ * 쓰도록 배열을 그대로 준다.
21
+ */
22
+ export declare function myEmployeeIds(context: any): Promise<string[]>;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.myEmployees = myEmployees;
4
+ exports.requireMyEmployee = requireMyEmployee;
5
+ exports.myEmployeeIds = myEmployeeIds;
6
+ const tslib_1 = require("tslib");
7
+ /*
8
+ * **「이 사용자의 사원 기록」을 읽는다** — 배선. 판정은 `my-employee-refusal.ts` 가 한다.
9
+ */
10
+ const shell_1 = require("@things-factory/shell");
11
+ const employee_js_1 = require("./employee.js");
12
+ const my_employee_refusal_js_1 = require("./my-employee-refusal.js");
13
+ tslib_1.__exportStar(require("./my-employee-refusal.js"), exports);
14
+ /**
15
+ * 이 사용자의 사원 기록들 — **없으면 빈 배열이고, 그것은 오류가 아니다.**
16
+ *
17
+ * 목록이 부른다. 「없다」는 그 목록의 참인 답이므로 여기서 던지지 않는다.
18
+ */
19
+ async function myEmployees(context) {
20
+ const { domain, user, tx } = context?.state ?? {};
21
+ if (!domain?.id || !user?.id)
22
+ return [];
23
+ return await (0, shell_1.getRepository)(employee_js_1.Employee, tx).findBy({ domain: { id: domain.id }, user: { id: user.id } });
24
+ }
25
+ /**
26
+ * 이 사용자의 사원 **하나** — 없거나 여럿이면 거절한다.
27
+ *
28
+ * 「내 것」을 만들고 고치는 뮤테이션이 부른다. 그 자리들은 사원 하나를 소유자로 적어야 하므로,
29
+ * 답할 수 없는 상태에서 진행하면 소유자가 틀린 행이 남는다.
30
+ */
31
+ async function requireMyEmployee(context) {
32
+ return (0, my_employee_refusal_js_1.theOneEmployee)(await myEmployees(context), context);
33
+ }
34
+ /**
35
+ * 목록 조건에 쓸 사원 id 들 — **빈 배열을 `In` 에 넣지 않게.**
36
+ *
37
+ * `In([])` 이 드라이버마다 무엇을 내보내는지에 기대지 않는다. 부르는 쪽이 「비었나」를 보고 갈라
38
+ * 쓰도록 배열을 그대로 준다.
39
+ */
40
+ async function myEmployeeIds(context) {
41
+ return (await myEmployees(context)).map(employee => employee.id);
42
+ }
43
+ //# sourceMappingURL=my-employee.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"my-employee.js","sourceRoot":"","sources":["../../../server/service/employee/my-employee.ts"],"names":[],"mappings":";;AAeA,kCAKC;AAQD,8CAEC;AAQD,sCAEC;;AAxCD;;GAEG;AACH,iDAAqD;AAErD,+CAAwC;AACxC,qEAAyD;AAEzD,mEAAwC;AAExC;;;;GAIG;AACI,KAAK,UAAU,WAAW,CAAC,OAAY;IAC5C,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,OAAO,EAAE,KAAK,IAAI,EAAE,CAAA;IACjD,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE;QAAE,OAAO,EAAE,CAAA;IAEvC,OAAO,MAAM,IAAA,qBAAa,EAAC,sBAAQ,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;AACvG,CAAC;AAED;;;;;GAKG;AACI,KAAK,UAAU,iBAAiB,CAAC,OAAY;IAClD,OAAO,IAAA,uCAAc,EAAC,MAAM,WAAW,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAA;AAC5D,CAAC;AAED;;;;;GAKG;AACI,KAAK,UAAU,aAAa,CAAC,OAAY;IAC9C,OAAO,CAAC,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;AAClE,CAAC","sourcesContent":["/*\n * **「이 사용자의 사원 기록」을 읽는다** — 배선. 판정은 `my-employee-refusal.ts` 가 한다.\n */\nimport { getRepository } from '@things-factory/shell'\n\nimport { Employee } from './employee.js'\nimport { theOneEmployee } from './my-employee-refusal.js'\n\nexport * from './my-employee-refusal.js'\n\n/**\n * 이 사용자의 사원 기록들 — **없으면 빈 배열이고, 그것은 오류가 아니다.**\n *\n * 목록이 부른다. 「없다」는 그 목록의 참인 답이므로 여기서 던지지 않는다.\n */\nexport async function myEmployees(context: any): Promise<Employee[]> {\n const { domain, user, tx } = context?.state ?? {}\n if (!domain?.id || !user?.id) return []\n\n return await getRepository(Employee, tx).findBy({ domain: { id: domain.id }, user: { id: user.id } })\n}\n\n/**\n * 이 사용자의 사원 **하나** — 없거나 여럿이면 거절한다.\n *\n * 「내 것」을 만들고 고치는 뮤테이션이 부른다. 그 자리들은 사원 하나를 소유자로 적어야 하므로,\n * 답할 수 없는 상태에서 진행하면 소유자가 틀린 행이 남는다.\n */\nexport async function requireMyEmployee(context: any): Promise<Employee> {\n return theOneEmployee(await myEmployees(context), context)\n}\n\n/**\n * 목록 조건에 쓸 사원 id 들 — **빈 배열을 `In` 에 넣지 않게.**\n *\n * `In([])` 이 드라이버마다 무엇을 내보내는지에 기대지 않는다. 부르는 쪽이 「비었나」를 보고 갈라\n * 쓰도록 배열을 그대로 준다.\n */\nexport async function myEmployeeIds(context: any): Promise<string[]> {\n return (await myEmployees(context)).map(employee => employee.id)\n}\n"]}