Skip to content

Commit 0c2fbf3

Browse files
committed
feat: add PolicyBulkViewSet and PolicySingleViewSet for managing bulk and single policy operations
1 parent 0dce5ad commit 0c2fbf3

2 files changed

Lines changed: 104 additions & 64 deletions

File tree

openedx_authz/urls.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22
URLs for openedx_authz.
33
"""
44

5-
from django.urls import re_path, include
5+
from django.urls import include, re_path
66
from rest_framework.routers import DefaultRouter
7-
from .views import LibraryViewSet, AdminRoleAssignmentViewSet, UserPermissionViewSet
7+
8+
from .views import AdminRoleAssignmentViewSet, LibraryViewSet, PolicyBulkViewSet, PolicySingleViewSet
89

910
router = DefaultRouter()
1011
router.register(r"libraries", LibraryViewSet, basename="library")
1112
router.register(r"admin-roles", AdminRoleAssignmentViewSet, basename="admin-roles")
12-
router.register(r"user-permissions", UserPermissionViewSet, basename="user-permissions")
13+
router.register(r"policy-bulk", PolicyBulkViewSet, basename="policy-bulk")
14+
router.register(r"policy-single", PolicySingleViewSet, basename="policy-single")
1315

1416
urlpatterns = [
1517
re_path(r"^api/", include(router.urls)),

openedx_authz/views.py

Lines changed: 99 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,6 @@ def create(self, request):
123123
}
124124
```
125125
"""
126-
enforcer.enable_auto_save(True)
127126
username = request.data["username"]
128127
enforcer.add_role_for_user(username, "admin")
129128
return Response(f"Admin role assigned to user {username}", status=status.HTTP_201_CREATED)
@@ -138,86 +137,125 @@ def destroy(self, request, pk=None):
138137
return Response(f"Admin role removed from user {username}", status=status.HTTP_204_NO_CONTENT)
139138

140139

141-
class UserPermissionViewSet(viewsets.ViewSet):
140+
class PolicyBulkViewSet(viewsets.ViewSet):
142141
"""
143-
ViewSet for managing specific user permissions using Casbin.
144-
Allows adding or removing specific permissions for users on resources.
145-
146-
Example:
147-
```json
148-
{
149-
"username": "john_doe",
150-
"obj": "/api/libraries/",
151-
"act": "GET"
152-
}
153-
```
142+
ViewSet for bulk policy operations using Casbin's add_policies and remove_policies.
143+
This is a simple testing interface for bulk policy management.
154144
"""
155145

156146
def create(self, request):
157147
"""
158-
POST /user-permissions/
159-
Add a specific permission to a user.
148+
POST /policy-bulk/
149+
Add multiple policies at once using add_policies.
160150
161151
Example request body:
162152
```json
163153
{
164-
"username": "john_doe",
165-
"obj": "/api/libraries/123/",
166-
"act": "GET"
154+
"policies": [
155+
["user1", "/api/resource1/", "GET"],
156+
["user2", "/api/resource2/", "POST"],
157+
["user3", "/api/resource3/", "DELETE"]
158+
]
167159
}
168160
```
169161
"""
170-
username = request.data.get("username")
171-
obj = request.data.get("obj")
172-
act = request.data.get("act")
173-
174-
if not all([username, obj, act]):
175-
return Response({"error": "username, obj, and act are required fields"}, status=status.HTTP_400_BAD_REQUEST)
162+
policies = request.data.get("policies", [])
163+
result = enforcer.add_policies(policies)
164+
return Response(
165+
{
166+
"message": "Bulk policy addition completed",
167+
"success": result,
168+
"policies_added": len(policies),
169+
"policies": policies,
170+
},
171+
status=status.HTTP_201_CREATED if result else status.HTTP_200_OK,
172+
)
176173

