w-web-perm 1.0.48 → 1.0.49
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/.github/workflows/ci-test.yml +2 -2
- package/_gh-pages-deploy/.nojekyll +0 -0
- package/_gh-pages-deploy/WWebPerm.html +938 -0
- package/_gh-pages-deploy/WWebPerm.mjs.html +1228 -0
- package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.eot +0 -0
- package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
- package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.woff +0 -0
- package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
- package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.eot +0 -0
- package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
- package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.woff +0 -0
- package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
- package/_gh-pages-deploy/index.html +84 -0
- package/_gh-pages-deploy/scripts/collapse.js +39 -0
- package/_gh-pages-deploy/scripts/commonNav.js +28 -0
- package/_gh-pages-deploy/scripts/linenumber.js +25 -0
- package/_gh-pages-deploy/scripts/nav.js +12 -0
- package/_gh-pages-deploy/scripts/polyfill.js +4 -0
- package/_gh-pages-deploy/scripts/prettify/Apache-License-2.0.txt +202 -0
- package/_gh-pages-deploy/scripts/prettify/lang-css.js +2 -0
- package/_gh-pages-deploy/scripts/prettify/prettify.js +28 -0
- package/_gh-pages-deploy/scripts/search.js +99 -0
- package/_gh-pages-deploy/styles/jsdoc.css +776 -0
- package/_gh-pages-deploy/styles/prettify.css +80 -0
- package/dist/css/app.d8b16216.css +1 -0
- package/dist/css/{chunk-vendors.f149e124.css → chunk-vendors.2d3ef2ba.css} +1 -1
- package/dist/index.tmp +2 -2
- package/dist/js/app-legacy.fb48310a.js +1 -0
- package/dist/js/app.fb48310a.js +1 -0
- package/dist/js/chunk-vendors-legacy.8fdd4435.js +21 -0
- package/dist/js/chunk-vendors.8fdd4435.js +21 -0
- package/dist/w-web-perm.umd.js +2 -2
- package/dist/w-web-perm.umd.js.map +1 -1
- package/docs/WWebPerm.html +2 -2
- package/docs/WWebPerm.mjs.html +138 -199
- package/docs/index.html +1 -1
- package/package.json +15 -11
- package/public/index.html +2 -2
- package/server/WWebPerm.mjs +137 -198
- package/server/procCore.mjs +169 -0
- package/server/procLang.mjs +197 -0
- package/server/procStaInfor.mjs +118 -0
- package/server/provideTabs.mjs +1 -1
- package/server/srLog.mjs +30 -0
- package/server/staLogs/staEvent.callWorker.mjs +46 -0
- package/server/staLogs/staEvent.mjs +116 -0
- package/server/staLogs/staEvent.shellWorker.mjs +19 -0
- package/server/staLogs/staEventTable.mjs +100 -0
- package/server/staLogs/test_staEvent.mjs +22 -0
- package/settings.json +40 -0
- package/src/components/Common/CheckYes.vue +18 -1
- package/src/components/Layout.vue +1 -1
- package/src/components/LayoutContent.vue +13 -1
- package/src/components/LayoutContentGrups.vue +32 -23
- package/src/components/LayoutContentPemis.vue +32 -23
- package/src/components/LayoutContentStaInfor.vue +536 -0
- package/src/components/LayoutContentTargets.vue +32 -23
- package/src/components/LayoutContentUsers.vue +32 -23
- package/src/components/LayoutState.vue +5 -0
- package/src/components/VeCgrups.vue +12 -3
- package/src/components/VeCpemis.vue +12 -3
- package/src/components/VeCrules.vue +12 -3
- package/src/components/VeGrupBlngUsers.vue +18 -6
- package/src/components/VePemiBlngGrups.vue +18 -6
- package/src/getPerm.mjs +7 -17
- package/src/getPermUserInfor.mjs +8 -18
- package/src/main.js +1 -0
- package/src/plugins/mShare.mjs +8 -13
- package/src/plugins/mUI.mjs +11 -0
- package/srv.mjs +76 -101
- package/tableTags.json +1 -1
- package/db/wperm/grups/data.mdb +0 -0
- package/db/wperm/grups/lock.mdb +0 -0
- package/db/wperm/pemis/data.mdb +0 -0
- package/db/wperm/pemis/lock.mdb +0 -0
- package/db/wperm/targets/data.mdb +0 -0
- package/db/wperm/targets/lock.mdb +0 -0
- package/db/wperm/users/data.mdb +0 -0
- package/db/wperm/users/lock.mdb +0 -0
- package/dist/css/app.30e81bfe.css +0 -1
- package/dist/js/app-legacy.3324392e.js +0 -1
- package/dist/js/app.3324392e.js +0 -1
- package/dist/js/chunk-vendors-legacy.e8703728.js +0 -21
- package/dist/js/chunk-vendors.e8703728.js +0 -21
- package/test/getUserRules.test.mjs +0 -899
|
@@ -1,899 +0,0 @@
|
|
|
1
|
-
import assert from 'assert'
|
|
2
|
-
import { getUserRules } from '../src/plugins/mShare.mjs'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// ---------------------------------------------------------------
|
|
6
|
-
// helpers
|
|
7
|
-
// ---------------------------------------------------------------
|
|
8
|
-
|
|
9
|
-
/** 建立 target 物件 */
|
|
10
|
-
let t = (id) => ({ id })
|
|
11
|
-
|
|
12
|
-
/** 建立 permission 物件,rules 為 { targetId: 'y'|'n' } */
|
|
13
|
-
let p = (name, rules = {}) => ({
|
|
14
|
-
name,
|
|
15
|
-
crules: JSON.stringify(rules),
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
/** 建立 group 物件,perms 為 { permName: { mode, isActive } } */
|
|
19
|
-
let g = (name, perms = {}) => ({
|
|
20
|
-
name,
|
|
21
|
-
cpemis: JSON.stringify(perms),
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
/** 建立 user 物件,groups 為 { groupName: { mode, isActive } } */
|
|
25
|
-
let u = (groups = {}) => ({
|
|
26
|
-
cgrups: JSON.stringify(groups),
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
/** 從 rules 陣列取特定 target 的 isActive */
|
|
30
|
-
let ruleOf = (rules, targetName) => {
|
|
31
|
-
let r = rules.find((v) => v.name === targetName)
|
|
32
|
-
return r ? r.isActive : undefined
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** 將 rules 陣列轉為 { name: isActive } map,方便比對 */
|
|
36
|
-
let rulesToMap = (rules) => {
|
|
37
|
-
let kp = {}
|
|
38
|
-
rules.forEach((v) => { kp[v.name] = v.isActive })
|
|
39
|
-
return kp
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** permission 內的 active entry 簡寫 */
|
|
43
|
-
let OR = { mode: 'OR', isActive: 'y' }
|
|
44
|
-
let AND = { mode: 'AND', isActive: 'y' }
|
|
45
|
-
let OR_OFF = { mode: 'OR', isActive: 'n' }
|
|
46
|
-
let AND_OFF = { mode: 'AND', isActive: 'n' }
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// ---------------------------------------------------------------
|
|
50
|
-
// tests
|
|
51
|
-
// ---------------------------------------------------------------
|
|
52
|
-
|
|
53
|
-
describe('getUserRules - 權限樹組裝', function() {
|
|
54
|
-
|
|
55
|
-
// ===========================================================
|
|
56
|
-
// 基本場景
|
|
57
|
-
// ===========================================================
|
|
58
|
-
describe('基本場景', function() {
|
|
59
|
-
|
|
60
|
-
it('單一使用者、單一群組、單一權限、單一target — 授權 y', function() {
|
|
61
|
-
let targets = [t('A')]
|
|
62
|
-
let pemis = [p('P1', { A: 'y' })]
|
|
63
|
-
let grups = [g('G1', { P1: OR })]
|
|
64
|
-
let user = u({ G1: OR })
|
|
65
|
-
|
|
66
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
67
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
it('單一使用者、單一群組、單一權限、單一target — 拒絕 n', function() {
|
|
71
|
-
let targets = [t('A')]
|
|
72
|
-
let pemis = [p('P1', { A: 'n' })]
|
|
73
|
-
let grups = [g('G1', { P1: OR })]
|
|
74
|
-
let user = u({ G1: OR })
|
|
75
|
-
|
|
76
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
77
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'n')
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
it('使用者沒有任何群組 — 全部 target 預設 n', function() {
|
|
81
|
-
let targets = [t('A'), t('B')]
|
|
82
|
-
let pemis = [p('P1', { A: 'y' })]
|
|
83
|
-
let grups = [g('G1', { P1: OR })]
|
|
84
|
-
let user = u({})
|
|
85
|
-
|
|
86
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
87
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'n')
|
|
88
|
-
assert.strictEqual(ruleOf(rules, 'B'), 'n')
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
it('cgrups 為空字串 — 不會拋錯、全部 target 預設 n', function() {
|
|
92
|
-
let targets = [t('A')]
|
|
93
|
-
let pemis = []
|
|
94
|
-
let grups = []
|
|
95
|
-
let user = { cgrups: '' }
|
|
96
|
-
|
|
97
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
98
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'n')
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
it('targets 為空陣列 — 回傳空 rules', function() {
|
|
102
|
-
let targets = []
|
|
103
|
-
let pemis = [p('P1', { A: 'y' })]
|
|
104
|
-
let grups = [g('G1', { P1: OR })]
|
|
105
|
-
let user = u({ G1: OR })
|
|
106
|
-
|
|
107
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
108
|
-
// 沒有 targets 需要展開,但 crules 中的 A 仍在 rules 中
|
|
109
|
-
// A 不在 targets 中,但 merge 結果會包含它
|
|
110
|
-
assert.ok(Array.isArray(rules))
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
// ===========================================================
|
|
117
|
-
// target 展開(未提及的 target 預設 'n')
|
|
118
|
-
// ===========================================================
|
|
119
|
-
describe('target 展開', function() {
|
|
120
|
-
|
|
121
|
-
it('未被任何權限提及的 target 預設為 n', function() {
|
|
122
|
-
let targets = [t('A'), t('B'), t('C')]
|
|
123
|
-
let pemis = [p('P1', { A: 'y' })]
|
|
124
|
-
let grups = [g('G1', { P1: OR })]
|
|
125
|
-
let user = u({ G1: OR })
|
|
126
|
-
|
|
127
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
128
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
129
|
-
assert.strictEqual(ruleOf(rules, 'B'), 'n')
|
|
130
|
-
assert.strictEqual(ruleOf(rules, 'C'), 'n')
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
it('多個權限覆蓋部分 targets — 其餘仍為 n', function() {
|
|
134
|
-
let targets = [t('A'), t('B'), t('C'), t('D')]
|
|
135
|
-
let pemis = [
|
|
136
|
-
p('P1', { A: 'y', B: 'n' }),
|
|
137
|
-
p('P2', { C: 'y' }),
|
|
138
|
-
]
|
|
139
|
-
let grups = [g('G1', { P1: OR, P2: OR })]
|
|
140
|
-
let user = u({ G1: OR })
|
|
141
|
-
|
|
142
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
143
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
144
|
-
assert.strictEqual(ruleOf(rules, 'B'), 'n')
|
|
145
|
-
assert.strictEqual(ruleOf(rules, 'C'), 'y')
|
|
146
|
-
assert.strictEqual(ruleOf(rules, 'D'), 'n')
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
// ===========================================================
|
|
153
|
-
// OR 模式合併
|
|
154
|
-
// ===========================================================
|
|
155
|
-
describe('OR 模式 — 權限層級', function() {
|
|
156
|
-
|
|
157
|
-
it('兩個權限 OR:其中一個 y 另一個 n → y', function() {
|
|
158
|
-
let targets = [t('A')]
|
|
159
|
-
let pemis = [
|
|
160
|
-
p('P1', { A: 'y' }),
|
|
161
|
-
p('P2', { A: 'n' }),
|
|
162
|
-
]
|
|
163
|
-
let grups = [g('G1', { P1: OR, P2: OR })]
|
|
164
|
-
let user = u({ G1: OR })
|
|
165
|
-
|
|
166
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
167
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
it('兩個權限 OR:兩個都 n → n', function() {
|
|
171
|
-
let targets = [t('A')]
|
|
172
|
-
let pemis = [
|
|
173
|
-
p('P1', { A: 'n' }),
|
|
174
|
-
p('P2', { A: 'n' }),
|
|
175
|
-
]
|
|
176
|
-
let grups = [g('G1', { P1: OR, P2: OR })]
|
|
177
|
-
let user = u({ G1: OR })
|
|
178
|
-
|
|
179
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
180
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'n')
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
it('兩個權限 OR:互不重疊的 target 聯集', function() {
|
|
184
|
-
let targets = [t('A'), t('B')]
|
|
185
|
-
let pemis = [
|
|
186
|
-
p('P1', { A: 'y' }),
|
|
187
|
-
p('P2', { B: 'y' }),
|
|
188
|
-
]
|
|
189
|
-
let grups = [g('G1', { P1: OR, P2: OR })]
|
|
190
|
-
let user = u({ G1: OR })
|
|
191
|
-
|
|
192
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
193
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
194
|
-
assert.strictEqual(ruleOf(rules, 'B'), 'y')
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
it('三個權限 OR:漸進聯集', function() {
|
|
198
|
-
let targets = [t('A'), t('B'), t('C')]
|
|
199
|
-
let pemis = [
|
|
200
|
-
p('P1', { A: 'y', B: 'n', C: 'n' }),
|
|
201
|
-
p('P2', { A: 'n', B: 'y', C: 'n' }),
|
|
202
|
-
p('P3', { A: 'n', B: 'n', C: 'y' }),
|
|
203
|
-
]
|
|
204
|
-
let grups = [g('G1', { P1: OR, P2: OR, P3: OR })]
|
|
205
|
-
let user = u({ G1: OR })
|
|
206
|
-
|
|
207
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
208
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
209
|
-
assert.strictEqual(ruleOf(rules, 'B'), 'y')
|
|
210
|
-
assert.strictEqual(ruleOf(rules, 'C'), 'y')
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
describe('OR 模式 — 群組層級', function() {
|
|
216
|
-
|
|
217
|
-
it('兩個群組 OR:其中一個群組授權 y → y', function() {
|
|
218
|
-
let targets = [t('A')]
|
|
219
|
-
let pemis = [
|
|
220
|
-
p('P1', { A: 'y' }),
|
|
221
|
-
p('P2', { A: 'n' }),
|
|
222
|
-
]
|
|
223
|
-
let grups = [
|
|
224
|
-
g('G1', { P1: OR }),
|
|
225
|
-
g('G2', { P2: OR }),
|
|
226
|
-
]
|
|
227
|
-
let user = u({ G1: OR, G2: OR })
|
|
228
|
-
|
|
229
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
230
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
231
|
-
})
|
|
232
|
-
|
|
233
|
-
it('兩個群組 OR:互不重疊的 target 聯集', function() {
|
|
234
|
-
let targets = [t('A'), t('B')]
|
|
235
|
-
let pemis = [
|
|
236
|
-
p('P1', { A: 'y' }),
|
|
237
|
-
p('P2', { B: 'y' }),
|
|
238
|
-
]
|
|
239
|
-
let grups = [
|
|
240
|
-
g('G1', { P1: OR }),
|
|
241
|
-
g('G2', { P2: OR }),
|
|
242
|
-
]
|
|
243
|
-
let user = u({ G1: OR, G2: OR })
|
|
244
|
-
|
|
245
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
246
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
247
|
-
assert.strictEqual(ruleOf(rules, 'B'), 'y')
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
})
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
// ===========================================================
|
|
254
|
-
// AND 模式合併
|
|
255
|
-
// ===========================================================
|
|
256
|
-
describe('AND 模式 — 權限層級', function() {
|
|
257
|
-
|
|
258
|
-
it('兩個權限 AND:都是 y → y', function() {
|
|
259
|
-
let targets = [t('A')]
|
|
260
|
-
let pemis = [
|
|
261
|
-
p('P1', { A: 'y' }),
|
|
262
|
-
p('P2', { A: 'y' }),
|
|
263
|
-
]
|
|
264
|
-
let grups = [g('G1', { P1: AND, P2: AND })]
|
|
265
|
-
let user = u({ G1: OR })
|
|
266
|
-
|
|
267
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
268
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
269
|
-
})
|
|
270
|
-
|
|
271
|
-
it('兩個權限 AND:一個 y 一個 n → n', function() {
|
|
272
|
-
let targets = [t('A')]
|
|
273
|
-
let pemis = [
|
|
274
|
-
p('P1', { A: 'y' }),
|
|
275
|
-
p('P2', { A: 'n' }),
|
|
276
|
-
]
|
|
277
|
-
let grups = [g('G1', { P1: AND, P2: AND })]
|
|
278
|
-
let user = u({ G1: OR })
|
|
279
|
-
|
|
280
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
281
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'n')
|
|
282
|
-
})
|
|
283
|
-
|
|
284
|
-
it('AND 非對稱性:key 只存在於 obj1 → 保留 obj1 的值', function() {
|
|
285
|
-
// P1 有 A 和 B,P2 只有 A
|
|
286
|
-
// AND 以 P1 為基底,P2 只影響 A
|
|
287
|
-
// B 不在 P2 中,保留 P1 的值
|
|
288
|
-
let targets = [t('A'), t('B')]
|
|
289
|
-
let pemis = [
|
|
290
|
-
p('P1', { A: 'y', B: 'y' }),
|
|
291
|
-
p('P2', { A: 'y' }),
|
|
292
|
-
]
|
|
293
|
-
let grups = [g('G1', { P1: AND, P2: AND })]
|
|
294
|
-
let user = u({ G1: OR })
|
|
295
|
-
|
|
296
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
297
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
298
|
-
assert.strictEqual(ruleOf(rules, 'B'), 'y') // B 保留自 P1
|
|
299
|
-
})
|
|
300
|
-
|
|
301
|
-
it('AND 非對稱性:key 只存在於 obj2 → 強制為 n', function() {
|
|
302
|
-
// P1 只有 A,P2 有 A 和 B
|
|
303
|
-
// AND 以 P1 為基底 {A:'y'},遍歷 P2:
|
|
304
|
-
// A: 都是 y → y
|
|
305
|
-
// B: 不在 P1 → 加入為 n
|
|
306
|
-
let targets = [t('A'), t('B')]
|
|
307
|
-
let pemis = [
|
|
308
|
-
p('P1', { A: 'y' }),
|
|
309
|
-
p('P2', { A: 'y', B: 'y' }),
|
|
310
|
-
]
|
|
311
|
-
let grups = [g('G1', { P1: AND, P2: AND })]
|
|
312
|
-
let user = u({ G1: OR })
|
|
313
|
-
|
|
314
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
315
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
316
|
-
assert.strictEqual(ruleOf(rules, 'B'), 'n') // B 不在 P1,強制 n
|
|
317
|
-
})
|
|
318
|
-
|
|
319
|
-
})
|
|
320
|
-
|
|
321
|
-
describe('AND 模式 — 群組層級', function() {
|
|
322
|
-
|
|
323
|
-
it('兩個群組 AND:同一 target 都授權 → y', function() {
|
|
324
|
-
let targets = [t('A')]
|
|
325
|
-
let pemis = [
|
|
326
|
-
p('P1', { A: 'y' }),
|
|
327
|
-
p('P2', { A: 'y' }),
|
|
328
|
-
]
|
|
329
|
-
let grups = [
|
|
330
|
-
g('G1', { P1: OR }),
|
|
331
|
-
g('G2', { P2: OR }),
|
|
332
|
-
]
|
|
333
|
-
let user = u({ G1: AND, G2: AND })
|
|
334
|
-
|
|
335
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
336
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
337
|
-
})
|
|
338
|
-
|
|
339
|
-
it('兩個群組 AND:一個授權一個拒絕 → n', function() {
|
|
340
|
-
let targets = [t('A')]
|
|
341
|
-
let pemis = [
|
|
342
|
-
p('P1', { A: 'y' }),
|
|
343
|
-
p('P2', { A: 'n' }),
|
|
344
|
-
]
|
|
345
|
-
let grups = [
|
|
346
|
-
g('G1', { P1: OR }),
|
|
347
|
-
g('G2', { P2: OR }),
|
|
348
|
-
]
|
|
349
|
-
let user = u({ G1: AND, G2: AND })
|
|
350
|
-
|
|
351
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
352
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'n')
|
|
353
|
-
})
|
|
354
|
-
|
|
355
|
-
})
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
// ===========================================================
|
|
359
|
-
// 混合 OR/AND
|
|
360
|
-
// ===========================================================
|
|
361
|
-
describe('混合 OR/AND', function() {
|
|
362
|
-
|
|
363
|
-
it('權限層級混合:OR 和 AND 權限共存於同一群組', function() {
|
|
364
|
-
// P1(OR): A=y, B=n
|
|
365
|
-
// P2(OR): A=n, B=y
|
|
366
|
-
// P3(AND): A=y, B=y
|
|
367
|
-
//
|
|
368
|
-
// Step1 OR: P1 OR P2 = {A:'y', B:'y'}
|
|
369
|
-
// Step2 AND: {A:'y', B:'y'} AND P3{A:'y', B:'y'} = {A:'y', B:'y'}
|
|
370
|
-
let targets = [t('A'), t('B')]
|
|
371
|
-
let pemis = [
|
|
372
|
-
p('P1', { A: 'y', B: 'n' }),
|
|
373
|
-
p('P2', { A: 'n', B: 'y' }),
|
|
374
|
-
p('P3', { A: 'y', B: 'y' }),
|
|
375
|
-
]
|
|
376
|
-
let grups = [g('G1', { P1: OR, P2: OR, P3: AND })]
|
|
377
|
-
let user = u({ G1: OR })
|
|
378
|
-
|
|
379
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
380
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
381
|
-
assert.strictEqual(ruleOf(rules, 'B'), 'y')
|
|
382
|
-
})
|
|
383
|
-
|
|
384
|
-
it('權限層級混合:AND 收緊 OR 結果', function() {
|
|
385
|
-
// P1(OR): A=y, B=y
|
|
386
|
-
// P2(AND): A=y, B=n
|
|
387
|
-
//
|
|
388
|
-
// Step1 OR: P1 = {A:'y', B:'y'}
|
|
389
|
-
// Step2 AND: {A:'y', B:'y'} AND {A:'y', B:'n'} = {A:'y', B:'n'}
|
|
390
|
-
let targets = [t('A'), t('B')]
|
|
391
|
-
let pemis = [
|
|
392
|
-
p('P1', { A: 'y', B: 'y' }),
|
|
393
|
-
p('P2', { A: 'y', B: 'n' }),
|
|
394
|
-
]
|
|
395
|
-
let grups = [g('G1', { P1: OR, P2: AND })]
|
|
396
|
-
let user = u({ G1: OR })
|
|
397
|
-
|
|
398
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
399
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
400
|
-
assert.strictEqual(ruleOf(rules, 'B'), 'n') // AND 收緊
|
|
401
|
-
})
|
|
402
|
-
|
|
403
|
-
it('群組層級混合:OR 群組 + AND 群組', function() {
|
|
404
|
-
// G1(OR): P1 → {A:'y', B:'y'}
|
|
405
|
-
// G2(AND): P2 → {A:'y', B:'n'}
|
|
406
|
-
//
|
|
407
|
-
// Step1 OR groups: G1 = {A:'y', B:'y'}
|
|
408
|
-
// Step2 AND groups: {A:'y', B:'y'} AND G2{A:'y', B:'n'} = {A:'y', B:'n'}
|
|
409
|
-
let targets = [t('A'), t('B')]
|
|
410
|
-
let pemis = [
|
|
411
|
-
p('P1', { A: 'y', B: 'y' }),
|
|
412
|
-
p('P2', { A: 'y', B: 'n' }),
|
|
413
|
-
]
|
|
414
|
-
let grups = [
|
|
415
|
-
g('G1', { P1: OR }),
|
|
416
|
-
g('G2', { P2: OR }),
|
|
417
|
-
]
|
|
418
|
-
let user = u({ G1: OR, G2: AND })
|
|
419
|
-
|
|
420
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
421
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
422
|
-
assert.strictEqual(ruleOf(rules, 'B'), 'n')
|
|
423
|
-
})
|
|
424
|
-
|
|
425
|
-
it('群組層級混合:多 OR + 多 AND 交互', function() {
|
|
426
|
-
// G1(OR): P1 → {A:'y', B:'n', C:'n'}
|
|
427
|
-
// G2(OR): P2 → {A:'n', B:'y', C:'n'}
|
|
428
|
-
// G3(AND): P3 → {A:'y', B:'y', C:'y'}
|
|
429
|
-
//
|
|
430
|
-
// OR: G1 OR G2 = {A:'y', B:'y', C:'n'}
|
|
431
|
-
// AND: {A:'y', B:'y', C:'n'} AND G3{A:'y', B:'y', C:'y'} = {A:'y', B:'y', C:'n'}
|
|
432
|
-
let targets = [t('A'), t('B'), t('C')]
|
|
433
|
-
let pemis = [
|
|
434
|
-
p('P1', { A: 'y', B: 'n', C: 'n' }),
|
|
435
|
-
p('P2', { A: 'n', B: 'y', C: 'n' }),
|
|
436
|
-
p('P3', { A: 'y', B: 'y', C: 'y' }),
|
|
437
|
-
]
|
|
438
|
-
let grups = [
|
|
439
|
-
g('G1', { P1: OR }),
|
|
440
|
-
g('G2', { P2: OR }),
|
|
441
|
-
g('G3', { P3: OR }),
|
|
442
|
-
]
|
|
443
|
-
let user = u({ G1: OR, G2: OR, G3: AND })
|
|
444
|
-
|
|
445
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
446
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
447
|
-
assert.strictEqual(ruleOf(rules, 'B'), 'y')
|
|
448
|
-
assert.strictEqual(ruleOf(rules, 'C'), 'n') // OR 結果 C=n,AND 不會變 y
|
|
449
|
-
})
|
|
450
|
-
|
|
451
|
-
})
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
// ===========================================================
|
|
455
|
-
// isActive 過濾
|
|
456
|
-
// ===========================================================
|
|
457
|
-
describe('isActive 過濾', function() {
|
|
458
|
-
|
|
459
|
-
it('群組 isActive=n — 該群組被忽略', function() {
|
|
460
|
-
let targets = [t('A')]
|
|
461
|
-
let pemis = [p('P1', { A: 'y' })]
|
|
462
|
-
let grups = [g('G1', { P1: OR })]
|
|
463
|
-
let user = u({ G1: { mode: 'OR', isActive: 'n' } })
|
|
464
|
-
|
|
465
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
466
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'n') // 群組被忽略,預設 n
|
|
467
|
-
})
|
|
468
|
-
|
|
469
|
-
it('權限 isActive=n — 該權限被忽略', function() {
|
|
470
|
-
let targets = [t('A')]
|
|
471
|
-
let pemis = [
|
|
472
|
-
p('P1', { A: 'y' }),
|
|
473
|
-
p('P2', { A: 'n' }),
|
|
474
|
-
]
|
|
475
|
-
let grups = [g('G1', { P1: OR_OFF, P2: OR })]
|
|
476
|
-
let user = u({ G1: OR })
|
|
477
|
-
|
|
478
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
479
|
-
// P1 被關閉,只剩 P2(A=n)
|
|
480
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'n')
|
|
481
|
-
})
|
|
482
|
-
|
|
483
|
-
it('全部群組皆 inactive — 全部 target 為 n', function() {
|
|
484
|
-
let targets = [t('A'), t('B')]
|
|
485
|
-
let pemis = [p('P1', { A: 'y', B: 'y' })]
|
|
486
|
-
let grups = [g('G1', { P1: OR })]
|
|
487
|
-
let user = u({
|
|
488
|
-
G1: { mode: 'OR', isActive: 'n' },
|
|
489
|
-
})
|
|
490
|
-
|
|
491
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
492
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'n')
|
|
493
|
-
assert.strictEqual(ruleOf(rules, 'B'), 'n')
|
|
494
|
-
})
|
|
495
|
-
|
|
496
|
-
it('混合 active/inactive 權限', function() {
|
|
497
|
-
let targets = [t('A'), t('B')]
|
|
498
|
-
let pemis = [
|
|
499
|
-
p('P1', { A: 'y', B: 'n' }),
|
|
500
|
-
p('P2', { A: 'n', B: 'y' }),
|
|
501
|
-
]
|
|
502
|
-
// P1 啟用, P2 停用 → 只有 P1 生效
|
|
503
|
-
let grups = [g('G1', { P1: OR, P2: OR_OFF })]
|
|
504
|
-
let user = u({ G1: OR })
|
|
505
|
-
|
|
506
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
507
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
508
|
-
assert.strictEqual(ruleOf(rules, 'B'), 'n')
|
|
509
|
-
})
|
|
510
|
-
|
|
511
|
-
it('群組內所有權限皆 inactive — 該群組產出空 rules', function() {
|
|
512
|
-
let targets = [t('A')]
|
|
513
|
-
let pemis = [p('P1', { A: 'y' })]
|
|
514
|
-
let grups = [g('G1', { P1: OR_OFF })]
|
|
515
|
-
let user = u({ G1: OR })
|
|
516
|
-
|
|
517
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
518
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'n')
|
|
519
|
-
})
|
|
520
|
-
|
|
521
|
-
})
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
// ===========================================================
|
|
525
|
-
// 名稱匹配(找不到對應的 group/permission)
|
|
526
|
-
// ===========================================================
|
|
527
|
-
describe('名稱匹配失敗', function() {
|
|
528
|
-
|
|
529
|
-
it('使用者引用不存在的群組 — 被忽略', function() {
|
|
530
|
-
let targets = [t('A')]
|
|
531
|
-
let pemis = [p('P1', { A: 'y' })]
|
|
532
|
-
let grups = [g('G1', { P1: OR })]
|
|
533
|
-
let user = u({ G_NOT_EXIST: OR })
|
|
534
|
-
|
|
535
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
536
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'n')
|
|
537
|
-
})
|
|
538
|
-
|
|
539
|
-
it('群組引用不存在的權限 — 被忽略', function() {
|
|
540
|
-
let targets = [t('A')]
|
|
541
|
-
let pemis = [p('P1', { A: 'y' })]
|
|
542
|
-
let grups = [g('G1', { P_NOT_EXIST: OR })]
|
|
543
|
-
let user = u({ G1: OR })
|
|
544
|
-
|
|
545
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
546
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'n')
|
|
547
|
-
})
|
|
548
|
-
|
|
549
|
-
it('部分匹配 — 只有匹配到的生效', function() {
|
|
550
|
-
let targets = [t('A'), t('B')]
|
|
551
|
-
let pemis = [p('P1', { A: 'y' })]
|
|
552
|
-
let grups = [g('G1', { P1: OR, P_NOT_EXIST: OR })]
|
|
553
|
-
let user = u({ G1: OR })
|
|
554
|
-
|
|
555
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
556
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
557
|
-
assert.strictEqual(ruleOf(rules, 'B'), 'n')
|
|
558
|
-
})
|
|
559
|
-
|
|
560
|
-
})
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
// ===========================================================
|
|
564
|
-
// 邊界情況
|
|
565
|
-
// ===========================================================
|
|
566
|
-
describe('邊界情況', function() {
|
|
567
|
-
|
|
568
|
-
it('權限的 crules 為空物件 — 不產出任何 rule', function() {
|
|
569
|
-
let targets = [t('A')]
|
|
570
|
-
let pemis = [p('P1', {})]
|
|
571
|
-
let grups = [g('G1', { P1: OR })]
|
|
572
|
-
let user = u({ G1: OR })
|
|
573
|
-
|
|
574
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
575
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'n')
|
|
576
|
-
})
|
|
577
|
-
|
|
578
|
-
it('單一權限覆蓋多個 targets', function() {
|
|
579
|
-
let targets = [t('A'), t('B'), t('C'), t('D'), t('E')]
|
|
580
|
-
let pemis = [p('P1', { A: 'y', B: 'y', C: 'n', D: 'y', E: 'n' })]
|
|
581
|
-
let grups = [g('G1', { P1: OR })]
|
|
582
|
-
let user = u({ G1: OR })
|
|
583
|
-
|
|
584
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
585
|
-
let m = rulesToMap(rules)
|
|
586
|
-
assert.deepStrictEqual(
|
|
587
|
-
{ A: m.A, B: m.B, C: m.C, D: m.D, E: m.E },
|
|
588
|
-
{ A: 'y', B: 'y', C: 'n', D: 'y', E: 'n' }
|
|
589
|
-
)
|
|
590
|
-
})
|
|
591
|
-
|
|
592
|
-
it('回傳結構包含 grups 和 rules', function() {
|
|
593
|
-
let targets = [t('A')]
|
|
594
|
-
let pemis = [p('P1', { A: 'y' })]
|
|
595
|
-
let grups = [g('G1', { P1: OR })]
|
|
596
|
-
let user = u({ G1: OR })
|
|
597
|
-
|
|
598
|
-
let result = getUserRules(user, grups, pemis, targets)
|
|
599
|
-
assert.ok(Array.isArray(result.grups))
|
|
600
|
-
assert.ok(Array.isArray(result.rules))
|
|
601
|
-
})
|
|
602
|
-
|
|
603
|
-
it('grups 回傳中僅包含 active 且匹配的群組', function() {
|
|
604
|
-
let targets = [t('A')]
|
|
605
|
-
let pemis = [p('P1', { A: 'y' })]
|
|
606
|
-
let grups = [g('G1', { P1: OR }), g('G2', { P1: OR })]
|
|
607
|
-
let user = u({
|
|
608
|
-
G1: OR,
|
|
609
|
-
G2: { mode: 'OR', isActive: 'n' },
|
|
610
|
-
G3: OR, // 不存在
|
|
611
|
-
})
|
|
612
|
-
|
|
613
|
-
let result = getUserRules(user, grups, pemis, targets)
|
|
614
|
-
// 只有 G1 是 active 且存在的
|
|
615
|
-
assert.strictEqual(result.grups.length, 1)
|
|
616
|
-
assert.strictEqual(result.grups[0].name, 'G1')
|
|
617
|
-
})
|
|
618
|
-
|
|
619
|
-
})
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
// ===========================================================
|
|
623
|
-
// 複雜實際場景
|
|
624
|
-
// ===========================================================
|
|
625
|
-
describe('複雜實際場景', function() {
|
|
626
|
-
|
|
627
|
-
it('模擬完整權限樹:多使用者群組、多權限、多 target', function() {
|
|
628
|
-
// Targets: 頁面結構
|
|
629
|
-
let targets = [
|
|
630
|
-
t('專案A/頁A'),
|
|
631
|
-
t('專案A/頁B'),
|
|
632
|
-
t('專案A/頁A/按鈕1'),
|
|
633
|
-
t('專案B/頁A'),
|
|
634
|
-
]
|
|
635
|
-
|
|
636
|
-
// Permissions
|
|
637
|
-
let pemis = [
|
|
638
|
-
p('閱覽權', { '專案A/頁A': 'y', '專案A/頁B': 'y', '專案A/頁A/按鈕1': 'n' }),
|
|
639
|
-
p('執行權', { '專案A/頁A/按鈕1': 'y' }),
|
|
640
|
-
p('專案B全權', { '專案B/頁A': 'y' }),
|
|
641
|
-
]
|
|
642
|
-
|
|
643
|
-
// Groups
|
|
644
|
-
let grups = [
|
|
645
|
-
g('基本瀏覽組', { '閱覽權': OR }),
|
|
646
|
-
g('操作員組', { '閱覽權': OR, '執行權': OR }),
|
|
647
|
-
g('專案B組', { '專案B全權': OR }),
|
|
648
|
-
]
|
|
649
|
-
|
|
650
|
-
// User: 操作員 + 專案B (OR 模式)
|
|
651
|
-
let user = u({ '操作員組': OR, '專案B組': OR })
|
|
652
|
-
|
|
653
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
654
|
-
let m = rulesToMap(rules)
|
|
655
|
-
|
|
656
|
-
assert.strictEqual(m['專案A/頁A'], 'y')
|
|
657
|
-
assert.strictEqual(m['專案A/頁B'], 'y')
|
|
658
|
-
assert.strictEqual(m['專案A/頁A/按鈕1'], 'y') // 執行權 OR 閱覽權(n) = y
|
|
659
|
-
assert.strictEqual(m['專案B/頁A'], 'y')
|
|
660
|
-
})
|
|
661
|
-
|
|
662
|
-
it('模擬 AND 限制:必須同時屬於兩個群組才有完整權限', function() {
|
|
663
|
-
let targets = [t('機密區'), t('一般區')]
|
|
664
|
-
|
|
665
|
-
let pemis = [
|
|
666
|
-
p('部門A存取', { '機密區': 'y', '一般區': 'y' }),
|
|
667
|
-
p('安全認證', { '機密區': 'y', '一般區': 'y' }),
|
|
668
|
-
]
|
|
669
|
-
|
|
670
|
-
let grups = [
|
|
671
|
-
g('部門A', { '部門A存取': OR }),
|
|
672
|
-
g('安全組', { '安全認證': OR }),
|
|
673
|
-
]
|
|
674
|
-
|
|
675
|
-
// 必須同時屬於部門A且通過安全認證(AND)
|
|
676
|
-
let user = u({ '部門A': AND, '安全組': AND })
|
|
677
|
-
|
|
678
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
679
|
-
let m = rulesToMap(rules)
|
|
680
|
-
|
|
681
|
-
assert.strictEqual(m['機密區'], 'y') // 兩者都 y → y
|
|
682
|
-
assert.strictEqual(m['一般區'], 'y')
|
|
683
|
-
})
|
|
684
|
-
|
|
685
|
-
it('模擬 AND 限制:缺少一個群組的授權', function() {
|
|
686
|
-
let targets = [t('機密區'), t('一般區')]
|
|
687
|
-
|
|
688
|
-
let pemis = [
|
|
689
|
-
p('部門A存取', { '機密區': 'y', '一般區': 'y' }),
|
|
690
|
-
p('安全認證', { '機密區': 'n', '一般區': 'y' }),
|
|
691
|
-
]
|
|
692
|
-
|
|
693
|
-
let grups = [
|
|
694
|
-
g('部門A', { '部門A存取': OR }),
|
|
695
|
-
g('安全組', { '安全認證': OR }),
|
|
696
|
-
]
|
|
697
|
-
|
|
698
|
-
let user = u({ '部門A': AND, '安全組': AND })
|
|
699
|
-
|
|
700
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
701
|
-
let m = rulesToMap(rules)
|
|
702
|
-
|
|
703
|
-
assert.strictEqual(m['機密區'], 'n') // 安全認證拒絕 → AND 結果為 n
|
|
704
|
-
assert.strictEqual(m['一般區'], 'y') // 兩者都 y → y
|
|
705
|
-
})
|
|
706
|
-
|
|
707
|
-
it('大量 targets 與稀疏權限 — 未涵蓋全部為 n', function() {
|
|
708
|
-
let targets = []
|
|
709
|
-
for (let i = 0; i < 50; i++) {
|
|
710
|
-
targets.push(t(`target-${i}`))
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
// 只授權前 3 個
|
|
714
|
-
let pemis = [p('P1', { 'target-0': 'y', 'target-1': 'y', 'target-2': 'y' })]
|
|
715
|
-
let grups = [g('G1', { P1: OR })]
|
|
716
|
-
let user = u({ G1: OR })
|
|
717
|
-
|
|
718
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
719
|
-
let m = rulesToMap(rules)
|
|
720
|
-
|
|
721
|
-
assert.strictEqual(m['target-0'], 'y')
|
|
722
|
-
assert.strictEqual(m['target-1'], 'y')
|
|
723
|
-
assert.strictEqual(m['target-2'], 'y')
|
|
724
|
-
assert.strictEqual(m['target-3'], 'n')
|
|
725
|
-
assert.strictEqual(m['target-49'], 'n')
|
|
726
|
-
|
|
727
|
-
// 確保所有 50 個 target 都有 rule
|
|
728
|
-
let targetNames = targets.map((v) => v.id)
|
|
729
|
-
targetNames.forEach((name) => {
|
|
730
|
-
assert.ok(m[name] !== undefined, `target ${name} should have a rule`)
|
|
731
|
-
})
|
|
732
|
-
})
|
|
733
|
-
|
|
734
|
-
})
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
// ===========================================================
|
|
738
|
-
// mergeRules 處理順序:OR 先、AND 後
|
|
739
|
-
// ===========================================================
|
|
740
|
-
describe('mergeRules 處理順序', function() {
|
|
741
|
-
|
|
742
|
-
it('OR 先執行再 AND — AND 可從 OR 結果收緊', function() {
|
|
743
|
-
// P1(OR): {A:'y', B:'y', C:'y'}
|
|
744
|
-
// P2(AND): {A:'y', B:'n', C:'y'}
|
|
745
|
-
//
|
|
746
|
-
// OR result: {A:'y', B:'y', C:'y'}
|
|
747
|
-
// AND: {A:'y', B:'n', C:'y'}
|
|
748
|
-
// Final: {A:'y', B:'n', C:'y'}
|
|
749
|
-
let targets = [t('A'), t('B'), t('C')]
|
|
750
|
-
let pemis = [
|
|
751
|
-
p('P1', { A: 'y', B: 'y', C: 'y' }),
|
|
752
|
-
p('P2', { A: 'y', B: 'n', C: 'y' }),
|
|
753
|
-
]
|
|
754
|
-
let grups = [g('G1', { P1: OR, P2: AND })]
|
|
755
|
-
let user = u({ G1: OR })
|
|
756
|
-
|
|
757
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
758
|
-
let m = rulesToMap(rules)
|
|
759
|
-
assert.strictEqual(m.A, 'y')
|
|
760
|
-
assert.strictEqual(m.B, 'n')
|
|
761
|
-
assert.strictEqual(m.C, 'y')
|
|
762
|
-
})
|
|
763
|
-
|
|
764
|
-
it('純 AND 無 OR — 以第一筆為基底逐步交集', function() {
|
|
765
|
-
// P1(AND): {A:'y', B:'y', C:'n'}
|
|
766
|
-
// P2(AND): {A:'y', B:'n', C:'y'}
|
|
767
|
-
//
|
|
768
|
-
// AND: P1 AND P2 = {A:'y', B:'n', C:'n'}
|
|
769
|
-
let targets = [t('A'), t('B'), t('C')]
|
|
770
|
-
let pemis = [
|
|
771
|
-
p('P1', { A: 'y', B: 'y', C: 'n' }),
|
|
772
|
-
p('P2', { A: 'y', B: 'n', C: 'y' }),
|
|
773
|
-
]
|
|
774
|
-
let grups = [g('G1', { P1: AND, P2: AND })]
|
|
775
|
-
let user = u({ G1: OR })
|
|
776
|
-
|
|
777
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
778
|
-
let m = rulesToMap(rules)
|
|
779
|
-
assert.strictEqual(m.A, 'y')
|
|
780
|
-
assert.strictEqual(m.B, 'n')
|
|
781
|
-
assert.strictEqual(m.C, 'n')
|
|
782
|
-
})
|
|
783
|
-
|
|
784
|
-
it('多 OR + 多 AND 權限 — 驗證最終結果', function() {
|
|
785
|
-
// P1(OR): {A:'y', B:'n'}
|
|
786
|
-
// P2(OR): {A:'n', B:'y'}
|
|
787
|
-
// P3(AND): {A:'y', B:'y'}
|
|
788
|
-
// P4(AND): {A:'y', B:'n'}
|
|
789
|
-
//
|
|
790
|
-
// OR: P1 OR P2 = {A:'y', B:'y'}
|
|
791
|
-
// AND step1: {A:'y', B:'y'} AND P3{A:'y', B:'y'} = {A:'y', B:'y'}
|
|
792
|
-
// AND step2: {A:'y', B:'y'} AND P4{A:'y', B:'n'} = {A:'y', B:'n'}
|
|
793
|
-
let targets = [t('A'), t('B')]
|
|
794
|
-
let pemis = [
|
|
795
|
-
p('P1', { A: 'y', B: 'n' }),
|
|
796
|
-
p('P2', { A: 'n', B: 'y' }),
|
|
797
|
-
p('P3', { A: 'y', B: 'y' }),
|
|
798
|
-
p('P4', { A: 'y', B: 'n' }),
|
|
799
|
-
]
|
|
800
|
-
let grups = [g('G1', { P1: OR, P2: OR, P3: AND, P4: AND })]
|
|
801
|
-
let user = u({ G1: OR })
|
|
802
|
-
|
|
803
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
804
|
-
let m = rulesToMap(rules)
|
|
805
|
-
assert.strictEqual(m.A, 'y')
|
|
806
|
-
assert.strictEqual(m.B, 'n') // P4 的 AND 收緊
|
|
807
|
-
})
|
|
808
|
-
|
|
809
|
-
})
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
// ===========================================================
|
|
813
|
-
// 兩層巢狀合併(群組內合併 + 群組間合併)
|
|
814
|
-
// ===========================================================
|
|
815
|
-
describe('兩層巢狀合併', function() {
|
|
816
|
-
|
|
817
|
-
it('群組內 OR 合併後,群組間再 AND', function() {
|
|
818
|
-
// G1 (OR mode at group level):
|
|
819
|
-
// P1(OR): {A:'y', B:'n'}
|
|
820
|
-
// P2(OR): {A:'n', B:'y'}
|
|
821
|
-
// → 群組內 OR = {A:'y', B:'y'}
|
|
822
|
-
//
|
|
823
|
-
// G2 (AND mode at group level):
|
|
824
|
-
// P3(OR): {A:'y', B:'n'}
|
|
825
|
-
// → 群組內 = {A:'y', B:'n'}
|
|
826
|
-
//
|
|
827
|
-
// 群組間:G1(OR) then AND G2
|
|
828
|
-
// OR result = {A:'y', B:'y'}
|
|
829
|
-
// AND result = {A:'y', B:'y'} AND {A:'y', B:'n'} = {A:'y', B:'n'}
|
|
830
|
-
let targets = [t('A'), t('B')]
|
|
831
|
-
let pemis = [
|
|
832
|
-
p('P1', { A: 'y', B: 'n' }),
|
|
833
|
-
p('P2', { A: 'n', B: 'y' }),
|
|
834
|
-
p('P3', { A: 'y', B: 'n' }),
|
|
835
|
-
]
|
|
836
|
-
let grups = [
|
|
837
|
-
g('G1', { P1: OR, P2: OR }),
|
|
838
|
-
g('G2', { P3: OR }),
|
|
839
|
-
]
|
|
840
|
-
let user = u({ G1: OR, G2: AND })
|
|
841
|
-
|
|
842
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
843
|
-
let m = rulesToMap(rules)
|
|
844
|
-
assert.strictEqual(m.A, 'y')
|
|
845
|
-
assert.strictEqual(m.B, 'n')
|
|
846
|
-
})
|
|
847
|
-
|
|
848
|
-
it('群組內 AND 合併後,群組間再 OR', function() {
|
|
849
|
-
// G1:
|
|
850
|
-
// P1(AND): {A:'y', B:'y'}
|
|
851
|
-
// P2(AND): {A:'y', B:'n'}
|
|
852
|
-
// → 群組內 AND = {A:'y', B:'n'}
|
|
853
|
-
//
|
|
854
|
-
// G2:
|
|
855
|
-
// P3(OR): {A:'n', B:'y'}
|
|
856
|
-
// → 群組內 = {A:'n', B:'y'}
|
|
857
|
-
//
|
|
858
|
-
// 群組間 OR: {A:'y', B:'n'} OR {A:'n', B:'y'} = {A:'y', B:'y'}
|
|
859
|
-
let targets = [t('A'), t('B')]
|
|
860
|
-
let pemis = [
|
|
861
|
-
p('P1', { A: 'y', B: 'y' }),
|
|
862
|
-
p('P2', { A: 'y', B: 'n' }),
|
|
863
|
-
p('P3', { A: 'n', B: 'y' }),
|
|
864
|
-
]
|
|
865
|
-
let grups = [
|
|
866
|
-
g('G1', { P1: AND, P2: AND }),
|
|
867
|
-
g('G2', { P3: OR }),
|
|
868
|
-
]
|
|
869
|
-
let user = u({ G1: OR, G2: OR })
|
|
870
|
-
|
|
871
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
872
|
-
let m = rulesToMap(rules)
|
|
873
|
-
assert.strictEqual(m.A, 'y')
|
|
874
|
-
assert.strictEqual(m.B, 'y')
|
|
875
|
-
})
|
|
876
|
-
|
|
877
|
-
})
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
// ===========================================================
|
|
881
|
-
// JSON5 格式容錯
|
|
882
|
-
// ===========================================================
|
|
883
|
-
describe('JSON5 格式', function() {
|
|
884
|
-
|
|
885
|
-
it('cgrups 使用 JSON5 格式(單引號)— 正常解析', function() {
|
|
886
|
-
let targets = [t('A')]
|
|
887
|
-
let pemis = [p('P1', { A: 'y' })]
|
|
888
|
-
let grups = [g('G1', { P1: OR })]
|
|
889
|
-
let user = {
|
|
890
|
-
cgrups: `{ 'G1': { 'mode': 'OR', 'isActive': 'y' } }`,
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
let { rules } = getUserRules(user, grups, pemis, targets)
|
|
894
|
-
assert.strictEqual(ruleOf(rules, 'A'), 'y')
|
|
895
|
-
})
|
|
896
|
-
|
|
897
|
-
})
|
|
898
|
-
|
|
899
|
-
})
|