|
42 | 42 | RemoveUsersFromRoleWithScopeSerializer, |
43 | 43 | TeamMemberSerializer, |
44 | 44 | UserRoleAssignmentSerializer, |
| 45 | + UserValidationAPIViewResponseSerializer, |
| 46 | + UserValidationAPIViewSerializer, |
45 | 47 | ) |
46 | 48 | from openedx_authz.utils import get_user_by_username_or_email |
47 | 49 |
|
@@ -586,3 +588,88 @@ def get(self, request: HttpRequest) -> Response: |
586 | 588 | paginator = self.pagination_class() |
587 | 589 | paginated_response_data = paginator.paginate_queryset(team_members, request) |
588 | 590 | return paginator.get_paginated_response(paginated_response_data) |
| 591 | + |
| 592 | +@view_auth_classes() |
| 593 | +class UserValidationAPIView(APIView): |
| 594 | + """API view for validating that provided user identifiers correspond to existing users. |
| 595 | +
|
| 596 | + This view allows clients to verify that a list of user identifiers (usernames or emails) |
| 597 | + correspond to valid users in the system. It is designed to support bulk validation of multiple |
| 598 | + user identifiers in a single request, providing a convenient way to check the validity of users before |
| 599 | + performing operations such as role assignments. |
| 600 | +
|
| 601 | + **Endpoints** |
| 602 | + - POST: Validate that the provided list of usernames or emails correspond to existing users |
| 603 | +
|
| 604 | + **Request Format (POST)** |
| 605 | + - users: List of user identifiers (username or email) |
| 606 | +
|
| 607 | + **Response Format (POST)** |
| 608 | +
|
| 609 | + Returns HTTP 200 OK with:: |
| 610 | +
|
| 611 | + { |
| 612 | + "valid_users": ["john_doe", "[email protected]"], |
| 613 | + "invalid_users": ["nonexistent_user"], |
| 614 | + "summary": { |
| 615 | + "total": 3, |
| 616 | + "valid_count": 2, |
| 617 | + "invalid_count": 1 |
| 618 | + } |
| 619 | + } |
| 620 | +
|
| 621 | + **Authentication and Permissions** |
| 622 | +
|
| 623 | + - Requires authenticated user. |
| 624 | + - Requires ``manage_library_team`` or ``manage_course_team`` permission in any scope. |
| 625 | +
|
| 626 | + **Example Request** |
| 627 | +
|
| 628 | + POST /api/authz/v1/users/validate/ :: |
| 629 | +
|
| 630 | + { |
| 631 | + "users": ["john_doe", "[email protected]", "nonexistent_user"] |
| 632 | + } |
| 633 | + """ |
| 634 | + |
| 635 | + permission_classes = [AnyScopePermission] |
| 636 | + |
| 637 | + @apidocs.schema( |
| 638 | + body=UserValidationAPIViewSerializer, |
| 639 | + responses={ |
| 640 | + status.HTTP_200_OK: UserValidationAPIViewResponseSerializer, |
| 641 | + status.HTTP_400_BAD_REQUEST: "The request data is invalid", |
| 642 | + status.HTTP_401_UNAUTHORIZED: "The user is not authenticated", |
| 643 | + status.HTTP_403_FORBIDDEN: "The user does not have the required permissions", |
| 644 | + }, |
| 645 | + ) |
| 646 | + @authz_permissions([permissions.MANAGE_LIBRARY_TEAM.identifier, permissions.COURSES_MANAGE_COURSE_TEAM.identifier]) |
| 647 | + def post(self, request: HttpRequest) -> Response: |
| 648 | + """Validates the provided usernames or emails correspond to existing users.""" |
| 649 | + |
| 650 | + request_serializer = UserValidationAPIViewSerializer(data=request.data) |
| 651 | + request_serializer.is_valid(raise_exception=True) |
| 652 | + serialized_request_data = request_serializer.validated_data |
| 653 | + valid_users = [] |
| 654 | + invalid_users = [] |
| 655 | + for user_identifier in serialized_request_data["users"]: |
| 656 | + try: |
| 657 | + user = get_user_by_username_or_email(user_identifier) |
| 658 | + if user.is_active: |
| 659 | + valid_users.append(user_identifier) |
| 660 | + else: |
| 661 | + invalid_users.append(user_identifier) |
| 662 | + except User.DoesNotExist: |
| 663 | + invalid_users.append(user_identifier) |
| 664 | + |
| 665 | + response_data = { |
| 666 | + "valid_users": valid_users, |
| 667 | + "invalid_users": invalid_users, |
| 668 | + "summary": { |
| 669 | + "total": len(serialized_request_data["users"]), |
| 670 | + "valid_count": len(valid_users), |
| 671 | + "invalid_count": len(invalid_users), |
| 672 | + }, |
| 673 | + } |
| 674 | + response_serializer = UserValidationAPIViewResponseSerializer(response_data) |
| 675 | + return Response(response_serializer.data, status=status.HTTP_200_OK) |
0 commit comments