1- """Views for the Open edX AuthZ REST API."""
1+ """
2+ REST API views for Open edX Authorization (AuthZ) system.
3+
4+ This module provides Django REST Framework views for managing authorization
5+ permissions, roles, and user assignments within Open edX platform.
6+ """
27
38import logging
49
10+ import edx_api_doc_tools as apidocs
511from common .djangoapps .student .models .user import get_user_by_username_or_email
612from django .contrib .auth import get_user_model
13+ from django .http import HttpRequest
714from rest_framework import status
815from rest_framework .permissions import IsAuthenticated
916from rest_framework .response import Response
1926)
2027from openedx_authz .rest_api .v1 .serializers import (
2128 AddUserToRoleWithScopeSerializer ,
29+ ListRolesWithScopeResponseSerializer ,
2230 ListRolesWithScopeSerializer ,
31+ ListUsersInRoleWithScopeResponseSerializer ,
2332 ListUsersInRoleWithScopeSerializer ,
33+ PermissionValidationResponseSerializer ,
2434 PermissionValidationSerializer ,
2535 RemoveUserFromRoleWithScopeSerializer ,
2636)
3242
3343class PermissionValidationView (APIView ):
3444 """
35- Validate permissions for the authenticated user.
45+ API view for validating user permissions against authorization policies.
46+
47+ This view allows authenticated users to check whether they have
48+ specific permissions for given actions and scopes within the system.
49+ Supports batch permission validation through POST request.
3650 """
3751
3852 permission_classes = [IsAuthenticated ]
3953
40- def post (self , request ):
54+ @apidocs .schema (
55+ body = PermissionValidationSerializer (help_text = "The permissions to validate" , many = True ),
56+ responses = {
57+ status .HTTP_200_OK : PermissionValidationResponseSerializer ,
58+ status .HTTP_400_BAD_REQUEST : "The request data is invalid" ,
59+ status .HTTP_401_UNAUTHORIZED : "The user is not authenticated" ,
60+ },
61+ )
62+ def post (self , request : HttpRequest ) -> Response :
4163 """Validate permissions for the authenticated user."""
4264 serializer = PermissionValidationSerializer (data = request .data , many = True )
4365 serializer .is_valid (raise_exception = True )
4466
4567 username = request .user .username
4668 subject = UserData (username = username )
4769
70+ response_data = []
4871 for perm in serializer .validated_data :
4972 try :
5073 action = ActionData (name = perm ["action" ])
5174 scope = ScopeData (name = perm ["scope" ])
5275 allowed = has_permission (subject , action , scope )
53- perm ["allowed" ] = allowed
76+ response_data .append (
77+ {
78+ "action" : perm ["action" ],
79+ "scope" : perm ["scope" ],
80+ "allowed" : allowed ,
81+ }
82+ )
5483 except Exception as e : # pylint: disable=broad-exception-caught
5584 logger .error (f"Error validating permission for user { username } : { e } " )
5685
57- return Response (serializer .validated_data , status = status .HTTP_200_OK )
86+ serializer = PermissionValidationResponseSerializer (response_data , many = True )
87+ return Response (serializer .data , status = status .HTTP_200_OK )
5888
5989
6090class RoleUserAPIView (APIView ):
6191 """
62- APIView for managing users and their roles.
63- Handles GET (list), PUT (add), and DELETE (remove) operations.
92+ API view for managing user-role assignments within specific scope.
6493 """
6594
6695 permission_classes = [IsAuthenticated ]
6796
68- def get (self , request ):
69- """
70- Get list of users in the role.
71- """
97+ @apidocs .schema (
98+ parameters = [
99+ apidocs .query_parameter ("role" , str , description = "The name of the role to query" ),
100+ apidocs .query_parameter ("scope" , str , description = "The authorization scope for the role" ),
101+ ],
102+ responses = {
103+ status .HTTP_200_OK : ListUsersInRoleWithScopeResponseSerializer (many = True ),
104+ status .HTTP_400_BAD_REQUEST : "The request parameters are invalid" ,
105+ status .HTTP_401_UNAUTHORIZED : "The user is not authenticated" ,
106+ },
107+ )
108+ def get (self , request : HttpRequest ) -> Response :
109+ """Retrieve all users assigned to a specific role within a scope."""
72110 serializer = ListUsersInRoleWithScopeSerializer (data = request .query_params )
73111 serializer .is_valid (raise_exception = True )
74112
@@ -88,12 +126,19 @@ def get(self, request):
88126 }
89127 )
90128
91- return Response (response_data , status = status .HTTP_200_OK )
92-
93- def put (self , request ):
94- """
95- Add users to the role.
96- """
129+ serializer = ListUsersInRoleWithScopeResponseSerializer (response_data , many = True )
130+ return Response (serializer .data , status = status .HTTP_200_OK )
131+
132+ @apidocs .schema (
133+ body = AddUserToRoleWithScopeSerializer ,
134+ responses = {
135+ status .HTTP_207_MULTI_STATUS : "The users were added to the role" ,
136+ status .HTTP_400_BAD_REQUEST : "The request data is invalid" ,
137+ status .HTTP_401_UNAUTHORIZED : "The user is not authenticated" ,
138+ },
139+ )
140+ def put (self , request : HttpRequest ) -> Response :
141+ """Assign multiple users to a specific role within a scope."""
97142 serializer = AddUserToRoleWithScopeSerializer (data = request .data )
98143 serializer .is_valid (raise_exception = True )
99144
@@ -115,10 +160,22 @@ def put(self, request):
115160 response_data = {"completed" : completed , "errors" : errors }
116161 return Response (response_data , status = status .HTTP_207_MULTI_STATUS )
117162
118- def delete (self , request ):
119- """
120- Remove user role from the role.
121- """
163+ @apidocs .schema (
164+ parameters = [
165+ apidocs .query_parameter ("user" , str , description = "The user to remove from the role" ),
166+ apidocs .query_parameter ("role" , str , description = "The role to remove the user from" ),
167+ apidocs .query_parameter ("scope" , str , description = "The scope to remove the user from" ),
168+ ],
169+ responses = {
170+ status .HTTP_200_OK : "The user was removed from the role" ,
171+ status .HTTP_400_BAD_REQUEST : "The request data is invalid" ,
172+ status .HTTP_401_UNAUTHORIZED : "The user is not authenticated" ,
173+ status .HTTP_404_NOT_FOUND : "The user was not found" ,
174+ status .HTTP_500_INTERNAL_SERVER_ERROR : "The user was not removed from the role" ,
175+ },
176+ )
177+ def delete (self , request : HttpRequest ) -> Response :
178+ """Remove a user from a specific role within a scope."""
122179 serializer = RemoveUserFromRoleWithScopeSerializer (data = request .query_params )
123180 serializer .is_valid (raise_exception = True )
124181
@@ -139,13 +196,26 @@ def delete(self, request):
139196
140197class RoleListView (APIView ):
141198 """
142- Get list of roles with their permissions for a scope.
199+ API view for retrieving role definitions and their associated permissions.
200+
201+ Provides read-only access to role information within specific
202+ authorization scopes, including permission mappings and user counts.
143203 """
144204
145205 permission_classes = [IsAuthenticated ]
146206
147- def get (self , request ):
148- """Get list of roles with their permissions for a library."""
207+ @apidocs .schema (
208+ parameters = [
209+ apidocs .query_parameter ("scope" , str , description = "The scope to query roles for" ),
210+ ],
211+ responses = {
212+ status .HTTP_200_OK : ListRolesWithScopeResponseSerializer (many = True ),
213+ status .HTTP_400_BAD_REQUEST : "The request parameters are invalid" ,
214+ status .HTTP_401_UNAUTHORIZED : "The user is not authenticated" ,
215+ },
216+ )
217+ def get (self , request : HttpRequest ) -> Response :
218+ """Retrieve all roles and their permissions for a specific scope."""
149219 serializer = ListRolesWithScopeSerializer (data = request .query_params )
150220 serializer .is_valid (raise_exception = True )
151221
@@ -159,9 +229,10 @@ def get(self, request):
159229 {
160230 "role" : role .name ,
161231 "permissions" : [perm .action .name for perm in role .permissions ] if role .permissions else [],
162- # TODO: Get user count using a api function
232+ # TODO: Get user count using an API function
163233 "user_count" : 0 ,
164234 }
165235 )
166236
167- return Response (response_data , status = status .HTTP_200_OK )
237+ serializer = ListRolesWithScopeResponseSerializer (response_data , many = True )
238+ return Response (serializer .data , status = status .HTTP_200_OK )
0 commit comments