Skip to content

Commit d086457

Browse files
authored
feat: implement self* methods using WithoutNotify pattern (sync with Go) (#539)
1 parent 4d68d28 commit d086457

File tree

3 files changed

+394
-16
lines changed

3 files changed

+394
-16
lines changed

src/internalEnforcer.ts

Lines changed: 117 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export class InternalEnforcer extends CoreEnforcer {
2929
return false;
3030
}
3131

32+
// Persist when an adapter is configured and autoSave is enabled.
3233
if (this.adapter && this.autoSave) {
3334
try {
3435
await this.adapter.addPolicy(sec, ptype, rule);
@@ -67,7 +68,8 @@ export class InternalEnforcer extends CoreEnforcer {
6768
}
6869
}
6970

70-
if (this.autoSave) {
71+
// Persist when an adapter is configured and autoSave is enabled.
72+
if (this.adapter && this.autoSave) {
7173
if ('addPolicies' in this.adapter) {
7274
try {
7375
await this.adapter.addPolicies(sec, ptype, rules);
@@ -113,7 +115,8 @@ export class InternalEnforcer extends CoreEnforcer {
113115
return false;
114116
}
115117

116-
if (this.autoSave) {
118+
// Persist when an adapter is configured and autoSave is enabled.
119+
if (this.adapter && this.autoSave) {
117120
if ('addPolicies' in this.adapter) {
118121
try {
119122
await this.adapter.addPolicies(sec, ptype, newRules);
@@ -158,8 +161,8 @@ export class InternalEnforcer extends CoreEnforcer {
158161
if (!this.model.hasPolicy(sec, ptype, oldRule)) {
159162
return false;
160163
}
161-
162-
if (this.autoSave) {
164+
// Persist when an adapter is configured and autoSave is enabled.
165+
if (this.adapter && this.autoSave) {
163166
if ('updatePolicy' in this.adapter) {
164167
try {
165168
await this.adapter.updatePolicy(sec, ptype, oldRule, newRule);
@@ -200,6 +203,7 @@ export class InternalEnforcer extends CoreEnforcer {
200203
return false;
201204
}
202205

206+
// Persist when an adapter is configured and autoSave is enabled.
203207
if (this.adapter && this.autoSave) {
204208
try {
205209
await this.adapter.removePolicy(sec, ptype, rule);
@@ -236,7 +240,8 @@ export class InternalEnforcer extends CoreEnforcer {
236240
}
237241
}
238242

239-
if (this.autoSave) {
243+
// Persist when an adapter is configured and autoSave is enabled.
244+
if (this.adapter && this.autoSave) {
240245
if ('removePolicies' in this.adapter) {
241246
try {
242247
await this.adapter.removePolicies(sec, ptype, rules);
@@ -278,6 +283,7 @@ export class InternalEnforcer extends CoreEnforcer {
278283
fieldValues: string[],
279284
useWatcher: boolean
280285
): Promise<boolean> {
286+
// Persist when an adapter is configured and autoSave is enabled.
281287
if (this.adapter && this.autoSave) {
282288
try {
283289
await this.adapter.removeFilteredPolicy(sec, ptype, fieldIndex, ...fieldValues);
@@ -320,4 +326,110 @@ export class InternalEnforcer extends CoreEnforcer {
320326
const assertion = this.model.model.get('p')?.get(ptype);
321327
assertion?.fieldIndexMap.set(field, index);
322328
}
329+
330+
protected async addPolicyWithoutNotify(sec: string, ptype: string, rule: string[]): Promise<boolean> {
331+
if (this.model.hasPolicy(sec, ptype, rule)) {
332+
return false;
333+
}
334+
335+
const ok = this.model.addPolicy(sec, ptype, rule);
336+
if (sec === 'g' && ok) {
337+
await this.buildIncrementalRoleLinks(PolicyOp.PolicyAdd, ptype, [rule]);
338+
}
339+
return ok;
340+
}
341+
342+
protected async addPoliciesWithoutNotify(sec: string, ptype: string, rules: string[][]): Promise<boolean> {
343+
for (const rule of rules) {
344+
if (this.model.hasPolicy(sec, ptype, rule)) {
345+
return false;
346+
}
347+
}
348+
349+
const [ok, effects] = await this.model.addPolicies(sec, ptype, rules);
350+
if (sec === 'g' && ok && effects?.length) {
351+
await this.buildIncrementalRoleLinks(PolicyOp.PolicyAdd, ptype, effects);
352+
}
353+
return ok;
354+
}
355+
356+
protected async addPoliciesWithoutNotifyEx(sec: string, ptype: string, rules: string[][]): Promise<boolean> {
357+
const newRules = rules.filter((rule) => !this.model.hasPolicy(sec, ptype, rule));
358+
if (newRules.length === 0) {
359+
return false;
360+
}
361+
362+
const [ok, effects] = await this.model.addPolicies(sec, ptype, newRules);
363+
if (sec === 'g' && ok && effects?.length) {
364+
await this.buildIncrementalRoleLinks(PolicyOp.PolicyAdd, ptype, effects);
365+
}
366+
return ok;
367+
}
368+
369+
protected async updatePolicyWithoutNotify(sec: string, ptype: string, oldRule: string[], newRule: string[]): Promise<boolean> {
370+
if (!this.model.hasPolicy(sec, ptype, oldRule)) {
371+
return false;
372+
}
373+
374+
const ok = this.model.updatePolicy(sec, ptype, oldRule, newRule);
375+
if (sec === 'g' && ok) {
376+
await this.buildIncrementalRoleLinks(PolicyOp.PolicyRemove, ptype, [oldRule]);
377+
await this.buildIncrementalRoleLinks(PolicyOp.PolicyAdd, ptype, [newRule]);
378+
}
379+
return ok;
380+
}
381+
382+
protected async removePolicyWithoutNotify(sec: string, ptype: string, rule: string[]): Promise<boolean> {
383+
if (!this.model.hasPolicy(sec, ptype, rule)) {
384+
return false;
385+
}
386+
387+
const ok = await this.model.removePolicy(sec, ptype, rule);
388+
if (sec === 'g' && ok) {
389+
await this.buildIncrementalRoleLinks(PolicyOp.PolicyRemove, ptype, [rule]);
390+
}
391+
return ok;
392+
}
393+
394+
protected async removePoliciesWithoutNotify(sec: string, ptype: string, rules: string[][]): Promise<boolean> {
395+
for (const rule of rules) {
396+
if (!this.model.hasPolicy(sec, ptype, rule)) {
397+
return false;
398+
}
399+
}
400+
401+
const [ok, effects] = this.model.removePolicies(sec, ptype, rules);
402+
if (sec === 'g' && ok && effects?.length) {
403+
await this.buildIncrementalRoleLinks(PolicyOp.PolicyRemove, ptype, effects);
404+
}
405+
return ok;
406+
}
407+
408+
protected async removeFilteredPolicyWithoutNotify(
409+
sec: string,
410+
ptype: string,
411+
fieldIndex: number,
412+
fieldValues: string[]
413+
): Promise<boolean> {
414+
const [ok, effects] = this.model.removeFilteredPolicy(sec, ptype, fieldIndex, ...fieldValues);
415+
if (sec === 'g' && ok && effects?.length) {
416+
await this.buildIncrementalRoleLinks(PolicyOp.PolicyRemove, ptype, effects);
417+
}
418+
return ok;
419+
}
420+
421+
protected async updatePoliciesWithoutNotify(sec: string, ptype: string, oldRules: string[][], newRules: string[][]): Promise<boolean> {
422+
// Mirror the Go updatePoliciesWithoutNotify; reuse the existing internal flow.
423+
// Because updatePoliciesInternal isn't implemented yet, fall back to per-item updates.
424+
if (oldRules.length !== newRules.length) {
425+
throw new Error('the length of oldRules should be equal to the length of newRules');
426+
}
427+
for (let i = 0; i < oldRules.length; i++) {
428+
const ok = await this.updatePolicyWithoutNotify(sec, ptype, oldRules[i], newRules[i]);
429+
if (!ok) {
430+
return false;
431+
}
432+
}
433+
return true;
434+
}
323435
}

src/managementEnforcer.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -589,28 +589,31 @@ export class ManagementEnforcer extends InternalEnforcer {
589589
public async addFunction(name: string, func: MatchingFunction): Promise<void> {
590590
this.fm.addFunction(name, func);
591591
}
592-
593592
public async selfAddPolicy(sec: string, ptype: string, rule: string[]): Promise<boolean> {
594-
return this.addPolicyInternal(sec, ptype, rule, false);
593+
return this.addPolicyWithoutNotify(sec, ptype, rule);
594+
}
595+
596+
public async selfAddPolicies(sec: string, ptype: string, rules: string[][]): Promise<boolean> {
597+
return this.addPoliciesWithoutNotify(sec, ptype, rules);
595598
}
596599

597600
public async selfRemovePolicy(sec: string, ptype: string, rule: string[]): Promise<boolean> {
598-
return this.removePolicyInternal(sec, ptype, rule, false);
601+
return this.removePolicyWithoutNotify(sec, ptype, rule);
599602
}
600603

601-
public async selfRemoveFilteredPolicy(sec: string, ptype: string, fieldIndex: number, fieldValues: string[]): Promise<boolean> {
602-
return this.removeFilteredPolicyInternal(sec, ptype, fieldIndex, fieldValues, false);
604+
public async selfRemovePolicies(sec: string, ptype: string, rules: string[][]): Promise<boolean> {
605+
return this.removePoliciesWithoutNotify(sec, ptype, rules);
603606
}
604607

605-
public async selfUpdatePolicy(sec: string, ptype: string, oldRule: string[], newRule: string[]): Promise<boolean> {
606-
return this.updatePolicyInternal(sec, ptype, oldRule, newRule, false);
608+
public async selfRemoveFilteredPolicy(sec: string, ptype: string, fieldIndex: number, ...fieldValues: string[]): Promise<boolean> {
609+
return this.removeFilteredPolicyWithoutNotify(sec, ptype, fieldIndex, fieldValues);
607610
}
608611

609-
public async selfAddPolicies(sec: string, ptype: string, rule: string[][]): Promise<boolean> {
610-
return this.addPoliciesInternal(sec, ptype, rule, false);
612+
public async selfUpdatePolicy(sec: string, ptype: string, oldRule: string[], newRule: string[]): Promise<boolean> {
613+
return this.updatePolicyWithoutNotify(sec, ptype, oldRule, newRule);
611614
}
612615

613-
public async selfRemovePolicies(sec: string, ptype: string, rule: string[][]): Promise<boolean> {
614-
return this.removePoliciesInternal(sec, ptype, rule, false);
616+
public async selfUpdatePolicies(sec: string, ptype: string, oldRules: string[][], newRules: string[][]): Promise<boolean> {
617+
return this.updatePoliciesWithoutNotify(sec, ptype, oldRules, newRules);
615618
}
616619
}

0 commit comments

Comments
 (0)