|
26 | 26 | sort_users, |
27 | 27 | ) |
28 | 28 | from openedx_authz.rest_api.v1.paginators import AuthZAPIViewPagination |
29 | | -from openedx_authz.rest_api.v1.permissions import DynamicScopePermission |
| 29 | +from openedx_authz.rest_api.v1.permissions import DynamicScopePermission, GlobalPermission |
30 | 30 | from openedx_authz.rest_api.v1.serializers import ( |
31 | 31 | AddUsersToRoleWithScopeSerializer, |
32 | 32 | ListRolesWithScopeResponseSerializer, |
|
36 | 36 | PermissionValidationSerializer, |
37 | 37 | RemoveUsersFromRoleWithScopeSerializer, |
38 | 38 | UserRoleAssignmentSerializer, |
| 39 | + UserValidationAPIViewResponseSerializer, |
| 40 | + UserValidationAPIViewSerializer, |
39 | 41 | ) |
40 | 42 |
|
41 | 43 | logger = logging.getLogger(__name__) |
@@ -449,3 +451,86 @@ def get(self, request: HttpRequest) -> Response: |
449 | 451 | paginated_response_data = paginator.paginate_queryset(response_data, request) |
450 | 452 | serialized_data = ListRolesWithScopeResponseSerializer(paginated_response_data, many=True) |
451 | 453 | return paginator.get_paginated_response(serialized_data.data) |
| 454 | + |
| 455 | + |
| 456 | +@view_auth_classes() |
| 457 | +class UserValidationAPIView(APIView): |
| 458 | + """API view for validating that provided user identifiers correspond to existing users. |
| 459 | +
|
| 460 | + This view allows clients to verify that a list of user identifiers (usernames or emails) |
| 461 | + correspond to valid users in the system. It is designed to support bulk validation of multiple |
| 462 | + user identifiers in a single request, providing a convenient way to check the validity of users before |
| 463 | + performing operations such as role assignments. |
| 464 | +
|
| 465 | + **Endpoints** |
| 466 | + - POST: Validate that the provided list of usernames or emails correspond to existing users |
| 467 | +
|
| 468 | + **Request Format (POST)** |
| 469 | + - users: List of user identifiers (username or email) |
| 470 | +
|
| 471 | + **Response Format (POST)** |
| 472 | +
|
| 473 | + Returns HTTP 200 OK with:: |
| 474 | +
|
| 475 | + { |
| 476 | + "valid_users": ["john_doe", "[email protected]"], |
| 477 | + "invalid_users": ["nonexistent_user"], |
| 478 | + "summary": { |
| 479 | + "total": 3, |
| 480 | + "valid_count": 2, |
| 481 | + "invalid_count": 1 |
| 482 | + } |
| 483 | + } |
| 484 | +
|
| 485 | + **Authentication and Permissions** |
| 486 | +
|
| 487 | + - Requires authenticated user. |
| 488 | + - Requires ``manage_library_team`` or ``manage_course_team`` permission in any scope. |
| 489 | +
|
| 490 | + **Example Request** |
| 491 | +
|
| 492 | + POST /api/authz/v1/users/validate/ :: |
| 493 | +
|
| 494 | + { |
| 495 | + "users": ["john_doe", "[email protected]", "nonexistent_user"] |
| 496 | + } |
| 497 | + """ |
| 498 | + |
| 499 | + permission_classes = [GlobalPermission] |
| 500 | + |
| 501 | + @apidocs.schema( |
| 502 | + body=UserValidationAPIViewSerializer, |
| 503 | + responses={ |
| 504 | + status.HTTP_200_OK: UserValidationAPIViewResponseSerializer, |
| 505 | + status.HTTP_400_BAD_REQUEST: "The request data is invalid", |
| 506 | + status.HTTP_401_UNAUTHORIZED: "The user is not authenticated", |
| 507 | + status.HTTP_403_FORBIDDEN: "The user does not have the required permissions", |
| 508 | + }, |
| 509 | + ) |
| 510 | + @authz_permissions([permissions.MANAGE_LIBRARY_TEAM.identifier, permissions.COURSES_MANAGE_COURSE_TEAM.identifier]) |
| 511 | + def post(self, request: HttpRequest) -> Response: |
| 512 | + """Validates the provided usernames or emails correspond to existing users.""" |
| 513 | + |
| 514 | + request_serializer = UserValidationAPIViewSerializer(data=request.data) |
| 515 | + request_serializer.is_valid(raise_exception=True) |
| 516 | + serialized_request_data = request_serializer.validated_data |
| 517 | + valid_users = [] |
| 518 | + invalid_users = [] |
| 519 | + for user_identifier in serialized_request_data["users"]: |
| 520 | + try: |
| 521 | + user = get_user_by_username_or_email(user_identifier) |
| 522 | + valid_users.append(user_identifier) |
| 523 | + except User.DoesNotExist: |
| 524 | + invalid_users.append(user_identifier) |
| 525 | + |
| 526 | + response_data = { |
| 527 | + "valid_users": valid_users, |
| 528 | + "invalid_users": invalid_users, |
| 529 | + "summary": { |
| 530 | + "total": len(serialized_request_data["users"]), |
| 531 | + "valid_count": len(valid_users), |
| 532 | + "invalid_count": len(invalid_users), |
| 533 | + }, |
| 534 | + } |
| 535 | + response_serializer = UserValidationAPIViewResponseSerializer(response_data) |
| 536 | + return Response(response_serializer.data, status=status.HTTP_200_OK) |
0 commit comments