Merge branch 'feature/permission_winery' into 'develop'

Feature/permission winery

See merge request gm/gm-backend!173
This commit is contained in:
d.kuzmenko 2019-12-09 14:05:48 +00:00
commit 6a3a40be4f
8 changed files with 105 additions and 43 deletions

View File

@ -0,0 +1,20 @@
# Generated by Django 2.2.7 on 2019-12-06 06:55
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('establishment', '0067_auto_20191122_1244'),
('account', '0023_auto_20191204_0916'),
]
operations = [
migrations.AddField(
model_name='role',
name='establishment_subtype',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='establishment.EstablishmentSubType', verbose_name='Establishment subtype'),
),
]

View File

@ -1,5 +1,6 @@
"""Account models"""
from datetime import datetime
from tabnanny import verbose
from django.conf import settings
from django.contrib.auth.models import AbstractUser, UserManager as BaseUserManager
@ -15,7 +16,7 @@ from django.utils.translation import ugettext_lazy as _
from rest_framework.authtoken.models import Token
from authorization.models import Application
from establishment.models import Establishment
from establishment.models import Establishment, EstablishmentSubType
from location.models import Country
from main.models import SiteSettings
from utils.models import GMTokenGenerator
@ -33,7 +34,7 @@ class Role(ProjectBaseMixin):
REVIEWER_MANGER = 6
RESTAURANT_REVIEWER = 7
SALES_MAN = 8
WINERY_REVIEWER = 9
WINERY_REVIEWER = 9 # Establishments subtype "winery"
SELLER = 10
ROLE_CHOICES = (
@ -54,6 +55,9 @@ class Role(ProjectBaseMixin):
null=True, blank=True, on_delete=models.SET_NULL)
site = models.ForeignKey(SiteSettings, verbose_name=_('Site settings'),
null=True, blank=True, on_delete=models.SET_NULL)
establishment_subtype = models.ForeignKey(EstablishmentSubType,
verbose_name=_('Establishment subtype'),
null=True, blank=True, on_delete=models.SET_NULL)
class UserManager(BaseUserManager):

View File

@ -33,6 +33,7 @@ class BackUserSerializer(serializers.ModelSerializer):
'email_confirmed',
'newsletter',
'roles',
'password'
)
extra_kwargs = {
'password': {'write_only': True}

View File

@ -8,6 +8,6 @@ app_name = 'account'
urlpatterns = [
path('role/', views.RoleLstView.as_view(), name='role-list-create'),
path('user-role/', views.UserRoleLstView.as_view(), name='user-role-list-create'),
path('user/', views.UserLstView.as_view(), name='user-list-create'),
path('user/', views.UserLstView.as_view(), name='user-create-list'),
path('user/<int:id>/', views.UserRUDView.as_view(), name='user-rud'),
]

View File

@ -830,25 +830,6 @@ class ContactEmail(models.Model):
return f'{self.email}'
#
# class Wine(TranslatedFieldsMixin, models.Model):
# """Wine model."""
# establishment = models.ForeignKey(
# 'establishment.Establishment', verbose_name=_('establishment'),
# on_delete=models.CASCADE)
# bottles = models.IntegerField(_('bottles'))
# price_min = models.DecimalField(
# _('price min'), max_digits=14, decimal_places=2)
# price_max = models.DecimalField(
# _('price max'), max_digits=14, decimal_places=2)
# by_glass = models.BooleanField(_('by glass'))
# price_glass_min = models.DecimalField(
# _('price min'), max_digits=14, decimal_places=2)
# price_glass_max = models.DecimalField(
# _('price max'), max_digits=14, decimal_places=2)
#
class Plate(TranslatedFieldsMixin, models.Model):
"""Plate model."""
STR_FIELD_NAME = 'name'

View File

@ -4,7 +4,8 @@ from account.models import User
from rest_framework import status
from http.cookies import SimpleCookie
from main.models import Currency
from establishment.models import Establishment, EstablishmentType, Menu, SocialChoice, SocialNetwork
from establishment.models import Establishment, EstablishmentType, EstablishmentSubType,\
Menu, SocialChoice, SocialNetwork
# Create your tests here.
from translation.models import Language
from account.models import Role, UserRole
@ -87,7 +88,7 @@ class BaseTestCase(APITestCase):
)
class EstablishmentBTests(BaseTestCase):
class EstablishmentBackTests(BaseTestCase):
def test_establishment_CRUD(self):
params = {'page': 1, 'page_size': 1, }
response = self.client.get('/api/back/establishments/', params, format='json')

