Skip to content

Commit c5b97a0

Browse files
committed
feat: add UserPermissionViewSet for managing user-specific permissions
1 parent 851a940 commit c5b97a0

2 files changed

Lines changed: 89 additions & 1 deletion

File tree

openedx_authz/urls.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44

55
from django.urls import re_path, include
66
from rest_framework.routers import DefaultRouter
7-
from .views import LibraryViewSet, AdminRoleAssignmentViewSet
7+
from .views import LibraryViewSet, AdminRoleAssignmentViewSet, UserPermissionViewSet
88

99
router = DefaultRouter()
1010
router.register(r"libraries", LibraryViewSet, basename="library")
1111
router.register(r"admin-roles", AdminRoleAssignmentViewSet, basename="admin-roles")
12+
router.register(r"user-permissions", UserPermissionViewSet, basename="user-permissions")
1213

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

openedx_authz/views.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,90 @@ def destroy(self, request, pk=None):
137137
enforcer.delete_role_for_user(username, "admin")
138138
enforcer.save_policy()
139139
return Response(f"Admin role removed from user {username}", status=status.HTTP_204_NO_CONTENT)
140+
141+
142+
class UserPermissionViewSet(viewsets.ViewSet):
143+
"""
144+
ViewSet for managing specific user permissions using Casbin.
145+
Allows adding or removing specific permissions for users on resources.
146+
147+
Example:
148+
```json
149+
{
150+
"username": "john_doe",
151+
"obj": "/api/libraries/",
152+
"act": "GET"
153+
}
154+
```
155+
"""
156+
157+
def create(self, request):
158+
"""
159+
POST /user-permissions/
160+
Add a specific permission to a user.
161+
162+
Example request body:
163+
```json
164+
{
165+
"username": "john_doe",
166+
"obj": "/api/libraries/123/",
167+
"act": "GET"
168+
}
169+
```
170+
"""
171+
username = request.data.get("username")
172+
obj = request.data.get("obj")
173+
act = request.data.get("act")
174+
175+
if not all([username, obj, act]):
176+
return Response({"error": "username, obj, and act are required fields"}, status=status.HTTP_400_BAD_REQUEST)
177+
178+
enforcer.add_policy(username, obj, act)
179+
enforcer.save_policy()
180+
181+
return Response(
182+
{
183+
"message": f"Permission '{act}' on '{obj}' granted to user '{username}'",
184+
"username": username,
185+
"obj": obj,
186+
"act": act,
187+
},
188+
status=status.HTTP_201_CREATED,
189+
)
190+
191+
def destroy(self, request, pk=None):
192+
"""
193+
DELETE /user-permissions/{username}/
194+
Remove a specific permission from a user.
195+
196+
Query parameters:
197+
- obj: The resource path (required)
198+
- act: The action/method (required)
199+
200+
Example: DELETE /user-permissions/john_doe/?obj=/api/libraries/123/&act=GET
201+
"""
202+
username = pk
203+
obj = request.query_params.get("obj")
204+
act = request.query_params.get("act")
205+
206+
if not all([obj, act]):
207+
return Response({"error": "obj and act query parameters are required"}, status=status.HTTP_400_BAD_REQUEST)
208+
209+
result = enforcer.remove_policy(username, obj, act)
210+
enforcer.save_policy()
211+
212+
if result:
213+
return Response(
214+
{
215+
"message": f"Permission '{act}' on '{obj}' removed from user '{username}'",
216+
"username": username,
217+
"obj": obj,
218+
"act": act,
219+
},
220+
status=status.HTTP_204_NO_CONTENT,
221+
)
222+
else:
223+
return Response(
224+
{"error": f"Permission not found for user '{username}' on '{obj}' with action '{act}'"},
225+
status=status.HTTP_404_NOT_FOUND,
226+
)

0 commit comments

Comments
 (0)