|
48 | 48 | from openwisp_radius.api.serializers import RadiusUserSerializer |
49 | 49 | from openwisp_users.api.authentication import BearerAuthentication, SesameAuthentication |
50 | 50 | from openwisp_users.api.filters import OrganizationManagedFilter |
51 | | -from openwisp_users.api.mixins import FilterByOrganizationManaged, ProtectedAPIMixin |
| 51 | +from openwisp_users.api.mixins import ( |
| 52 | + FilterByOrganizationManaged, |
| 53 | + FilterByParentManaged, |
| 54 | + ProtectedAPIMixin, |
| 55 | +) |
52 | 56 | from openwisp_users.api.permissions import IsOrganizationManager |
53 | 57 | from openwisp_users.api.views import ChangePasswordView as BasePasswordChangeView |
54 | 58 | from openwisp_users.backends import UsersAuthenticationBackend |
|
69 | 73 | RadiusAccountingSerializer, |
70 | 74 | RadiusBatchSerializer, |
71 | 75 | RadiusGroupSerializer, |
| 76 | + RadiusUserGroupSerializer, |
72 | 77 | UserRadiusUsageSerializer, |
73 | 78 | ValidatePhoneTokenSerializer, |
74 | 79 | ) |
@@ -936,3 +941,123 @@ class RadiusGroupDetailView( |
936 | 941 |
|
937 | 942 |
|
938 | 943 | radius_group_detail = RadiusGroupDetailView.as_view() |
| 944 | + |
| 945 | + |
| 946 | +class BaseRadiusUserGroupView(ProtectedAPIMixin, FilterByParentManaged): |
| 947 | + """ |
| 948 | + Base view for RadiusUserGroup management. |
| 949 | + Provides user parent filtering and queryset logic. |
| 950 | + """ |
| 951 | + |
| 952 | + serializer_class = RadiusUserGroupSerializer |
| 953 | + queryset = RadiusUserGroup.objects.select_related("group", "user").order_by( |
| 954 | + "-created" |
| 955 | + ) |
| 956 | + |
| 957 | + def get_queryset(self): |
| 958 | + if getattr(self, "swagger_fake_view", False): |
| 959 | + return self.queryset.none() |
| 960 | + qs = ( |
| 961 | + super() |
| 962 | + .get_queryset() |
| 963 | + .filter( |
| 964 | + user_id=self.kwargs["user_pk"], |
| 965 | + ) |
| 966 | + ) |
| 967 | + if self.request.user.is_superuser: |
| 968 | + return qs |
| 969 | + return qs.filter( |
| 970 | + group__organization__in=self.request.user.organizations_managed |
| 971 | + ) |
| 972 | + |
| 973 | + def get_parent_queryset(self): |
| 974 | + return User.objects.filter(pk=self.kwargs["user_pk"]) |
| 975 | + |
| 976 | + def get_organization_queryset(self, qs): |
| 977 | + """Filter users by organizations the request user manages.""" |
| 978 | + orgs = self.request.user.organizations_managed |
| 979 | + app_label = User._meta.app_config.label |
| 980 | + filter_kwargs = { |
| 981 | + # exclude superusers |
| 982 | + "is_superuser": False, |
| 983 | + # ensure user is member of the org |
| 984 | + f"{app_label}_organizationuser__organization_id__in": orgs, |
| 985 | + } |
| 986 | + return qs.filter(**filter_kwargs).distinct() |
| 987 | + |
| 988 | + |
| 989 | +class RadiusUserGroupFilter(OrganizationManagedFilter, filters.FilterSet): |
| 990 | + """ |
| 991 | + Filter RADIUS groups by organizations managed by the user. |
| 992 | + """ |
| 993 | + |
| 994 | + # Disable parent's organization_slug; use group__organization__slug instead |
| 995 | + organization_slug = None |
| 996 | + |
| 997 | + class Meta(OrganizationManagedFilter.Meta): |
| 998 | + model = RadiusUserGroup |
| 999 | + fields = ["group__organization", "group__organization__slug"] |
| 1000 | + |
| 1001 | + |
| 1002 | +@method_decorator( |
| 1003 | + name="get", |
| 1004 | + decorator=swagger_auto_schema( |
| 1005 | + operation_description=""" |
| 1006 | + Returns the list of RADIUS user groups for a specific user. |
| 1007 | + """, |
| 1008 | + ), |
| 1009 | +) |
| 1010 | +@method_decorator( |
| 1011 | + name="post", |
| 1012 | + decorator=swagger_auto_schema( |
| 1013 | + operation_description=""" |
| 1014 | + Creates a new RADIUS user group assignment for the user. |
| 1015 | + """, |
| 1016 | + ), |
| 1017 | +) |
| 1018 | +class RadiusUserGroupListCreateView(BaseRadiusUserGroupView, ListCreateAPIView): |
| 1019 | + pagination_class = RadiusGroupPaginator |
| 1020 | + filter_backends = [DjangoFilterBackend] |
| 1021 | + filterset_class = RadiusUserGroupFilter |
| 1022 | + |
| 1023 | + |
| 1024 | +radius_user_group_list = RadiusUserGroupListCreateView.as_view() |
| 1025 | + |
| 1026 | + |
| 1027 | +@method_decorator( |
| 1028 | + name="get", |
| 1029 | + decorator=swagger_auto_schema( |
| 1030 | + operation_description=""" |
| 1031 | + Returns a single RADIUS user group by its UUID. |
| 1032 | + """, |
| 1033 | + ), |
| 1034 | +) |
| 1035 | +@method_decorator( |
| 1036 | + name="put", |
| 1037 | + decorator=swagger_auto_schema( |
| 1038 | + operation_description=""" |
| 1039 | + Updates a RADIUS user group identified by its UUID. |
| 1040 | + """, |
| 1041 | + ), |
| 1042 | +) |
| 1043 | +@method_decorator( |
| 1044 | + name="patch", |
| 1045 | + decorator=swagger_auto_schema( |
| 1046 | + operation_description=""" |
| 1047 | + Partially updates a RADIUS user group identified by its UUID. |
| 1048 | + """, |
| 1049 | + ), |
| 1050 | +) |
| 1051 | +@method_decorator( |
| 1052 | + name="delete", |
| 1053 | + decorator=swagger_auto_schema( |
| 1054 | + operation_description=""" |
| 1055 | + Deletes a RADIUS user group identified by its UUID. |
| 1056 | + """, |
| 1057 | + ), |
| 1058 | +) |
| 1059 | +class RadiusUserGroupDetailView(BaseRadiusUserGroupView, RetrieveUpdateDestroyAPIView): |
| 1060 | + organization_field = "group__organization" |
| 1061 | + |
| 1062 | + |
| 1063 | +radius_user_group_detail = RadiusUserGroupDetailView.as_view() |
0 commit comments