@things-factory/auth-base 10.1.4 → 10.1.7
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.
- package/CHANGELOG.md +16 -0
- package/dist-client/auth.d.ts +9 -1
- package/dist-client/auth.js +12 -3
- package/dist-client/auth.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/controllers/profile.d.ts +1 -0
- package/dist-server/controllers/signin.js +33 -12
- package/dist-server/controllers/signin.js.map +1 -1
- package/dist-server/controllers/unlock-user.js +21 -2
- package/dist-server/controllers/unlock-user.js.map +1 -1
- package/dist-server/index.js +8 -0
- package/dist-server/index.js.map +1 -1
- package/dist-server/router/auth-public-process-router.js +32 -5
- package/dist-server/router/auth-public-process-router.js.map +1 -1
- package/dist-server/service/index.d.ts +3 -1
- package/dist-server/service/index.js +15 -11
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/privilege/privilege-directive.d.ts +15 -0
- package/dist-server/service/privilege/privilege-directive.js +27 -6
- package/dist-server/service/privilege/privilege-directive.js.map +1 -1
- package/dist-server/service/role/index.d.ts +2 -1
- package/dist-server/service/role/index.js +2 -1
- package/dist-server/service/role/index.js.map +1 -1
- package/dist-server/service/role/role-mutation.d.ts +17 -1
- package/dist-server/service/role/role-mutation.js +126 -7
- package/dist-server/service/role/role-mutation.js.map +1 -1
- package/dist-server/service/role/role-privilege-query.d.ts +14 -0
- package/dist-server/service/role/role-privilege-query.js +37 -0
- package/dist-server/service/role/role-privilege-query.js.map +1 -0
- package/dist-server/service/role/role-query.d.ts +61 -1
- package/dist-server/service/role/role-query.js +114 -55
- package/dist-server/service/role/role-query.js.map +1 -1
- package/dist-server/service/role-template/index.d.ts +4 -0
- package/dist-server/service/role-template/index.js +9 -0
- package/dist-server/service/role-template/index.js.map +1 -0
- package/dist-server/service/role-template/role-template-mutation.d.ts +39 -0
- package/dist-server/service/role-template/role-template-mutation.js +124 -0
- package/dist-server/service/role-template/role-template-mutation.js.map +1 -0
- package/dist-server/service/role-template/role-template-query.d.ts +11 -0
- package/dist-server/service/role-template/role-template-query.js +79 -0
- package/dist-server/service/role-template/role-template-query.js.map +1 -0
- package/dist-server/service/role-template/role-template-types.d.ts +51 -0
- package/dist-server/service/role-template/role-template-types.js +71 -0
- package/dist-server/service/role-template/role-template-types.js.map +1 -0
- package/dist-server/service/role-template/role-template.d.ts +110 -0
- package/dist-server/service/role-template/role-template.js +129 -0
- package/dist-server/service/role-template/role-template.js.map +1 -0
- package/dist-server/service/user/user.d.ts +1 -0
- package/dist-server/service/user/user.js +55 -13
- package/dist-server/service/user/user.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/dist-server/utils/account-lock-rule.d.ts +79 -0
- package/dist-server/utils/account-lock-rule.js +114 -0
- package/dist-server/utils/account-lock-rule.js.map +1 -0
- package/dist-server/utils/lock-duration.d.ts +3 -0
- package/dist-server/utils/lock-duration.js +36 -0
- package/dist-server/utils/lock-duration.js.map +1 -0
- package/package.json +4 -4
- package/tests/account-lock-db.test.ts +216 -0
- package/tests/account-lock-rule.test.ts +141 -0
- package/tests/compiled.ts +41 -0
- package/tests/has-privilege-db.test.ts +198 -0
- package/tests/lock-recovery.test.ts +204 -0
- package/tests/password-hashing.test.ts +131 -0
- package/tests/password-persistence.test.ts +147 -0
- package/tests/permission-gate.test.ts +226 -0
- package/tests/privilege-directive.test.ts +180 -0
- package/tests/role-mutation-db.test.ts +263 -0
- package/tests/role-privileges-db.test.ts +226 -0
- package/tests/role-template-seed-db.test.ts +179 -0
- package/tests/role-template.test.ts +126 -0
- package/tests/signin-policy.test.ts +200 -0
- package/tests/token-issuance.test.ts +240 -0
- package/translations/en.json +161 -1
- package/translations/ko.json +161 -1
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RoleMutation = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
+
const typeorm_1 = require("typeorm");
|
|
5
6
|
const type_graphql_1 = require("type-graphql");
|
|
6
7
|
const shell_1 = require("@things-factory/shell");
|
|
7
8
|
const privilege_js_1 = require("../privilege/privilege.js");
|
|
@@ -9,6 +10,12 @@ const user_js_1 = require("../user/user.js");
|
|
|
9
10
|
const role_js_1 = require("./role.js");
|
|
10
11
|
const role_types_js_1 = require("./role-types.js");
|
|
11
12
|
let RoleMutation = class RoleMutation {
|
|
13
|
+
/*
|
|
14
|
+
* 선언이 `User` 였다 — 돌려주는 것은 `Role` 인데(아래 TS 반환형도 그렇다) 스키마에는 사용자로
|
|
15
|
+
* 적혀 있었다. 두 이름에 겹치는 칸(`id`·`name`·`description`)만 물어서 지금까지 드러나지
|
|
16
|
+
* 않았고, `email` 을 물으면 오류 없이 빈 값이 온다. 부르는 자리는 하나뿐이고 겹치는 칸만
|
|
17
|
+
* 쓴다(`role-list-page.ts` 의 `ox-record-creator`).
|
|
18
|
+
*/
|
|
12
19
|
async createRole(role, context) {
|
|
13
20
|
const { domain, user } = context.state;
|
|
14
21
|
const roleName = role.name.trim();
|
|
@@ -37,6 +44,15 @@ let RoleMutation = class RoleMutation {
|
|
|
37
44
|
where: { domain: { id: domain.id }, id },
|
|
38
45
|
relations: ['privileges', 'creator', 'updater']
|
|
39
46
|
});
|
|
47
|
+
/*
|
|
48
|
+
* **못 찾았으면 그렇게 말한다.** 이 범위는 `domain.id` 하나다 — 목록은 상속으로 부모 도메인의
|
|
49
|
+
* 역할까지 보여 주므로(`inherited: Include`) 관리자가 그것을 고치려 하면 여기로 온다. 예전에는
|
|
50
|
+
* 바로 아래 `role.name` 에서 TypeError 가 나 500 이 되었고, 화면은 왜 안 되는지 알 수 없었다.
|
|
51
|
+
*/
|
|
52
|
+
if (!role) {
|
|
53
|
+
throw new Error(context.t('error.failed to find x', { x: context.t('label.role') }) +
|
|
54
|
+
' — a role defined in a parent domain can only be edited in that domain.');
|
|
55
|
+
}
|
|
40
56
|
if (name && role.name !== name) {
|
|
41
57
|
const roleName = name.trim();
|
|
42
58
|
const existsRole = await roleRepository.findOne({ where: { name: roleName, domain: { id: domain.id } } });
|
|
@@ -51,36 +67,129 @@ let RoleMutation = class RoleMutation {
|
|
|
51
67
|
return await roleRepository.save({
|
|
52
68
|
...role,
|
|
53
69
|
...patch,
|
|
54
|
-
|
|
70
|
+
/*
|
|
71
|
+
* `privileges` 를 안 보낸 patch 는 **권한을 건드리지 않는다는 뜻**이다. 예전에는 여기서
|
|
72
|
+
* `patch.privileges.map` 이 TypeError 를 냈다 — 이름만 고치려는 호출이 500 이었다.
|
|
73
|
+
*/
|
|
74
|
+
privileges: privileges
|
|
75
|
+
? await (0, shell_1.getRepository)(privilege_js_1.Privilege).findBy({ id: (0, typeorm_1.In)(privileges.map(privilege => privilege.id)) })
|
|
76
|
+
: role.privileges,
|
|
55
77
|
updater: user
|
|
56
78
|
});
|
|
57
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* 격자에서 고친 여러 줄을 한 번에 저장한다.
|
|
82
|
+
*
|
|
83
|
+
* 이 저장소의 목록 화면 관례다 — `ox-grist` 의 `dirtyRecords` 를 `cuFlag` 와 함께 보내면
|
|
84
|
+
* `+` 는 만들고 `M` 은 고친다(`updateMultipleAuthProvider`·`updateMultipleUser`·
|
|
85
|
+
* `updateMultipleDomainLink` 가 같은 모양). 역할에만 이 자리가 없어서 이름·설명을 격자에서
|
|
86
|
+
* 고칠 수 없었다.
|
|
87
|
+
*
|
|
88
|
+
* **`privileges` 는 여기서 안 건드린다.** 격자는 이름과 설명만 고치고, 권한은 전용 화면이
|
|
89
|
+
* 쓴다(`updateRole`). 안 보낸 것을 「비우라」로 읽으면 격자에서 이름만 고친 순간 그 역할이
|
|
90
|
+
* 아무것도 안 여는 역할이 된다.
|
|
91
|
+
*
|
|
92
|
+
* 지우기는 이 자리에 없다 — 격자의 삭제는 `deleteRoles` 가 받고, 그쪽은 **쓰이는 역할을
|
|
93
|
+
* 남긴다**는 규칙을 따로 갖는다.
|
|
94
|
+
*/
|
|
95
|
+
async updateMultipleRole(patches, context) {
|
|
96
|
+
const { domain, user, tx } = context.state;
|
|
97
|
+
const roleRepository = tx.getRepository(role_js_1.Role);
|
|
98
|
+
const results = [];
|
|
99
|
+
/* `cuFlag` 가 없는 줄은 무엇을 하라는 것인지 알 수 없다 — 짐작해서 만들거나 고치지 않는다. */
|
|
100
|
+
const flagOf = (patch) => (patch.cuFlag || '').toUpperCase();
|
|
101
|
+
for (const patch of patches.filter(patch => flagOf(patch) === '+')) {
|
|
102
|
+
const name = patch.name?.trim();
|
|
103
|
+
if (!name) {
|
|
104
|
+
throw new Error(context.t('error.value is empty', { value: context.t('field.name') }));
|
|
105
|
+
}
|
|
106
|
+
if (await roleRepository.findOne({ where: { name, domain: { id: domain.id } } })) {
|
|
107
|
+
throw new Error('role name is duplicated');
|
|
108
|
+
}
|
|
109
|
+
results.push(await roleRepository.save({
|
|
110
|
+
domain,
|
|
111
|
+
creator: user,
|
|
112
|
+
updater: user,
|
|
113
|
+
name,
|
|
114
|
+
description: patch.description
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
for (const patch of patches.filter(patch => flagOf(patch) === 'M')) {
|
|
118
|
+
const role = await roleRepository.findOne({ where: { domain: { id: domain.id }, id: patch.id } });
|
|
119
|
+
/* 목록은 상속으로 부모 도메인 역할까지 보여 준다 — 그것을 고치려 하면 여기로 온다. */
|
|
120
|
+
if (!role) {
|
|
121
|
+
throw new Error(context.t('error.failed to find x', { x: context.t('label.role') }) +
|
|
122
|
+
' — a role defined in a parent domain can only be edited in that domain.');
|
|
123
|
+
}
|
|
124
|
+
const name = patch.name?.trim();
|
|
125
|
+
if (name && name !== role.name) {
|
|
126
|
+
if (await roleRepository.findOne({ where: { name, domain: { id: domain.id } } })) {
|
|
127
|
+
throw new Error('role name is duplicated');
|
|
128
|
+
}
|
|
129
|
+
role.name = name;
|
|
130
|
+
}
|
|
131
|
+
if (patch.description !== undefined) {
|
|
132
|
+
role.description = patch.description;
|
|
133
|
+
}
|
|
134
|
+
results.push(await roleRepository.save({ ...role, updater: user }));
|
|
135
|
+
}
|
|
136
|
+
return results;
|
|
137
|
+
}
|
|
58
138
|
async deleteRole(id, context) {
|
|
59
139
|
const { tx, domain } = context.state;
|
|
60
140
|
let role = await tx
|
|
61
141
|
.getRepository(role_js_1.Role)
|
|
62
142
|
.findOne({ where: { domain: { id: domain.id }, id }, relations: ['users', 'privileges'] });
|
|
143
|
+
/*
|
|
144
|
+
* **세 가지 실패가 한 문장으로 나가고 있었다.** 아래 try 의 catch 가 무엇이 났든
|
|
145
|
+
* 「사용 중이라 지울 수 없다」로 401 을 던졌다 — 못 찾은 것도(부모 도메인의 역할이 그렇다),
|
|
146
|
+
* DB 가 실패한 것도 그렇게 말했다. 관리자는 있지도 않은 사용자를 떼러 갔다.
|
|
147
|
+
*
|
|
148
|
+
* 그래서 판단할 수 있는 둘을 먼저 가른다.
|
|
149
|
+
*/
|
|
150
|
+
if (!role) {
|
|
151
|
+
throw new Error(context.t('error.failed to find x', { x: context.t('label.role') }) +
|
|
152
|
+
' — a role defined in a parent domain can only be deleted in that domain.');
|
|
153
|
+
}
|
|
154
|
+
if (role.users.length) {
|
|
155
|
+
throw new Error('cannot delete role because it is currently in use');
|
|
156
|
+
}
|
|
63
157
|
try {
|
|
64
|
-
if (role.users.length)
|
|
65
|
-
throw new Error('cannot delete role because it is currently in use');
|
|
66
158
|
role.privileges = [];
|
|
67
159
|
role = await tx.getRepository(role_js_1.Role).save(role);
|
|
68
160
|
await tx.getRepository(role_js_1.Role).delete(role.id);
|
|
69
161
|
return true;
|
|
70
162
|
}
|
|
71
163
|
catch (e) {
|
|
72
|
-
|
|
164
|
+
/* 여기까지 온 것은 지우는 동작 자체의 실패다 — 그 말을 그대로 올린다. */
|
|
165
|
+
context.throw(500, e.message);
|
|
73
166
|
}
|
|
74
167
|
}
|
|
75
|
-
async deleteRoles(ids,
|
|
76
|
-
|
|
168
|
+
async deleteRoles(ids, context) {
|
|
169
|
+
const { domain } = context.state;
|
|
170
|
+
/*
|
|
171
|
+
* **도메인을 봤어야 했다.** 예전에는 받은 id 를 그대로 지웠다 — `user:mutation` 을 가진
|
|
172
|
+
* 사람이 남의 도메인 역할을 id 만으로 지울 수 있었다. `deleteRole`(단수)은 처음부터
|
|
173
|
+
* 도메인으로 좁혀 찾았으므로, 둘의 규칙이 달랐다.
|
|
174
|
+
*
|
|
175
|
+
* 그리고 **사용 중인 역할은 남긴다** — 단수 쪽과 같은 규칙이다. 지운 것과 남은 것을 세어
|
|
176
|
+
* 돌려주지는 않는다(반환형이 `Boolean` 이다). 목록이 다시 읽으면 무엇이 남았는지 보인다.
|
|
177
|
+
*/
|
|
178
|
+
const roles = await (0, shell_1.getRepository)(role_js_1.Role).find({
|
|
179
|
+
where: { domain: { id: domain.id }, id: (0, typeorm_1.In)(ids) },
|
|
180
|
+
relations: ['users']
|
|
181
|
+
});
|
|
182
|
+
const deletable = roles.filter(role => !role.users?.length).map(role => role.id);
|
|
183
|
+
if (deletable.length) {
|
|
184
|
+
await (0, shell_1.getRepository)(role_js_1.Role).delete(deletable);
|
|
185
|
+
}
|
|
77
186
|
return true;
|
|
78
187
|
}
|
|
79
188
|
};
|
|
80
189
|
exports.RoleMutation = RoleMutation;
|
|
81
190
|
tslib_1.__decorate([
|
|
82
191
|
(0, type_graphql_1.Directive)('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)'),
|
|
83
|
-
(0, type_graphql_1.Mutation)(returns =>
|
|
192
|
+
(0, type_graphql_1.Mutation)(returns => role_js_1.Role, { description: 'To create new role' }),
|
|
84
193
|
tslib_1.__param(0, (0, type_graphql_1.Arg)('role')),
|
|
85
194
|
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
86
195
|
tslib_1.__metadata("design:type", Function),
|
|
@@ -97,6 +206,16 @@ tslib_1.__decorate([
|
|
|
97
206
|
tslib_1.__metadata("design:paramtypes", [String, role_types_js_1.RolePatch, Object]),
|
|
98
207
|
tslib_1.__metadata("design:returntype", Promise)
|
|
99
208
|
], RoleMutation.prototype, "updateRole", null);
|
|
209
|
+
tslib_1.__decorate([
|
|
210
|
+
(0, type_graphql_1.Directive)('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)'),
|
|
211
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
212
|
+
(0, type_graphql_1.Mutation)(returns => [role_js_1.Role], { description: 'To create or update multiple roles at once' }),
|
|
213
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('patches', type => [role_types_js_1.RolePatch])),
|
|
214
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
215
|
+
tslib_1.__metadata("design:type", Function),
|
|
216
|
+
tslib_1.__metadata("design:paramtypes", [Array, Object]),
|
|
217
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
218
|
+
], RoleMutation.prototype, "updateMultipleRole", null);
|
|
100
219
|
tslib_1.__decorate([
|
|
101
220
|
(0, type_graphql_1.Directive)('@privilege(category: "user", privilege: "mutation")'),
|
|
102
221
|
(0, type_graphql_1.Directive)('@transaction'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role-mutation.js","sourceRoot":"","sources":["../../../server/service/role/role-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'\n\nimport { getRepository } from '@things-factory/shell'\n\nimport { Privilege } from '../privilege/privilege.js'\nimport { User } from '../user/user.js'\nimport { Role } from './role.js'\nimport { NewRole, RolePatch } from './role-types.js'\n\n@Resolver(Role)\nexport class RoleMutation {\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => User, { description: 'To create new user' })\n async createRole(@Arg('role') role: NewRole, @Ctx() context: ResolverContext): Promise<Role> {\n const { domain, user } = context.state\n const roleName = role.name.trim()\n\n const existsRole: Role = await getRepository(Role).findOne({ where: { name: roleName, domain: { id: domain.id } } })\n\n if (existsRole) {\n throw new Error('role name is duplicated')\n }\n\n if (role.privileges && role.privileges.length) {\n role.privileges = await getRepository(Privilege).findByIds(role.privileges.map(privilege => privilege.id))\n }\n\n if (role.users && role.users.length) {\n role.users = await getRepository(User).findByIds(role.users.map(user => user.id))\n }\n\n return await getRepository(Role).save({\n domain,\n updater: user,\n creator: user,\n ...role\n })\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Role, { description: 'To modify role information' })\n async updateRole(\n @Arg('id') id: string,\n @Arg('patch') patch: RolePatch,\n @Ctx() context: ResolverContext\n ): Promise<Role> {\n const { domain, user } = context.state\n const { name, description, privileges } = patch\n const roleRepository = getRepository(Role)\n const role: Role = await roleRepository.findOne({\n where: { domain: { id: domain.id }, id },\n relations: ['privileges', 'creator', 'updater']\n })\n\n if (name && role.name !== name) {\n const roleName = name.trim()\n const existsRole: Role = await roleRepository.findOne({ where: { name: roleName, domain: { id: domain.id } } })\n if (existsRole) {\n throw new Error('role name is duplicated')\n }\n\n role.name = roleName\n }\n\n if (description) {\n role.description = description\n }\n\n return await roleRepository.save({\n ...role,\n ...patch,\n privileges: await getRepository(Privilege).findByIds(\n patch.privileges.map((privilege: Privilege) => privilege.id)\n ),\n updater: user\n } as any)\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\")')\n @Directive('@transaction')\n @Mutation(returns => Boolean, { description: 'To delete role' })\n async deleteRole(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Boolean> {\n const { tx, domain } = context.state\n let role: Role = await tx\n .getRepository(Role)\n .findOne({ where: { domain: { id: domain.id }, id }, relations: ['users', 'privileges'] })\n\n try {\n if (role.users.length) throw new Error('cannot delete role because it is currently in use')\n\n role.privileges = []\n\n role = await tx.getRepository(Role).save(role)\n\n await tx.getRepository(Role).delete(role.id)\n\n return true\n } catch (e) {\n context.throw(401, 'cannot delete role because it is currently in use')\n }\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Boolean, { description: 'To delete multiple roles' })\n async deleteRoles(@Arg('ids', type => [String]) ids: string[], @Ctx() _context: any) {\n await getRepository(Role).delete(ids)\n return true\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"role-mutation.js","sourceRoot":"","sources":["../../../server/service/role/role-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { In } from 'typeorm'\nimport { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'\n\nimport { getRepository } from '@things-factory/shell'\n\nimport { Privilege } from '../privilege/privilege.js'\nimport { User } from '../user/user.js'\nimport { Role } from './role.js'\nimport { NewRole, RolePatch } from './role-types.js'\n\n@Resolver(Role)\nexport class RoleMutation {\n /*\n * 선언이 `User` 였다 — 돌려주는 것은 `Role` 인데(아래 TS 반환형도 그렇다) 스키마에는 사용자로\n * 적혀 있었다. 두 이름에 겹치는 칸(`id`·`name`·`description`)만 물어서 지금까지 드러나지\n * 않았고, `email` 을 물으면 오류 없이 빈 값이 온다. 부르는 자리는 하나뿐이고 겹치는 칸만\n * 쓴다(`role-list-page.ts` 의 `ox-record-creator`).\n */\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Role, { description: 'To create new role' })\n async createRole(@Arg('role') role: NewRole, @Ctx() context: ResolverContext): Promise<Role> {\n const { domain, user } = context.state\n const roleName = role.name.trim()\n\n const existsRole: Role = await getRepository(Role).findOne({ where: { name: roleName, domain: { id: domain.id } } })\n\n if (existsRole) {\n throw new Error('role name is duplicated')\n }\n\n if (role.privileges && role.privileges.length) {\n role.privileges = await getRepository(Privilege).findByIds(role.privileges.map(privilege => privilege.id))\n }\n\n if (role.users && role.users.length) {\n role.users = await getRepository(User).findByIds(role.users.map(user => user.id))\n }\n\n return await getRepository(Role).save({\n domain,\n updater: user,\n creator: user,\n ...role\n })\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Role, { description: 'To modify role information' })\n async updateRole(\n @Arg('id') id: string,\n @Arg('patch') patch: RolePatch,\n @Ctx() context: ResolverContext\n ): Promise<Role> {\n const { domain, user } = context.state\n const { name, description, privileges } = patch\n const roleRepository = getRepository(Role)\n const role: Role = await roleRepository.findOne({\n where: { domain: { id: domain.id }, id },\n relations: ['privileges', 'creator', 'updater']\n })\n\n /*\n * **못 찾았으면 그렇게 말한다.** 이 범위는 `domain.id` 하나다 — 목록은 상속으로 부모 도메인의\n * 역할까지 보여 주므로(`inherited: Include`) 관리자가 그것을 고치려 하면 여기로 온다. 예전에는\n * 바로 아래 `role.name` 에서 TypeError 가 나 500 이 되었고, 화면은 왜 안 되는지 알 수 없었다.\n */\n if (!role) {\n throw new Error(\n context.t('error.failed to find x', { x: context.t('label.role') }) +\n ' — a role defined in a parent domain can only be edited in that domain.'\n )\n }\n\n if (name && role.name !== name) {\n const roleName = name.trim()\n const existsRole: Role = await roleRepository.findOne({ where: { name: roleName, domain: { id: domain.id } } })\n if (existsRole) {\n throw new Error('role name is duplicated')\n }\n\n role.name = roleName\n }\n\n if (description) {\n role.description = description\n }\n\n return await roleRepository.save({\n ...role,\n ...patch,\n /*\n * `privileges` 를 안 보낸 patch 는 **권한을 건드리지 않는다는 뜻**이다. 예전에는 여기서\n * `patch.privileges.map` 이 TypeError 를 냈다 — 이름만 고치려는 호출이 500 이었다.\n */\n privileges: privileges\n ? await getRepository(Privilege).findBy({ id: In(privileges.map(privilege => privilege.id)) })\n : role.privileges,\n updater: user\n } as any)\n }\n\n /**\n * 격자에서 고친 여러 줄을 한 번에 저장한다.\n *\n * 이 저장소의 목록 화면 관례다 — `ox-grist` 의 `dirtyRecords` 를 `cuFlag` 와 함께 보내면\n * `+` 는 만들고 `M` 은 고친다(`updateMultipleAuthProvider`·`updateMultipleUser`·\n * `updateMultipleDomainLink` 가 같은 모양). 역할에만 이 자리가 없어서 이름·설명을 격자에서\n * 고칠 수 없었다.\n *\n * **`privileges` 는 여기서 안 건드린다.** 격자는 이름과 설명만 고치고, 권한은 전용 화면이\n * 쓴다(`updateRole`). 안 보낸 것을 「비우라」로 읽으면 격자에서 이름만 고친 순간 그 역할이\n * 아무것도 안 여는 역할이 된다.\n *\n * 지우기는 이 자리에 없다 — 격자의 삭제는 `deleteRoles` 가 받고, 그쪽은 **쓰이는 역할을\n * 남긴다**는 규칙을 따로 갖는다.\n */\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [Role], { description: 'To create or update multiple roles at once' })\n async updateMultipleRole(\n @Arg('patches', type => [RolePatch]) patches: RolePatch[],\n @Ctx() context: ResolverContext\n ): Promise<Role[]> {\n const { domain, user, tx } = context.state\n const roleRepository = tx.getRepository(Role)\n const results: Role[] = []\n\n /* `cuFlag` 가 없는 줄은 무엇을 하라는 것인지 알 수 없다 — 짐작해서 만들거나 고치지 않는다. */\n const flagOf = (patch: RolePatch) => (patch.cuFlag || '').toUpperCase()\n\n for (const patch of patches.filter(patch => flagOf(patch) === '+')) {\n const name = patch.name?.trim()\n if (!name) {\n throw new Error(context.t('error.value is empty', { value: context.t('field.name') }))\n }\n\n if (await roleRepository.findOne({ where: { name, domain: { id: domain.id } } })) {\n throw new Error('role name is duplicated')\n }\n\n results.push(\n await roleRepository.save({\n domain,\n creator: user,\n updater: user,\n name,\n description: patch.description\n })\n )\n }\n\n for (const patch of patches.filter(patch => flagOf(patch) === 'M')) {\n const role = await roleRepository.findOne({ where: { domain: { id: domain.id }, id: patch.id } })\n\n /* 목록은 상속으로 부모 도메인 역할까지 보여 준다 — 그것을 고치려 하면 여기로 온다. */\n if (!role) {\n throw new Error(\n context.t('error.failed to find x', { x: context.t('label.role') }) +\n ' — a role defined in a parent domain can only be edited in that domain.'\n )\n }\n\n const name = patch.name?.trim()\n if (name && name !== role.name) {\n if (await roleRepository.findOne({ where: { name, domain: { id: domain.id } } })) {\n throw new Error('role name is duplicated')\n }\n role.name = name\n }\n\n if (patch.description !== undefined) {\n role.description = patch.description\n }\n\n results.push(await roleRepository.save({ ...role, updater: user }))\n }\n\n return results\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\")')\n @Directive('@transaction')\n @Mutation(returns => Boolean, { description: 'To delete role' })\n async deleteRole(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Boolean> {\n const { tx, domain } = context.state\n let role: Role = await tx\n .getRepository(Role)\n .findOne({ where: { domain: { id: domain.id }, id }, relations: ['users', 'privileges'] })\n\n /*\n * **세 가지 실패가 한 문장으로 나가고 있었다.** 아래 try 의 catch 가 무엇이 났든\n * 「사용 중이라 지울 수 없다」로 401 을 던졌다 — 못 찾은 것도(부모 도메인의 역할이 그렇다),\n * DB 가 실패한 것도 그렇게 말했다. 관리자는 있지도 않은 사용자를 떼러 갔다.\n *\n * 그래서 판단할 수 있는 둘을 먼저 가른다.\n */\n if (!role) {\n throw new Error(\n context.t('error.failed to find x', { x: context.t('label.role') }) +\n ' — a role defined in a parent domain can only be deleted in that domain.'\n )\n }\n\n if (role.users.length) {\n throw new Error('cannot delete role because it is currently in use')\n }\n\n try {\n role.privileges = []\n\n role = await tx.getRepository(Role).save(role)\n\n await tx.getRepository(Role).delete(role.id)\n\n return true\n } catch (e) {\n /* 여기까지 온 것은 지우는 동작 자체의 실패다 — 그 말을 그대로 올린다. */\n context.throw(500, e.message)\n }\n }\n\n @Directive('@privilege(category: \"user\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Boolean, { description: 'To delete multiple roles' })\n async deleteRoles(@Arg('ids', type => [String]) ids: string[], @Ctx() context: ResolverContext) {\n const { domain } = context.state\n\n /*\n * **도메인을 봤어야 했다.** 예전에는 받은 id 를 그대로 지웠다 — `user:mutation` 을 가진\n * 사람이 남의 도메인 역할을 id 만으로 지울 수 있었다. `deleteRole`(단수)은 처음부터\n * 도메인으로 좁혀 찾았으므로, 둘의 규칙이 달랐다.\n *\n * 그리고 **사용 중인 역할은 남긴다** — 단수 쪽과 같은 규칙이다. 지운 것과 남은 것을 세어\n * 돌려주지는 않는다(반환형이 `Boolean` 이다). 목록이 다시 읽으면 무엇이 남았는지 보인다.\n */\n const roles = await getRepository(Role).find({\n where: { domain: { id: domain.id }, id: In(ids) },\n relations: ['users']\n })\n\n const deletable = roles.filter(role => !role.users?.length).map(role => role.id)\n if (deletable.length) {\n await getRepository(Role).delete(deletable)\n }\n\n return true\n }\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { RolePrivilege } from './role-types.js';
|
|
2
|
+
/**
|
|
3
|
+
* `rolePrivileges` 가 돌려주는 행에도 **유령 여부**를 붙인다.
|
|
4
|
+
*
|
|
5
|
+
* `Privilege` 타입에는 이미 같은 칸이 있는데(`privilege-query.ts`), `RolePrivilege` 는 다른
|
|
6
|
+
* 타입이므로 그 칸을 못 쓴다. 권한 편집 화면이 드는 것은 이쪽이고, 유령을 못 보면 관리자는
|
|
7
|
+
* **붙여도 아무 일이 없는 권한**을 계속 붙인다.
|
|
8
|
+
*
|
|
9
|
+
* 저장하지 않고 매번 계산하는 이유는 `privilege-deprecation.ts` 에 적혀 있다 — 뜻은 「영원히
|
|
10
|
+
* 죽었다」가 아니라 **「지금 이 배포가 요구하지 않는다」**다.
|
|
11
|
+
*/
|
|
12
|
+
export declare class RolePrivilegeQuery {
|
|
13
|
+
deprecated(rolePrivilege: RolePrivilege): Promise<boolean>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RolePrivilegeQuery = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const type_graphql_1 = require("type-graphql");
|
|
6
|
+
const privilege_deprecation_js_1 = require("../privilege/privilege-deprecation.js");
|
|
7
|
+
const role_types_js_1 = require("./role-types.js");
|
|
8
|
+
/**
|
|
9
|
+
* `rolePrivileges` 가 돌려주는 행에도 **유령 여부**를 붙인다.
|
|
10
|
+
*
|
|
11
|
+
* `Privilege` 타입에는 이미 같은 칸이 있는데(`privilege-query.ts`), `RolePrivilege` 는 다른
|
|
12
|
+
* 타입이므로 그 칸을 못 쓴다. 권한 편집 화면이 드는 것은 이쪽이고, 유령을 못 보면 관리자는
|
|
13
|
+
* **붙여도 아무 일이 없는 권한**을 계속 붙인다.
|
|
14
|
+
*
|
|
15
|
+
* 저장하지 않고 매번 계산하는 이유는 `privilege-deprecation.ts` 에 적혀 있다 — 뜻은 「영원히
|
|
16
|
+
* 죽었다」가 아니라 **「지금 이 배포가 요구하지 않는다」**다.
|
|
17
|
+
*/
|
|
18
|
+
let RolePrivilegeQuery = class RolePrivilegeQuery {
|
|
19
|
+
async deprecated(rolePrivilege) {
|
|
20
|
+
return (0, privilege_deprecation_js_1.isDeprecatedPrivilege)(process['PRIVILEGES'], rolePrivilege);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
exports.RolePrivilegeQuery = RolePrivilegeQuery;
|
|
24
|
+
tslib_1.__decorate([
|
|
25
|
+
(0, type_graphql_1.FieldResolver)(type => Boolean, {
|
|
26
|
+
description: 'True when no module in this deployment declares this privilege anymore (@privilege directive). ' +
|
|
27
|
+
'Computed per request — it answers for the asking deployment, not for all time.'
|
|
28
|
+
}),
|
|
29
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
30
|
+
tslib_1.__metadata("design:type", Function),
|
|
31
|
+
tslib_1.__metadata("design:paramtypes", [role_types_js_1.RolePrivilege]),
|
|
32
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
33
|
+
], RolePrivilegeQuery.prototype, "deprecated", null);
|
|
34
|
+
exports.RolePrivilegeQuery = RolePrivilegeQuery = tslib_1.__decorate([
|
|
35
|
+
(0, type_graphql_1.Resolver)(role_types_js_1.RolePrivilege)
|
|
36
|
+
], RolePrivilegeQuery);
|
|
37
|
+
//# sourceMappingURL=role-privilege-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role-privilege-query.js","sourceRoot":"","sources":["../../../server/service/role/role-privilege-query.ts"],"names":[],"mappings":";;;;AAAA,+CAA4D;AAE5D,oFAA6E;AAC7E,mDAA+C;AAE/C;;;;;;;;;GASG;AAEI,IAAM,kBAAkB,GAAxB,MAAM,kBAAkB;IAMvB,AAAN,KAAK,CAAC,UAAU,CAAS,aAA4B;QACnD,OAAO,IAAA,gDAAqB,EAAC,OAAO,CAAC,YAAY,CAAC,EAAE,aAAa,CAAC,CAAA;IACpE,CAAC;CACF,CAAA;AATY,gDAAkB;AAMvB;IALL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE;QAC9B,WAAW,EACT,iGAAiG;YACjG,gFAAgF;KACnF,CAAC;IACgB,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAgB,6BAAa;;oDAEpD;6BARU,kBAAkB;IAD9B,IAAA,uBAAQ,EAAC,6BAAa,CAAC;GACX,kBAAkB,CAS9B","sourcesContent":["import { FieldResolver, Resolver, Root } from 'type-graphql'\n\nimport { isDeprecatedPrivilege } from '../privilege/privilege-deprecation.js'\nimport { RolePrivilege } from './role-types.js'\n\n/**\n * `rolePrivileges` 가 돌려주는 행에도 **유령 여부**를 붙인다.\n *\n * `Privilege` 타입에는 이미 같은 칸이 있는데(`privilege-query.ts`), `RolePrivilege` 는 다른\n * 타입이므로 그 칸을 못 쓴다. 권한 편집 화면이 드는 것은 이쪽이고, 유령을 못 보면 관리자는\n * **붙여도 아무 일이 없는 권한**을 계속 붙인다.\n *\n * 저장하지 않고 매번 계산하는 이유는 `privilege-deprecation.ts` 에 적혀 있다 — 뜻은 「영원히\n * 죽었다」가 아니라 **「지금 이 배포가 요구하지 않는다」**다.\n */\n@Resolver(RolePrivilege)\nexport class RolePrivilegeQuery {\n @FieldResolver(type => Boolean, {\n description:\n 'True when no module in this deployment declares this privilege anymore (@privilege directive). ' +\n 'Computed per request — it answers for the asking deployment, not for all time.'\n })\n async deprecated(@Root() rolePrivilege: RolePrivilege): Promise<boolean> {\n return isDeprecatedPrivilege(process['PRIVILEGES'], rolePrivilege)\n }\n}\n"]}
|
|
@@ -6,16 +6,76 @@ import { RoleList, RolePrivilege, UserRole, RoleBrief } from './role-types.js';
|
|
|
6
6
|
export declare class RoleQuery {
|
|
7
7
|
role(name: string, context: ResolverContext): Promise<Role>;
|
|
8
8
|
roles(params: ListParam, context: ResolverContext): Promise<RoleList>;
|
|
9
|
+
/**
|
|
10
|
+
* 한 역할의 권한 — **전체 목록과 이 역할이 가진 것을 한 번에** 돌려준다.
|
|
11
|
+
*
|
|
12
|
+
* 권한 편집 화면이 필요한 것은 「무엇이 있나」와 「이 역할이 무엇을 갖나」 둘인데, 그것을
|
|
13
|
+
* 질의 둘로 가르면 화면이 둘을 짝지어야 하고 그 짝짓기가 역할 **이름**으로 이루어졌다
|
|
14
|
+
* (옛 `role-privilege-editor` — 같은 이름의 부모 도메인 역할과 헷갈렸다). 여기서 `roleId` 로
|
|
15
|
+
* 짝지어 주면 화면이 그 일을 안 한다.
|
|
16
|
+
*
|
|
17
|
+
* ── 원시 SQL 을 걷어냈다 ────────────────────────────────────────────────────
|
|
18
|
+
* 셋을 동시에 잃고 있었다.
|
|
19
|
+
*
|
|
20
|
+
* ① `roleId` 를 문자열로 이어 붙였다. `user:query` 를 가진 사람이 임의의 SQL 을 넣을 수 있다.
|
|
21
|
+
* ② `CASE WHEN … THEN true` 는 방언이다 — MSSQL 에 boolean 리터럴이 없다. 이 저장소는
|
|
22
|
+
* DB 5종을 지원한다.
|
|
23
|
+
* ③ 도메인을 안 봤다. 남의 도메인 역할의 `roleId` 로도 답했다.
|
|
24
|
+
*
|
|
25
|
+
* 권한 마스터는 전체 배포에 84행 규모(도메인마다 늘지 않는다)이므로 관계를 그대로 읽는다.
|
|
26
|
+
*/
|
|
9
27
|
rolePrivileges(roleId: string, context: ResolverContext): Promise<RolePrivilege[]>;
|
|
28
|
+
/**
|
|
29
|
+
* 한 사람의 역할 — **부여할 수 있는 전체와 이 사람이 가진 것을 한 번에.**
|
|
30
|
+
*
|
|
31
|
+
* `rolePrivileges` 와 같은 모양이고, **같은 결함을 갖고 있었다.** 한 자리를 고쳤으면 두 번째
|
|
32
|
+
* 자리도 재야 한다는 것이 이 파일에서 그대로 났다.
|
|
33
|
+
*
|
|
34
|
+
* ① `UR.users_id` 자리에 `userId` 를 문자열로 이어 붙였다. `user:query` 를 가진
|
|
35
|
+
* 사람이 임의의 SQL 을 넣을 수 있다.
|
|
36
|
+
* ② `CASE WHEN … THEN true` 는 방언이다 — MSSQL 에 boolean 리터럴이 없다(DB 5종 지원).
|
|
37
|
+
* ③ `FROM roles` — **도메인을 안 봤다.** 남의 도메인 역할까지 전부 돌려줬다.
|
|
38
|
+
*
|
|
39
|
+
* ③ 을 고치면서 범위를 `role`·`rolePrivileges` 와 같게 뒀다 — 내 도메인과 부모 1단.
|
|
40
|
+
* 그것이 실제로 부여할 수 있는 범위다.
|
|
41
|
+
*
|
|
42
|
+
* 지금 이 질의를 부르는 화면은 없다(옛 `user-role-editor` 는 `user(email:)` 로 읽었다).
|
|
43
|
+
* 그래서 범위를 좁히는 것이 깨뜨릴 소비처가 없다.
|
|
44
|
+
*/
|
|
10
45
|
userRoles(userId: string, context: ResolverContext): Promise<UserRole[]>;
|
|
11
46
|
myRoles(context: ResolverContext): Promise<RoleBrief[]>;
|
|
12
|
-
checkRolePreset(context: ResolverContext): Promise<Role[]>;
|
|
13
47
|
domain(role: Role): Promise<Domain>;
|
|
14
48
|
/**
|
|
15
49
|
* Role의 users 필드를 위한 리졸버
|
|
16
50
|
* 사용자 조회 권한이 있는 경우에만 접근 가능
|
|
17
51
|
*/
|
|
18
52
|
users(role: Role, context: ResolverContext): Promise<User[]>;
|
|
53
|
+
/**
|
|
54
|
+
* 이 역할이 여는 권한이 **몇 개인가.**
|
|
55
|
+
*
|
|
56
|
+
* ── 왜 수만 따로 있나 ──────────────────────────────────────────────────────
|
|
57
|
+
* 목록 화면이 「이 역할이 무엇을 여나」를 말해야 하는데, 그것을 위해 권한 **행**을 받고 있었다.
|
|
58
|
+
*
|
|
59
|
+
* ```
|
|
60
|
+
* [확인함] roles(limit:20) 권한 포함 5,731 bytes · 69ms
|
|
61
|
+
* [확인함] roles(limit:20) 권한 없이 518 bytes · 7ms → 11.1배 · 10배
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* 역할 2개에 권한 행 60개를 받아서 화면에는 잘린 코드 용어 셋을 그렸다. 역할 40개 ×
|
|
65
|
+
* 권한 100개면 한 페이지에 4,000행이다. **`privileges` 필드 리졸버가 역할마다 한 번씩 도는
|
|
66
|
+
* 것**까지 함께 없어지는 것이 더 큰 쪽이다.
|
|
67
|
+
*
|
|
68
|
+
* 그래서 목록은 이 칸을 쓴다 — 행을 안 받고 수를 받는다. 권한을 실제로 고치는 화면은
|
|
69
|
+
* `rolePrivileges(roleId:)` 로 따로 읽는다(전체 목록 + 이 역할이 가진 것을 한 번에).
|
|
70
|
+
*
|
|
71
|
+
* ── 왜 관계를 세지 않고 질의로 세나 ────────────────────────────────────────
|
|
72
|
+
* `relation(...).loadMany()` 는 행을 다 읽고 길이를 재는 것이라 여기서 고치려는 것을 그대로
|
|
73
|
+
* 다시 한다. `getCount()` 는 DB 가 센다.
|
|
74
|
+
*
|
|
75
|
+
* 조인 테이블의 주인은 `Privilege` 쪽이지만(`privilege.ts:72` 의 `@JoinTable`), 양쪽이 관계를
|
|
76
|
+
* 선언하고 있으므로 어느 쪽에서 조인해도 같다.
|
|
77
|
+
*/
|
|
78
|
+
privilegeCount(role: Role): Promise<number>;
|
|
19
79
|
privileges(role: Role): Promise<Privilege[]>;
|
|
20
80
|
updater(role: Role): Promise<User>;
|
|
21
81
|
creator(role: Role): Promise<User>;
|
|
@@ -4,7 +4,6 @@ exports.RoleQuery = void 0;
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const typeorm_1 = require("typeorm");
|
|
6
6
|
const type_graphql_1 = require("type-graphql");
|
|
7
|
-
const env_1 = require("@things-factory/env");
|
|
8
7
|
const shell_1 = require("@things-factory/shell");
|
|
9
8
|
const privilege_js_1 = require("../privilege/privilege.js");
|
|
10
9
|
const user_js_1 = require("../user/user.js");
|
|
@@ -28,52 +27,71 @@ let RoleQuery = class RoleQuery {
|
|
|
28
27
|
}).getManyAndCount();
|
|
29
28
|
return { items, total };
|
|
30
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* 한 역할의 권한 — **전체 목록과 이 역할이 가진 것을 한 번에** 돌려준다.
|
|
32
|
+
*
|
|
33
|
+
* 권한 편집 화면이 필요한 것은 「무엇이 있나」와 「이 역할이 무엇을 갖나」 둘인데, 그것을
|
|
34
|
+
* 질의 둘로 가르면 화면이 둘을 짝지어야 하고 그 짝짓기가 역할 **이름**으로 이루어졌다
|
|
35
|
+
* (옛 `role-privilege-editor` — 같은 이름의 부모 도메인 역할과 헷갈렸다). 여기서 `roleId` 로
|
|
36
|
+
* 짝지어 주면 화면이 그 일을 안 한다.
|
|
37
|
+
*
|
|
38
|
+
* ── 원시 SQL 을 걷어냈다 ────────────────────────────────────────────────────
|
|
39
|
+
* 셋을 동시에 잃고 있었다.
|
|
40
|
+
*
|
|
41
|
+
* ① `roleId` 를 문자열로 이어 붙였다. `user:query` 를 가진 사람이 임의의 SQL 을 넣을 수 있다.
|
|
42
|
+
* ② `CASE WHEN … THEN true` 는 방언이다 — MSSQL 에 boolean 리터럴이 없다. 이 저장소는
|
|
43
|
+
* DB 5종을 지원한다.
|
|
44
|
+
* ③ 도메인을 안 봤다. 남의 도메인 역할의 `roleId` 로도 답했다.
|
|
45
|
+
*
|
|
46
|
+
* 권한 마스터는 전체 배포에 84행 규모(도메인마다 늘지 않는다)이므로 관계를 그대로 읽는다.
|
|
47
|
+
*/
|
|
31
48
|
async rolePrivileges(roleId, context) {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
`);
|
|
53
|
-
return rolePrivileges;
|
|
49
|
+
const { domain } = context.state;
|
|
50
|
+
/* 상속으로 보이는 부모 도메인 역할까지가 범위다 — `role` 질의와 같은 규칙. */
|
|
51
|
+
const role = await (0, shell_1.getRepository)(role_js_1.Role).findOne({
|
|
52
|
+
where: {
|
|
53
|
+
id: roleId,
|
|
54
|
+
domain: { id: (0, typeorm_1.In)([domain.id, domain.parentId].filter(Boolean)) }
|
|
55
|
+
},
|
|
56
|
+
relations: ['privileges']
|
|
57
|
+
});
|
|
58
|
+
if (!role) {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
const assigned = new Set((role.privileges || []).map(privilege => privilege.id));
|
|
62
|
+
return (await (0, shell_1.getRepository)(privilege_js_1.Privilege).find()).map(({ id, name, category, description }) => ({
|
|
63
|
+
id,
|
|
64
|
+
name,
|
|
65
|
+
category,
|
|
66
|
+
description,
|
|
67
|
+
assigned: assigned.has(id)
|
|
68
|
+
}));
|
|
54
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* 한 사람의 역할 — **부여할 수 있는 전체와 이 사람이 가진 것을 한 번에.**
|
|
72
|
+
*
|
|
73
|
+
* `rolePrivileges` 와 같은 모양이고, **같은 결함을 갖고 있었다.** 한 자리를 고쳤으면 두 번째
|
|
74
|
+
* 자리도 재야 한다는 것이 이 파일에서 그대로 났다.
|
|
75
|
+
*
|
|
76
|
+
* ① `UR.users_id` 자리에 `userId` 를 문자열로 이어 붙였다. `user:query` 를 가진
|
|
77
|
+
* 사람이 임의의 SQL 을 넣을 수 있다.
|
|
78
|
+
* ② `CASE WHEN … THEN true` 는 방언이다 — MSSQL 에 boolean 리터럴이 없다(DB 5종 지원).
|
|
79
|
+
* ③ `FROM roles` — **도메인을 안 봤다.** 남의 도메인 역할까지 전부 돌려줬다.
|
|
80
|
+
*
|
|
81
|
+
* ③ 을 고치면서 범위를 `role`·`rolePrivileges` 와 같게 뒀다 — 내 도메인과 부모 1단.
|
|
82
|
+
* 그것이 실제로 부여할 수 있는 범위다.
|
|
83
|
+
*
|
|
84
|
+
* 지금 이 질의를 부르는 화면은 없다(옛 `user-role-editor` 는 `user(email:)` 로 읽었다).
|
|
85
|
+
* 그래서 범위를 좁히는 것이 깨뜨릴 소비처가 없다.
|
|
86
|
+
*/
|
|
55
87
|
async userRoles(userId, context) {
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
R.id
|
|
64
|
-
FROM
|
|
65
|
-
roles R JOIN users_roles UR
|
|
66
|
-
ON
|
|
67
|
-
R.id = UR.roles_id
|
|
68
|
-
WHERE
|
|
69
|
-
UR.users_id = '${userId}'
|
|
70
|
-
) THEN true
|
|
71
|
-
ELSE false
|
|
72
|
-
END AS assigned
|
|
73
|
-
FROM
|
|
74
|
-
roles
|
|
75
|
-
`);
|
|
76
|
-
return userRoles;
|
|
88
|
+
const { domain } = context.state;
|
|
89
|
+
const user = await (0, shell_1.getRepository)(user_js_1.User).findOne({ where: { id: userId }, relations: ['roles'] });
|
|
90
|
+
const assigned = new Set((user?.roles || []).map(role => role.id));
|
|
91
|
+
const roles = await (0, shell_1.getRepository)(role_js_1.Role).find({
|
|
92
|
+
where: { domain: { id: (0, typeorm_1.In)([domain.id, domain.parentId].filter(Boolean)) } }
|
|
93
|
+
});
|
|
94
|
+
return roles.map(({ id, name, description }) => ({ id, name, description, assigned: assigned.has(id) }));
|
|
77
95
|
}
|
|
78
96
|
async myRoles(context) {
|
|
79
97
|
const { user, domain } = context.state;
|
|
@@ -87,10 +105,19 @@ let RoleQuery = class RoleQuery {
|
|
|
87
105
|
.getMany();
|
|
88
106
|
return roles;
|
|
89
107
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
108
|
+
/*
|
|
109
|
+
* `checkRolePreset` stood here and has been removed. It read `config.get('rolePreset')`
|
|
110
|
+
* and returned it unchanged, declared as `[Role]`.
|
|
111
|
+
*
|
|
112
|
+
* Nothing set that config key and nothing called the query, across every repository on
|
|
113
|
+
* this machine — and it carried no `@privilege`, so any signed-in user could read
|
|
114
|
+
* whatever an installation later put there. Empty today, quietly public the day someone
|
|
115
|
+
* fills it. Role templates (`service/role-template/`) do what this was reaching for, as
|
|
116
|
+
* a boot registry rather than a config blob.
|
|
117
|
+
*
|
|
118
|
+
* auth-base ships to npm, so consumers outside this repository cannot be counted. The
|
|
119
|
+
* removal is recorded in the changelog — that is the only channel they have.
|
|
120
|
+
*/
|
|
94
121
|
async domain(role) {
|
|
95
122
|
return await (0, shell_1.getRepository)(shell_1.Domain).findOneBy({ id: role.domainId });
|
|
96
123
|
}
|
|
@@ -105,6 +132,38 @@ let RoleQuery = class RoleQuery {
|
|
|
105
132
|
});
|
|
106
133
|
return roleData?.users || [];
|
|
107
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* 이 역할이 여는 권한이 **몇 개인가.**
|
|
137
|
+
*
|
|
138
|
+
* ── 왜 수만 따로 있나 ──────────────────────────────────────────────────────
|
|
139
|
+
* 목록 화면이 「이 역할이 무엇을 여나」를 말해야 하는데, 그것을 위해 권한 **행**을 받고 있었다.
|
|
140
|
+
*
|
|
141
|
+
* ```
|
|
142
|
+
* [확인함] roles(limit:20) 권한 포함 5,731 bytes · 69ms
|
|
143
|
+
* [확인함] roles(limit:20) 권한 없이 518 bytes · 7ms → 11.1배 · 10배
|
|
144
|
+
* ```
|
|
145
|
+
*
|
|
146
|
+
* 역할 2개에 권한 행 60개를 받아서 화면에는 잘린 코드 용어 셋을 그렸다. 역할 40개 ×
|
|
147
|
+
* 권한 100개면 한 페이지에 4,000행이다. **`privileges` 필드 리졸버가 역할마다 한 번씩 도는
|
|
148
|
+
* 것**까지 함께 없어지는 것이 더 큰 쪽이다.
|
|
149
|
+
*
|
|
150
|
+
* 그래서 목록은 이 칸을 쓴다 — 행을 안 받고 수를 받는다. 권한을 실제로 고치는 화면은
|
|
151
|
+
* `rolePrivileges(roleId:)` 로 따로 읽는다(전체 목록 + 이 역할이 가진 것을 한 번에).
|
|
152
|
+
*
|
|
153
|
+
* ── 왜 관계를 세지 않고 질의로 세나 ────────────────────────────────────────
|
|
154
|
+
* `relation(...).loadMany()` 는 행을 다 읽고 길이를 재는 것이라 여기서 고치려는 것을 그대로
|
|
155
|
+
* 다시 한다. `getCount()` 는 DB 가 센다.
|
|
156
|
+
*
|
|
157
|
+
* 조인 테이블의 주인은 `Privilege` 쪽이지만(`privilege.ts:72` 의 `@JoinTable`), 양쪽이 관계를
|
|
158
|
+
* 선언하고 있으므로 어느 쪽에서 조인해도 같다.
|
|
159
|
+
*/
|
|
160
|
+
async privilegeCount(role) {
|
|
161
|
+
return await (0, shell_1.getRepository)(privilege_js_1.Privilege)
|
|
162
|
+
.createQueryBuilder('PRIVILEGE')
|
|
163
|
+
.innerJoin('PRIVILEGE.roles', 'ROLE')
|
|
164
|
+
.where('ROLE.id = :id', { id: role.id })
|
|
165
|
+
.getCount();
|
|
166
|
+
}
|
|
108
167
|
async privileges(role) {
|
|
109
168
|
return (await (0, shell_1.getRepository)(role_js_1.Role).findOne({
|
|
110
169
|
where: { id: role.id },
|
|
@@ -162,13 +221,6 @@ tslib_1.__decorate([
|
|
|
162
221
|
tslib_1.__metadata("design:paramtypes", [Object]),
|
|
163
222
|
tslib_1.__metadata("design:returntype", Promise)
|
|
164
223
|
], RoleQuery.prototype, "myRoles", null);
|
|
165
|
-
tslib_1.__decorate([
|
|
166
|
-
(0, type_graphql_1.Query)(returns => [role_js_1.Role], { description: 'To fetch the preset of role for new user' }),
|
|
167
|
-
tslib_1.__param(0, (0, type_graphql_1.Ctx)()),
|
|
168
|
-
tslib_1.__metadata("design:type", Function),
|
|
169
|
-
tslib_1.__metadata("design:paramtypes", [Object]),
|
|
170
|
-
tslib_1.__metadata("design:returntype", Promise)
|
|
171
|
-
], RoleQuery.prototype, "checkRolePreset", null);
|
|
172
224
|
tslib_1.__decorate([
|
|
173
225
|
(0, type_graphql_1.FieldResolver)(type => shell_1.Domain),
|
|
174
226
|
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
@@ -185,6 +237,13 @@ tslib_1.__decorate([
|
|
|
185
237
|
tslib_1.__metadata("design:paramtypes", [role_js_1.Role, Object]),
|
|
186
238
|
tslib_1.__metadata("design:returntype", Promise)
|
|
187
239
|
], RoleQuery.prototype, "users", null);
|
|
240
|
+
tslib_1.__decorate([
|
|
241
|
+
(0, type_graphql_1.FieldResolver)(type => type_graphql_1.Int),
|
|
242
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
243
|
+
tslib_1.__metadata("design:type", Function),
|
|
244
|
+
tslib_1.__metadata("design:paramtypes", [role_js_1.Role]),
|
|
245
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
246
|
+
], RoleQuery.prototype, "privilegeCount", null);
|
|
188
247
|
tslib_1.__decorate([
|
|
189
248
|
(0, type_graphql_1.FieldResolver)(type => [privilege_js_1.Privilege]),
|
|
190
249
|
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|