From 587f6c0bad0e5c5dec901c096b7e427a26e359af Mon Sep 17 00:00:00 2001 From: Anatoly Date: Thu, 23 Jan 2020 13:28:57 +0300 Subject: [PATCH] fix role counter, added additional field role choice id --- apps/account/models.py | 63 ++++++++++++++++++++++++-------- apps/account/serializers/back.py | 6 --- apps/account/urls/back.py | 3 +- apps/account/views/back.py | 38 +++++-------------- 4 files changed, 59 insertions(+), 51 deletions(-) diff --git a/apps/account/models.py b/apps/account/models.py index acb56089..0175ccf0 100644 --- a/apps/account/models.py +++ b/apps/account/models.py @@ -12,6 +12,7 @@ from django.utils.html import mark_safe from django.utils.http import urlsafe_base64_encode from django.utils.translation import ugettext_lazy as _ from rest_framework.authtoken.models import Token +from collections import Counter from authorization.models import Application from establishment.models import Establishment, EstablishmentSubType @@ -84,26 +85,13 @@ class Role(ProjectBaseMixin): objects = RoleQuerySet.as_manager() - @classmethod - def role_names(cls): - return [role_name for role_name in dict(cls.ROLE_CHOICES).values()] - @classmethod def role_types(cls): roles = [] - for role_id, role in dict(cls.ROLE_CHOICES).items(): - roles.append({'id': role_id, 'name': role}) + for role, display_name in dict(cls.ROLE_CHOICES).items(): + roles.append({'role_name': role, 'role_counter': display_name, 'role': 0}) return roles - @classmethod - def role_condition_expressions(cls) -> list: - role_choices = {role_id: role_name._proxy____args[0] - for role_id, role_name in dict(cls.ROLE_CHOICES).items()} - - whens = [models.When(role=role_id, then=models.Value(role_name)) - for role_id, role_name in role_choices.items()] - return whens - class UserManager(BaseUserManager): """Extended manager for User model.""" @@ -124,6 +112,14 @@ class UserManager(BaseUserManager): class UserQuerySet(models.QuerySet): """Extended queryset for User model.""" + def with_base_related(self): + """Return QuerySet with base related.""" + return self.select_related('last_country', 'last_country__country') + + def with_extend_related(self): + """Return QuerySet with extend related.""" + return self.with_base_related().prefetch_related('roles', 'subscriber') + def active(self, switcher=True): """Filter only active users.""" return self.filter(is_active=switcher) @@ -403,10 +399,47 @@ class User(AbstractUser): class UserRoleQueryset(models.QuerySet): """QuerySet for model UserRole.""" + def _role_counter(self, country_code: str = None) -> dict: + additional_filters = { + 'state': self.model.VALIDATED, + } + + if country_code: + additional_filters.update({'role__site__country__code': country_code}) + + user_roles = ( + self.filter(**additional_filters) + .distinct('user_id', 'role__role') + .values('user_id', 'role__role') + ) + return dict(Counter([i['role__role'] for i in user_roles])) + def country_admin_role(self): return self.filter(role__role=self.model.role.field.target_field.model.COUNTRY_ADMIN, state=self.model.VALIDATED) + def aggregate_role_counter(self, country_code: str = None) -> list: + _role_choices = dict(Role.ROLE_CHOICES) + role_counter = [] + + # fill existed roles + for role, count in self._role_counter(country_code=country_code).items(): + role_counter.append({ + 'role': role, + 'role_name': _role_choices[role], + 'count': count, + }) + + # check by roles + for role, role_name in _role_choices.items(): + if role not in [i['role'] for i in role_counter]: + role_counter.append({ + 'role': role, + 'role_name': _role_choices[role], + 'count': 0, + }) + return role_counter + class UserRole(ProjectBaseMixin): """UserRole model.""" diff --git a/apps/account/serializers/back.py b/apps/account/serializers/back.py index b38b9042..2baaf656 100644 --- a/apps/account/serializers/back.py +++ b/apps/account/serializers/back.py @@ -143,9 +143,3 @@ class UserRoleSerializer(serializers.ModelSerializer): 'user', 'establishment' ] - - -class RoleTabRetrieveSerializer(serializers.Serializer): - """Serializer for BackOffice role tab.""" - role_name = serializers.CharField() - role_counter = serializers.IntegerField() diff --git a/apps/account/urls/back.py b/apps/account/urls/back.py index db7cb772..a24a33e6 100644 --- a/apps/account/urls/back.py +++ b/apps/account/urls/back.py @@ -7,8 +7,7 @@ app_name = 'account' urlpatterns = [ path('role/', views.RoleListView.as_view(), name='role-list-create'), - path('role/types/', views.RoleChoiceListView.as_view(), name='role-type-list'), - path('role/tab/', views.RoleTabRetrieveView.as_view(), name='role-tab'), + path('role/types/', views.RoleTypeRetrieveView.as_view(), name='role-types'), path('user-role/', views.UserRoleListView.as_view(), name='user-role-list-create'), path('user/', views.UserListView.as_view(), name='user-create-list'), path('user//', views.UserRUDView.as_view(), name='user-rud'), diff --git a/apps/account/views/back.py b/apps/account/views/back.py index f339ffb7..0fd9bdde 100644 --- a/apps/account/views/back.py +++ b/apps/account/views/back.py @@ -18,39 +18,18 @@ class RoleListView(generics.ListCreateAPIView): filter_class = filters.RoleListFilter -class RoleChoiceListView(generics.GenericAPIView): - """Return role choices.""" - def get(self, request, *args, **kwargs): - """Implement GET-method""" - return Response(models.Role.role_types(), status=status.HTTP_200_OK) - - -class RoleTabRetrieveView(generics.GenericAPIView): +class RoleTypeRetrieveView(generics.GenericAPIView): permission_classes = [permissions.IsAdminUser] - def get_queryset(self): - """Overridden get_queryset method.""" - additional_filters = {} + def get(self, request, *args, **kwargs): + """Implement GET-method""" + country_code = None if (self.request.user.userrole_set.country_admin_role().exists() and hasattr(self.request, 'country_code')): - additional_filters.update({'country__code': self.request.country_code}) - - return models.Role.objects.filter(**additional_filters)\ - .annotate_role_name()\ - .values('role_name')\ - .annotate_role_counter()\ - .values('role_name', 'role_counter') - - def get(self, request, *args, **kwargs): - """Implement GET-method""" - data = list(self.get_queryset()) - - # todo: Need refactoring. Extend data list with non-existed role. - for role in models.Role.role_names(): - if role not in [role.get('role_name') for role in data]: - data.append({'role_name': role, 'role_counter': 0}) + country_code = self.request.country_code + data = models.UserRole.objects.aggregate_role_counter(country_code) return Response(data, status=status.HTTP_200_OK) @@ -61,7 +40,6 @@ class UserRoleListView(generics.ListCreateAPIView): class UserListView(generics.ListCreateAPIView): """User list create view.""" - queryset = User.objects.prefetch_related('roles', 'subscriber') serializer_class = serializers.BackUserSerializer permission_classes = (permissions.IsAdminUser,) filter_class = filters.AccountBackOfficeFilter @@ -76,6 +54,10 @@ class UserListView(generics.ListCreateAPIView): 'date_joined', ) + def get_queryset(self): + """Overridden get_queryset method.""" + return User.objects.with_extend_related() + class UserRUDView(generics.RetrieveUpdateDestroyAPIView): """User RUD view."""