diff --git a/apps/account/models.py b/apps/account/models.py index f34d8634..c43f7e19 100644 --- a/apps/account/models.py +++ b/apps/account/models.py @@ -1,6 +1,7 @@ """Account models""" from collections import Counter from datetime import datetime +from typing import List from django.conf import settings from django.contrib.auth.models import AbstractUser, UserManager as BaseUserManager @@ -15,8 +16,6 @@ from django.utils.http import urlsafe_base64_encode from django.utils.translation import ugettext_lazy as _ from phonenumber_field.modelfields import PhoneNumberField from rest_framework.authtoken.models import Token -from collections import Counter -from typing import List from authorization.models import Application from establishment.models import Establishment, EstablishmentSubType @@ -74,16 +73,6 @@ class Role(ProjectBaseMixin): (ARTISAN_INSPECTOR, _('Artisan inspector')), ) - ESTABLISHMENT_EDITORS = [ - COUNTRY_ADMIN, - ESTABLISHMENT_MANAGER, - ESTABLISHMENT_ADMINISTRATOR, - ] - - PRODUCT_EDITORS = ESTABLISHMENT_EDITORS + [ - DISTILLERY_LIQUOR_INSPECTOR - ] - role = models.PositiveIntegerField(verbose_name=_('Role'), choices=ROLE_CHOICES, null=False, blank=False) country = models.ForeignKey(Country, verbose_name=_('Country'), diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 0371ae17..2ca28311 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -14,7 +14,7 @@ from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.indexes import GinIndex from django.contrib.postgres.search import TrigramSimilarity from django.core.exceptions import ValidationError -from django.core.validators import MinValueValidator, MaxValueValidator, FileExtensionValidator +from django.core.validators import MinValueValidator, MaxValueValidator from django.db import models from django.db.models import When, Case, F, ExpressionWrapper, Subquery, Q, Prefetch from django.shortcuts import get_object_or_404 @@ -519,27 +519,22 @@ class EstablishmentQuerySet(models.QuerySet): to_attr='main_image') ) - def available_establishments(self, user): - """Return QuerySet with establishment that user has an access.""" + def available_establishments(self, user, country_code: str): + """Return QuerySet with establishments that user has an access.""" from account.models import UserRole - administrator_establishment_ids = [] - filters = {} - - # put in array administrated establishment ids - if user.is_establishment_administrator: - administrator_establishment_ids.extend( - UserRole.objects.filter(user=user) - .distinct('user', 'establishment') - .values_list('establishment', flat=True) - ) - # check if user is_staff if not user.is_staff: - filters.update({'address__city__country__code__in': user.administrated_country_codes}) - - return self.filter(**filters).union( - self.filter(id__in=administrator_establishment_ids) - ) + filters = {'address__city__country__code': country_code} + if user.is_establishment_administrator and not user.is_establishment_manager: + filters.update({ + 'id__in': models.Subquery( + UserRole.objects.filter(user=user, role__site__country__code=country_code) + .distinct('user', 'establishment') + .values_list('establishment', flat=True) + ) + }) + return self.filter(**filters) + return self def with_contacts(self): return self.prefetch_related('emails', 'phones') diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index e1d97b91..beabf801 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -3,7 +3,7 @@ from django.db.models.query_utils import Q from django.http import Http404 from django.shortcuts import get_object_or_404 from django_filters.rest_framework import DjangoFilterBackend -from rest_framework import generics, status, permissions +from rest_framework import generics, status from rest_framework.response import Response from account.models import User @@ -13,8 +13,7 @@ from timetable.models import Timetable from timetable.serialziers import ScheduleCreateSerializer, ScheduleRUDSerializer from utils.methods import get_permission_classes from utils.permissions import ( - IsEstablishmentManager, IsEstablishmentAdministrator, IsReviewManager, -) + IsEstablishmentManager, IsEstablishmentAdministrator, ) from utils.views import CreateDestroyGalleryViewMixin @@ -40,7 +39,7 @@ class EstablishmentMixinViews: queryset = models.Establishment.objects.with_base_related if hasattr(self, 'request') and \ (hasattr(self.request, 'user') and hasattr(self.request, 'country_code')): - return queryset().available_establishments(self.request.user) + return queryset().available_establishments(self.request.user, self.request.country_code) return queryset().none() diff --git a/apps/news/models.py b/apps/news/models.py index 758269b8..dc7f8898 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -1,15 +1,16 @@ """News app models.""" import uuid +from datetime import datetime import elasticsearch_dsl from django.conf import settings from django.contrib.contenttypes import fields as generic from django.contrib.contenttypes.models import ContentType from django.contrib.postgres.fields import HStoreField +from django.contrib.postgres.search import TrigramSimilarity from django.db import models from django.db.models import Case, When, Q, F from django.db.models.functions import Cast -from django.contrib.postgres.search import TrigramSimilarity from django.urls.exceptions import NoReverseMatch from django.utils import timezone from django.utils.translation import gettext_lazy as _ @@ -21,7 +22,6 @@ from utils.models import (BaseAttributes, TJSONField, TranslatedFieldsMixin, Has ProjectBaseMixin, GalleryMixin, IntermediateGalleryModelMixin, FavoritesMixin, TypeDefaultImageMixin) from utils.querysets import TranslationQuerysetMixin -from datetime import datetime class Agenda(ProjectBaseMixin, TranslatedFieldsMixin): @@ -244,6 +244,10 @@ class NewsQuerySet(TranslationQuerysetMixin): 'subtitle_similarity')) ).filter(relevance__gte=0.3).order_by('-relevance') + def available_news(self, user, country_code: str): + """Return QuerySet with news that user has an access.""" + return self.filter(site__country__code=country_code) if not user.is_staff else self + class News(GalleryMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixin, FavoritesMixin): diff --git a/apps/news/views.py b/apps/news/views.py index 665eb60d..ff6b165e 100644 --- a/apps/news/views.py +++ b/apps/news/views.py @@ -129,11 +129,18 @@ class NewsBackOfficeMixinView: permission_classes = get_permission_classes(IsContentPageManager, IsContentPageManager) def get_queryset(self): - """Override get_queryset method.""" - qs = models.News.objects.with_base_related() \ - .annotate_in_favorites(self.request.user) \ - .order_by('-is_highlighted', '-created') - return qs + """Overridden get_queryset method.""" + queryset = models.News.objects + if hasattr(self, 'request') and \ + (hasattr(self.request, 'user') and hasattr(self.request, 'country_code')): + user = self.request.user + return ( + queryset.with_base_related() + .annotate_in_favorites(user) + .available_news(user, self.request.country_code) + .order_by('-is_highlighted', '-created') + ) + return queryset.none() class NewsBackOfficeLCView(NewsBackOfficeMixinView, @@ -165,8 +172,6 @@ class NewsBackOfficeLCView(NewsBackOfficeMixinView, self.request.query_params['ordering'] = self.request.query_params['ordering']\ .replace('publication_datetime', 'publication_date,publication_time') self.request.GET._mutable = False - if self.request.country_code: - qs = qs.by_country_code(self.request.country_code) return qs diff --git a/apps/partner/views/back.py b/apps/partner/views/back.py index 80d70d62..c130ed4a 100644 --- a/apps/partner/views/back.py +++ b/apps/partner/views/back.py @@ -17,24 +17,24 @@ class PartnerLstView(generics.ListCreateAPIView): queryset = Partner.objects.with_base_related() serializer_class = serializers.BackPartnerSerializer pagination_class = None + filter_class = filters.PartnerFilterSet permission_classes = get_permission_classes( IsEstablishmentManager, IsEstablishmentAdministrator ) - filter_class = filters.PartnerFilterSet class EstablishmentPartners(generics.ListAPIView): queryset = PartnerToEstablishment.objects.prefetch_related('partner', 'partner__country') serializer_class = serializers.PartnersForEstablishmentSerializer pagination_class = None + filter_backends = (OrderingFilter, DjangoFilterBackend) + ordering_fields = '__all__' + ordering = '-partner_bind_date' permission_classes = get_permission_classes( IsEstablishmentManager, IsEstablishmentAdministrator ) - filter_backends = (OrderingFilter, DjangoFilterBackend) - ordering_fields = '__all__' - ordering = '-partner_bind_date' def get_queryset(self): return super().get_queryset().filter(establishment=self.kwargs['establishment_id']) diff --git a/apps/product/models.py b/apps/product/models.py index 068350e4..851bc138 100644 --- a/apps/product/models.py +++ b/apps/product/models.py @@ -227,27 +227,22 @@ class ProductQuerySet(models.QuerySet): .distinct(*similarity_rules['distinction'], 'id') - def available_products(self, user): - """Return QuerySet with establishment that user has an access.""" + def available_products(self, user, country_code: str): + """Return QuerySet with products that user has an access.""" from account.models import UserRole - administrator_establishment_ids = [] - filters = {} - - # put in array administrated establishment ids - if user.is_establishment_administrator: - administrator_establishment_ids.extend( - UserRole.objects.filter(user=user) - .distinct('user', 'establishment') - .values_list('establishment', flat=True) - ) - # check if user is_staff if not user.is_staff: - filters.update({'establishment__address__city__country__code__in': user.administrated_country_codes}) - - return self.filter(**filters).union( - self.filter(establishment__id__in=administrator_establishment_ids) - ) + filters = {'establishment__address__city__country__code': country_code} + if user.is_establishment_administrator and not user.is_establishment_manager: + filters.update({ + 'establishment__id__in': models.Subquery( + UserRole.objects.filter(user=user, role__site__country__code=country_code) + .distinct('user', 'establishment') + .values_list('establishment', flat=True) + ) + }) + return self.filter(**filters) + return self class Product(GalleryMixin, TranslatedFieldsMixin, BaseAttributes, diff --git a/apps/product/views/back.py b/apps/product/views/back.py index 639f6bf0..17902917 100644 --- a/apps/product/views/back.py +++ b/apps/product/views/back.py @@ -28,7 +28,7 @@ class ProductBackOfficeMixinView(ProductBaseView): ) if hasattr(self, 'request') and \ (hasattr(self.request, 'user') and hasattr(self.request, 'country_code')): - return queryset.available_products(self.request.user) + return queryset.available_products(self.request.user, self.request.country_code) return queryset.none() diff --git a/apps/utils/permissions.py b/apps/utils/permissions.py index af6a0806..7fe145f5 100644 --- a/apps/utils/permissions.py +++ b/apps/utils/permissions.py @@ -100,7 +100,7 @@ class IsContentPageManager(IsApprovedUser): role=Role.CONTENT_PAGE_MANAGER, site__country__code=request.country_code, ).only('id') if role.exists(): - user_role = UserRole.objects.filter( + user_role = UserRole.objects.validated().filter( user=request.user, role__id__in=role.values_list('id', flat=True), ).only('id') has_permission = True if user_role.exists() else has_permission @@ -125,7 +125,7 @@ class IsCountryAdmin(IsApprovedUser): role=Role.COUNTRY_ADMIN, site__country__code=request.country_code, ).only('id') if role.exists(): - user_role = UserRole.objects.filter( + user_role = UserRole.objects.validated().filter( user=request.user, role__id__in=role.values_list('id', flat=True) ).only('id') has_permission = True if user_role.exists() else has_permission @@ -150,7 +150,7 @@ class IsModerator(IsApprovedUser): role=Role.MODERATOR, site__country__code=request.country_code, ).only('id') if role.exists(): - user_role = UserRole.objects.filter( + user_role = UserRole.objects.validated().filter( user=request.user, role__id__in=role.values_list('id', flat=True), ).only('id') has_permission = True if user_role.exists() else has_permission @@ -173,7 +173,7 @@ class IsEstablishmentManager(IsApprovedUser): role=Role.ESTABLISHMENT_MANAGER, site__country__code=request.country_code, ).only('id') if role.exists(): - user_role = UserRole.objects.filter( + user_role = UserRole.objects.validated().filter( user=user, role__id__in=role.values_list('id', flat=True), ).only('id') has_permission = True if user_role.exists() else has_permission @@ -195,7 +195,7 @@ class IsEstablishmentAdministrator(IsApprovedUser): role=Role.ESTABLISHMENT_ADMINISTRATOR, site__country__code=request.country_code, ).only('id') if role.exists(): - user_role = UserRole.objects.filter( + user_role = UserRole.objects.validated().filter( user=request.user, role__id__in=role.values_list('id', flat=True), ).only('id') has_permission = True if user_role.exists() else has_permission @@ -218,7 +218,7 @@ class IsEstablishmentAdministrator(IsApprovedUser): if isinstance(obj, Product): filters.update({'establishment__products__id': obj.id}) - user_role = UserRole.objects.filter(**filters) + user_role = UserRole.objects.validated().filter(**filters) has_object_permission = True if user_role.exists() else has_object_permission rules.append(has_object_permission) return all(rules) @@ -243,7 +243,7 @@ class IsReviewManager(IsApprovedUser): role=Role.REVIEW_MANAGER, site__country__code=request.country_code, ).only('id') if role.exists(): - user_role = UserRole.objects.filter( + user_role = UserRole.objects.validated().filter( user=request.user, role__id__in=role.values_list('id', flat=True), ).only('id') if user_role.exists(): @@ -276,7 +276,7 @@ class IsRestaurantInspector(IsApprovedUser): role=Role.RESTAURANT_INSPECTOR, site__country__code=request.country_code, ).only('id') if role.exists(): - user_role = UserRole.objects.filter( + user_role = UserRole.objects.validated().filter( user=request.user, role__id__in=role.values_list('id', flat=True), ).only('id') if user_role.exists(): @@ -309,7 +309,7 @@ class IsArtisanInspector(IsApprovedUser): role=Role.ARTISAN_INSPECTOR, site__country__code=request.country_code, ).only('id') if role.exists(): - user_role = UserRole.objects.filter( + user_role = UserRole.objects.validated().filter( user=request.user, role__id__in=role.values_list('id', flat=True), ).only('id') if user_role.exists(): @@ -342,7 +342,7 @@ class IsWineryWineInspector(IsApprovedUser): role=Role.WINERY_WINE_INSPECTOR, site__country__code=request.country_code, ).only('id') if role.exists(): - user_role = UserRole.objects.filter( + user_role = UserRole.objects.validated().filter( user=request.user, role__id__in=role.values_list('id', flat=True), ).only('id') if user_role.exists(): @@ -375,7 +375,7 @@ class IsProducerFoodInspector(IsApprovedUser): role=Role.PRODUCER_FOOD_INSPECTOR, site__country__code=request.country_code, ).only('id') if role.exists(): - user_role = UserRole.objects.filter( + user_role = UserRole.objects.validated().filter( user=request.user, role__id__in=role.values_list('id', flat=True), ).only('id') if user_role.exists(): @@ -408,7 +408,7 @@ class IsDistilleryLiquorInspector(IsApprovedUser): role=Role.DISTILLERY_LIQUOR_INSPECTOR, site__country__code=request.country_code, ).only('id') if role.exists(): - user_role = UserRole.objects.filter( + user_role = UserRole.objects.validated().filter( user=request.user, role__id__in=role.values_list('id', flat=True), ).only('id') if user_role.exists():