Skip to content

Commit 9160772

Browse files
authored
feat: add policy APIs in nodejs SDK (#67)
1 parent cf224e6 commit 9160772

File tree

3 files changed

+237
-0
lines changed

3 files changed

+237
-0
lines changed

src/policy.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright 2024 The Casdoor Authors. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import { AxiosResponse } from 'axios'
16+
import { Config } from './config'
17+
import Request from './request'
18+
import { Enforcer } from './enforcer'
19+
20+
export interface Policy {
21+
Id: number
22+
Ptype: string
23+
V0: string
24+
V1: string
25+
V2: string
26+
V3?: string
27+
V4?: string
28+
V5?: string
29+
tableName?: string
30+
}
31+
32+
export class PolicySDK {
33+
private config: Config
34+
private readonly request: Request
35+
36+
constructor(config: Config, request: Request) {
37+
this.config = config
38+
this.request = request
39+
}
40+
41+
public async getPolicies(enforcerName: string, adapterId?: string) {
42+
if (!this.request) {
43+
throw new Error('request init failed')
44+
}
45+
46+
return (await this.request.get('/get-policies', {
47+
params: {
48+
id: `${this.config.orgName}/${enforcerName}`,
49+
adapterId: adapterId,
50+
},
51+
})) as unknown as Promise<AxiosResponse<{ data: Policy[] }>>
52+
}
53+
54+
public async modifyPolicy(
55+
method: string,
56+
enforcer: Enforcer,
57+
policies: Policy[],
58+
) {
59+
if (!this.request) {
60+
throw new Error('request init failed')
61+
}
62+
63+
let data
64+
if (method === 'update-policy') {
65+
data = JSON.stringify(policies)
66+
} else {
67+
data = JSON.stringify(policies[0])
68+
}
69+
70+
const url = `/${method}`
71+
return (await this.request.post(url, data, {
72+
params: {
73+
id: `${enforcer.owner}/${enforcer.name}`,
74+
},
75+
})) as unknown as Promise<AxiosResponse<Record<string, unknown>>>
76+
}
77+
78+
public async addPolicy(enforcer: Enforcer, policy: Policy) {
79+
return this.modifyPolicy('add-policy', enforcer, [policy])
80+
}
81+
82+
public async updatePolicy(
83+
enforcer: Enforcer,
84+
oldPolicy: Policy,
85+
newPolicy: Policy,
86+
) {
87+
return this.modifyPolicy('update-policy', enforcer, [oldPolicy, newPolicy])
88+
}
89+
90+
public async deletePolicy(enforcer: Enforcer, policy: Policy) {
91+
return this.modifyPolicy('remove-policy', enforcer, [policy])
92+
}
93+
}

src/sdk.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { Session, SessionSDK } from './session'
2727
import { Syncer, SyncerSDK } from './syncer'
2828
import { Permission, PermissionSDK } from './permission'
2929
import { Plan, PlanSDK } from './plan'
30+
import { Policy, PolicySDK } from './policy'
3031
import { Pricing, PricingSDK } from './pricing'
3132
import { Provider, ProviderSDK } from './provider'
3233
import { Resource, ResourceSDK } from './resource'
@@ -58,6 +59,7 @@ export class SDK {
5859
private syncerSDK: SyncerSDK
5960
private permissionSDK: PermissionSDK
6061
private planSDK: PlanSDK
62+
private policySDK: PolicySDK
6163
private pricingSDK: PricingSDK
6264
private providerSDK: ProviderSDK
6365
private resourceSDK: ResourceSDK
@@ -99,6 +101,7 @@ export class SDK {
99101
this.syncerSDK = new SyncerSDK(this.config, this.request)
100102
this.permissionSDK = new PermissionSDK(this.config, this.request)
101103
this.planSDK = new PlanSDK(this.config, this.request)
104+
this.policySDK = new PolicySDK(this.config, this.request)
102105
this.pricingSDK = new PricingSDK(this.config, this.request)
103106
this.providerSDK = new ProviderSDK(this.config, this.request)
104107
this.resourceSDK = new ResourceSDK(this.config, this.request)
@@ -390,6 +393,26 @@ export class SDK {
390393
return await this.planSDK.deletePlan(plan)
391394
}
392395

396+
public async getPolicies(enforcerName: string, adapterId?: string) {
397+
return await this.policySDK.getPolicies(enforcerName, adapterId)
398+
}
399+
400+
public async addPolicy(enforcer: Enforcer, policy: Policy) {
401+
return await this.policySDK.addPolicy(enforcer, policy)
402+
}
403+
404+
public async updatePolicy(
405+
enforcer: Enforcer,
406+
oldPolicy: Policy,
407+
newPolicy: Policy,
408+
) {
409+
return await this.policySDK.updatePolicy(enforcer, oldPolicy, newPolicy)
410+
}
411+
412+
public async deletePolicy(enforcer: Enforcer, policy: Policy) {
413+
return await this.policySDK.deletePolicy(enforcer, policy)
414+
}
415+
393416
public async getPricings() {
394417
return await this.pricingSDK.getPricings()
395418
}

test/policy.test.ts

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// Copyright 2024 The Casdoor Authors. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import { SDK } from '../src'
16+
import * as util from './util'
17+
import { Config } from '../src/config'
18+
import { Policy } from '../src/policy'
19+
import { Enforcer } from '../src/enforcer'
20+
21+
test('TestPolicy', async () => {
22+
const testConfig: Config = {
23+
endpoint: util.TestCasdoorEndpoint,
24+
clientId: util.TestClientId,
25+
clientSecret: util.TestClientSecret,
26+
certificate: util.TestJwtPublicKey,
27+
orgName: util.TestCasdoorOrganization,
28+
appName: util.TestCasdoorApplication,
29+
}
30+
const sdk = new SDK(testConfig)
31+
32+
const name = util.getRandomName('policy')
33+
34+
const enforcer: Enforcer = {
35+
owner: 'admin',
36+
name: name,
37+
createdTime: new Date().toISOString(),
38+
displayName: name,
39+
model: 'built-in/user-model-built-in',
40+
adapter: 'built-in/user-adapter-built-in',
41+
description: 'Casdoor Website',
42+
}
43+
44+
// Add a new object
45+
const policy: Policy = {
46+
Id: 0,
47+
Ptype: 'p',
48+
V0: '1',
49+
V1: '2',
50+
V2: '4',
51+
}
52+
53+
const newPolicy: Policy = {
54+
Id: 0,
55+
Ptype: 'p',
56+
V0: '1',
57+
V1: '2',
58+
V2: '5',
59+
}
60+
61+
const { data: enforcerAddResponse } = await sdk.addEnforcer(enforcer)
62+
if (enforcerAddResponse.data !== 'Affected') {
63+
throw new Error('Failed to add enforcer')
64+
}
65+
66+
const { data: addResponse } = await sdk.addPolicy(enforcer, policy)
67+
if (addResponse.data !== 'Affected') {
68+
throw new Error('Failed to add object')
69+
}
70+
71+
// Get all objects and check if our added object is in the list
72+
const {
73+
data: { data: policies },
74+
} = await sdk.getPolicies(enforcer.name)
75+
const found = policies.some((item) => item.Id === 0 && item.V2 === '4')
76+
if (!found) {
77+
throw new Error('Added object not found in list')
78+
}
79+
80+
// Update the object
81+
const { data: updateResponse } = await sdk.updatePolicy(
82+
enforcer,
83+
policy,
84+
newPolicy,
85+
)
86+
if (updateResponse.data !== 'Affected') {
87+
throw new Error('Failed to update object')
88+
}
89+
90+
// ValIdate the update
91+
const {
92+
data: { data: updatedPolicies },
93+
} = await sdk.getPolicies(name)
94+
const updatedfound = updatedPolicies.some(
95+
(item) => item.Id === 0 && item.V2 === '5',
96+
)
97+
if (!updatedfound) {
98+
throw new Error(
99+
`Failed to update object, description mismatch: ${policy.V2} != ${newPolicy.V2}`,
100+
)
101+
}
102+
103+
// Delete the object
104+
const { data: deleteResponse } = await sdk.deletePolicy(enforcer, newPolicy)
105+
if (deleteResponse.data !== 'Affected') {
106+
throw new Error('Failed to delete object')
107+
}
108+
109+
// ValIdate the deletion
110+
const {
111+
data: { data: deletedPolicies },
112+
} = await sdk.getPolicies(name)
113+
const deletedfound = deletedPolicies.some((item) => item === newPolicy)
114+
if (deletedfound) {
115+
throw new Error(
116+
`Failed to delete object, it's still retrievable ${JSON.stringify(
117+
deletedPolicies,
118+
)}`,
119+
)
120+
}
121+
})

0 commit comments

Comments
 (0)