177-
enforcer.add_policy(username, obj, act)
174+
def destroy(self, request, pk=None): # pylint: disable=unused-argument
175+
"""
176+
DELETE /policy-bulk/remove/
177+
Remove multiple policies at once using remove_policies.
178+
Uses request body instead of pk since we need to pass multiple policies.
178179
180+
Example request body:
181+
```json
182+
{
183+
"policies": [
184+
["user1", "/api/resource1/", "GET"],
185+
["user2", "/api/resource2/", "POST"]
186+
]
187+
}
188+
```
189+
"""
190+
policies = request.data.get("policies", [])
191+
result = enforcer.remove_policies(policies)
179192
return Response(
180193
{
181-
"message": f"Permission '{act}' on '{obj}' granted to user '{username}'",
182-
"username": username,
183-
"obj": obj,
184-
"act": act,
194+
"message": "Bulk policy removal completed",
195+
"success": result,
196+
"policies_removed": len(policies),
197+
"policies": policies,
185198
},
186-
status=status.HTTP_201_CREATED,
199+
status=status.HTTP_204_NO_CONTENT if result else status.HTTP_200_OK,
187200
)
188201

189-
def destroy(self, request, pk=None):
202+
203+
class PolicySingleViewSet(viewsets.ViewSet):
204+
"""
205+
ViewSet for single policy operations using Casbin's add_policy and remove_policy.
206+
Simple testing interface for individual policy management.
207+
"""
208+
209+
def create(self, request):
210+
"""
211+
POST /policy-single/
212+
Add a single policy using add_policy.
213+
214+
Example request body:
215+
```json
216+
{
217+
"subject": "user1",
218+
"object": "/api/resource1/",
219+
"action": "GET"
220+
}
221+
```
190222
"""
191-
DELETE /user-permissions/{username}/
192-
Remove a specific permission from a user.
223+
subject = request.data.get("subject")
224+
obj = request.data.get("object")
225+
action = request.data.get("action")
226+
result = enforcer.add_policy(subject, obj, action)
227+
return Response(
228+
{
229+
"message": "Policy added successfully" if result else "Policy already exists",
230+
"success": result,
231+
"policy": [subject, obj, action],
232+
},
233+
status=status.HTTP_201_CREATED if result else status.HTTP_200_OK,
234+
)
193235

194-
Query parameters:
195-
- obj: The resource path (required)
196-
- act: The action/method (required)
236+
def destroy(self, request, pk=None): # pylint: disable=unused-argument
237+
"""
238+
DELETE /policy-single/remove/
239+
Remove a single policy using remove_policy.
197240
198-
Example: DELETE /user-permissions/john_doe/?obj=/api/libraries/123/&act=GET
241+
Example request body:
242+
```json
243+
{
244+
"subject": "user1",
245+
"object": "/api/resource1/",
246+
"action": "GET"
247+
}
248+
```
199249
"""
200-
username = pk
201-
obj = request.query_params.get("obj")
202-
act = request.query_params.get("act")
203-
204-
if not all([obj, act]):
205-
return Response({"error": "obj and act query parameters are required"}, status=status.HTTP_400_BAD_REQUEST)
206-
207-
result = enforcer.remove_policy(username, obj, act)
208-
209-
if result:
210-
return Response(
211-
{
212-
"message": f"Permission '{act}' on '{obj}' removed from user '{username}'",
213-
"username": username,
214-
"obj": obj,
215-
"act": act,
216-
},
217-
status=status.HTTP_204_NO_CONTENT,
218-
)
219-
else:
220-
return Response(
221-
{"error": f"Permission not found for user '{username}' on '{obj}' with action '{act}'"},
222-
status=status.HTTP_404_NOT_FOUND,
223-
)
250+
subject = request.data.get("subject")
251+
obj = request.data.get("object")
252+
action = request.data.get("action")
253+
result = enforcer.remove_policy(subject, obj, action)
254+
return Response(
255+
{
256+
"message": "Policy removed successfully" if result else "Policy not found",
257+
"success": result,
258+
"policy": [subject, obj, action],
259+
},
260+
status=status.HTTP_204_NO_CONTENT if result else status.HTTP_404_NOT_FOUND,
261+
)

0 commit comments

Comments
 (0)