View File

@ -3,10 +3,9 @@ from django.http import Http404, HttpResponse
from django.shortcuts import get_object_or_404
from rest_framework import generics, permissions, status
from utils.permissions import IsCountryAdmin, IsEstablishmentManager
from establishment import filters, models, serializers
from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer
from utils.permissions import IsCountryAdmin, IsEstablishmentManager
from utils.permissions import IsCountryAdmin, IsEstablishmentManager, IsWineryReviewer
from utils.views import CreateDestroyGalleryViewMixin
from timetable.models import Timetable
from rest_framework import status
@ -25,7 +24,8 @@ class EstablishmentListCreateView(EstablishmentMixinViews, generics.ListCreateAP
"""Establishment list/create view."""
filter_class = filters.EstablishmentFilter
permission_classes = [IsCountryAdmin | IsEstablishmentManager]
permission_classes = [IsWineryReviewer | IsCountryAdmin | IsEstablishmentManager]
queryset = models.Establishment.objects.all()
serializer_class = serializers.EstablishmentListCreateSerializer
@ -34,14 +34,14 @@ class EstablishmentRUDView(generics.RetrieveUpdateDestroyAPIView):
lookup_field = 'slug'
queryset = models.Establishment.objects.all()
serializer_class = serializers.EstablishmentRUDSerializer
permission_classes = [IsCountryAdmin | IsEstablishmentManager]
permission_classes = [IsWineryReviewer | IsCountryAdmin | IsEstablishmentManager]
class EstablishmentScheduleRUDView(generics.RetrieveUpdateDestroyAPIView):
"""Establishment schedule RUD view"""
lookup_field = 'slug'
serializer_class = ScheduleRUDSerializer
permission_classes = [IsEstablishmentManager]
permission_classes = [IsWineryReviewer |IsEstablishmentManager]
def get_object(self):
"""
@ -67,21 +67,21 @@ class EstablishmentScheduleCreateView(generics.CreateAPIView):
lookup_field = 'slug'
serializer_class = ScheduleCreateSerializer
queryset = Timetable.objects.all()
permission_classes = [IsEstablishmentManager]
permission_classes = [IsWineryReviewer | IsEstablishmentManager]
class MenuListCreateView(generics.ListCreateAPIView):
"""Menu list create view."""
serializer_class = serializers.MenuSerializers
queryset = models.Menu.objects.all()
permission_classes = [IsEstablishmentManager]
permission_classes = [IsWineryReviewer | IsEstablishmentManager]
class MenuRUDView(generics.RetrieveUpdateDestroyAPIView):
"""Menu RUD view."""
serializer_class = serializers.MenuRUDSerializers
queryset = models.Menu.objects.all()
permission_classes = [IsEstablishmentManager]
permission_classes = [IsWineryReviewer | IsEstablishmentManager]
class SocialChoiceListCreateView(generics.ListCreateAPIView):
@ -119,14 +119,14 @@ class PlateListCreateView(generics.ListCreateAPIView):
serializer_class = serializers.PlatesSerializers
queryset = models.Plate.objects.all()
pagination_class = None
permission_classes = [IsEstablishmentManager]
permission_classes = [IsWineryReviewer | IsEstablishmentManager]
class PlateRUDView(generics.RetrieveUpdateDestroyAPIView):
"""Plate RUD view."""
serializer_class = serializers.PlatesSerializers
queryset = models.Plate.objects.all()
permission_classes = [IsEstablishmentManager]
permission_classes = [IsWineryReviewer | IsEstablishmentManager]
class PhonesListCreateView(generics.ListCreateAPIView):
@ -134,14 +134,14 @@ class PhonesListCreateView(generics.ListCreateAPIView):
serializer_class = serializers.ContactPhoneBackSerializers
queryset = models.ContactPhone.objects.all()
pagination_class = None
permission_classes = [IsEstablishmentManager]
permission_classes = [IsWineryReviewer | IsEstablishmentManager]
class PhonesRUDView(generics.RetrieveUpdateDestroyAPIView):
"""Phones RUD view."""
serializer_class = serializers.ContactPhoneBackSerializers
queryset = models.ContactPhone.objects.all()
permission_classes = [IsEstablishmentManager]
permission_classes = [IsWineryReviewer | IsEstablishmentManager]
class EmailListCreateView(generics.ListCreateAPIView):
@ -149,14 +149,14 @@ class EmailListCreateView(generics.ListCreateAPIView):
serializer_class = serializers.ContactEmailBackSerializers
queryset = models.ContactEmail.objects.all()
pagination_class = None
permission_classes = [IsEstablishmentManager]
permission_classes = [IsWineryReviewer | IsEstablishmentManager]
class EmailRUDView(generics.RetrieveUpdateDestroyAPIView):
"""Email RUD view."""
serializer_class = serializers.ContactEmailBackSerializers
queryset = models.ContactEmail.objects.all()
permission_classes = [IsEstablishmentManager]
permission_classes = [IsWineryReviewer | IsEstablishmentManager]
class EmployeeListCreateView(generics.ListCreateAPIView):

View File

@ -7,7 +7,8 @@ from rest_framework_simplejwt.tokens import AccessToken
from account.models import UserRole, Role
from authorization.models import JWTRefreshToken
from utils.tokens import GMRefreshToken
from establishment.models import EstablishmentSubType
from location.models import Address
class IsAuthenticatedAndTokenIsValid(permissions.BasePermission):
"""
@ -56,8 +57,9 @@ class IsGuest(permissions.IsAuthenticatedOrReadOnly):
"""
Object-level permission to only allow owners of an object to edit it.
"""
SAFE_METHODS = ('GET', 'HEAD', 'OPTIONS')
def has_permission(self, request, view):
rules = [
request.user.is_superuser,
request.method in permissions.SAFE_METHODS
@ -306,7 +308,6 @@ class IsEstablishmentManager(IsStandardUser):
rules = [
# special!
super().has_permission(request, view)
# super().has_object_permission(request, view, obj)
]
role = Role.objects.filter(role=Role.ESTABLISHMENT_MANAGER) \
@ -319,7 +320,6 @@ class IsEstablishmentManager(IsStandardUser):
).exists(),
# special!
super().has_permission(request, view)
# super().has_object_permission(request, view, obj)
]
return any(rules)
@ -368,7 +368,7 @@ class IsRestaurantReviewer(IsStandardUser):
# and request.user.email_confirmed,
if hasattr(request.data, 'user') and hasattr(request.data, 'object_id'):
role = Role.objects.filter(role=Role.RESTAURANT_REVIEWER) \
.first() # 'Comments moderator'
.first()
rules = [
UserRole.objects.filter(user=request.user, role=role,
@ -394,3 +394,58 @@ class IsRestaurantReviewer(IsStandardUser):
]
return any(rules)
class IsWineryReviewer(IsStandardUser):
def has_permission(self, request, view):
rules = [
super().has_permission(request, view)
]
if 'type_id' in request.data and 'address_id' in request.data and request.user:
countries = Address.objects.filter(id=request.data['address_id'])
est = EstablishmentSubType.objects.filter(establishment_type_id=request.data['type_id'])
if est.exists():
role = Role.objects.filter(establishment_subtype_id__in=[type.id for type in est],
role=Role.WINERY_REVIEWER,
country_id__in=[country.id for country in countries]) \
.first()
rules.append(
UserRole.objects.filter(user=request.user, role=role).exists()
)
return any(rules)
def has_object_permission(self, request, view, obj):
rules = [
super().has_object_permission(request, view, obj)
]
if hasattr(obj, 'type_id') or hasattr(obj, 'establishment_type_id'):
type_id: int
if hasattr(obj, 'type_id'):
type_id = obj.type_id
else:
type_id = obj.establishment_type_id
est = EstablishmentSubType.objects.filter(establishment_type_id=type_id)
role = Role.objects.filter(role=Role.WINERY_REVIEWER,
establishment_subtype_id__in=[id for type.id in est],
country_id=obj.country_id).first()
object_id: int
if hasattr(obj, 'object_id'):
object_id = obj.object_id
else:
object_id = obj.establishment_id
rules = [
UserRole.objects.filter(user=request.user, role=role,
establishment_id=object_id
).exists(),
super().has_object_permission(request, view, obj)
]
return any(rules)