diff --git a/back_latienda/permissions.py b/back_latienda/permissions.py index f39454a..0ec3c4f 100644 --- a/back_latienda/permissions.py +++ b/back_latienda/permissions.py @@ -19,3 +19,7 @@ class IsCreator(permissions.BasePermission): return obj.creator == request.user return False + +class ReadOnly(permissions.BasePermission): + def has_permission(self, request, view): + return request.method in permissions.SAFE_METHODS diff --git a/back_latienda/routers.py b/back_latienda/routers.py index fe78d68..f0a920e 100644 --- a/back_latienda/routers.py +++ b/back_latienda/routers.py @@ -5,9 +5,17 @@ from products.views import ProductViewSet from history.views import HistorySyncViewSet from stats.views import StatsLogViewSet +from geo import views as geo_views router = routers.DefaultRouter() -router.register('companies', CompanyViewSet) -router.register('products', ProductViewSet) -router.register('history', HistorySyncViewSet) -router.register('stats', StatsLogViewSet) + +router.register('companies', CompanyViewSet, basename='company') +router.register('products', ProductViewSet, basename='product') +router.register('history', HistorySyncViewSet, basename='history') +router.register('stats', StatsLogViewSet, basename='stats') + +# Geo +router.register('countries', geo_views.CountryViewSet, basename='country') +router.register('regions', geo_views.RegionViewSet, basename='region') +router.register('provinces', geo_views.ProvinceViewSet, basename='province') +router.register('cities', geo_views.CityViewSet, basename='city') diff --git a/companies/tests.py b/companies/tests.py index 375a355..20c474c 100644 --- a/companies/tests.py +++ b/companies/tests.py @@ -10,12 +10,14 @@ from rest_framework import status from companies.factories import CompanyFactory from companies.models import Company -from core.utils import get_auth_token, create_active_user +from core.factories import CustomUserFactory + +from core.utils import get_auth_token, create_active_user, get_tokens_for_user # Create your tests here. -class BuildingViewSetTest(APITestCase): - """Building viewset tests +class CompanyViewSetTest(APITestCase): + """CompanyViewset tests """ def setUp(self): @@ -25,10 +27,8 @@ class BuildingViewSetTest(APITestCase): self.factory = CompanyFactory self.model = Company # create user - self.rand = ''.join(random.choices(string.ascii_uppercase, k = 5)) self.password = ''.join(random.choices(string.ascii_uppercase, k = 10)) - self.email = f"{self.rand}@mail.com" - self.user = create_active_user(email=self.email, password=self.password) + self.user = CustomUserFactory(password=self.password) # user not authenticated def test_not_logged_user_cannot_create_instance(self): @@ -85,8 +85,8 @@ class BuildingViewSetTest(APITestCase): instances = [self.factory() for n in range(random.randint(1,5))] # Authenticate user - token = get_auth_token(self.client, self.email, self.password) - self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}") + token = get_tokens_for_user(self.user) + self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {token['access']}") # Request list response = self.client.get(self.endpoint) @@ -125,8 +125,8 @@ class BuildingViewSetTest(APITestCase): } # Authenticate user - token = get_auth_token(self.client, self.email, self.password) - self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}") + token = get_tokens_for_user(self.user) + self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {token['access']}") # Query endpoint response = self.client.post(self.endpoint, data=data, format='json') @@ -171,8 +171,8 @@ class BuildingViewSetTest(APITestCase): } # Authenticate user - token = get_auth_token(self.client, self.email, self.password) - self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}") + token = get_tokens_for_user(self.user) + self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {token['access']}") # Query endpoint url = self.endpoint + f'{instance.pk}/' @@ -192,8 +192,8 @@ class BuildingViewSetTest(APITestCase): instance = self.factory() # Authenticate user - token = get_auth_token(self.client, self.email, self.password) - self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}") + token = get_tokens_for_user(self.user) + self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {token['access']}") # Query endpoint url = self.endpoint + f'{instance.pk}/' @@ -209,8 +209,8 @@ class BuildingViewSetTest(APITestCase): instance = self.factory() # Authenticate user - token = get_auth_token(self.client, self.email, self.password) - self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}") + token = get_tokens_for_user(self.user) + self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {token['access']}") # Query endpoint url = self.endpoint + f'{instance.pk}/' @@ -229,8 +229,8 @@ class BuildingViewSetTest(APITestCase): instance.save() # Authenticate user - token = get_auth_token(self.client, self.email, self.password) - self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}") + token = get_tokens_for_user(self.user) + self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {token['access']}") # Query endpoint url = self.endpoint + f'{instance.pk}/' diff --git a/core/factories.py b/core/factories.py new file mode 100644 index 0000000..b5506e2 --- /dev/null +++ b/core/factories.py @@ -0,0 +1,20 @@ +import datetime +from django.utils import timezone + +from factory import LazyAttribute, SubFactory +from factory.fuzzy import FuzzyText, FuzzyChoice, FuzzyDateTime, FuzzyDate, FuzzyDecimal +from factory.django import DjangoModelFactory + + +class CustomUserFactory(DjangoModelFactory): + + email = FuzzyText(length=6, suffix="@mail.com") + full_name = FuzzyText(length=15, prefix="TestName_") + role = FuzzyText(length=15, prefix="TestPosition_") + notify = FuzzyChoice(choices=(True, False)) + provider = FuzzyText(length=15, prefix="TestProvider_") + email_verified = True + # company = None + + class Meta: + model = 'core.CustomUser' diff --git a/core/utils.py b/core/utils.py index c78133d..7fcb253 100644 --- a/core/utils.py +++ b/core/utils.py @@ -2,9 +2,17 @@ import logging from django.contrib.auth import get_user_model +from rest_framework_simplejwt.tokens import RefreshToken User = get_user_model() +def get_tokens_for_user(user): + refresh = RefreshToken.for_user(user) + + return { + 'refresh': str(refresh), + 'access': str(refresh.access_token), + } def get_auth_token(client, email, password): credentials = { diff --git a/geo/serializers.py b/geo/serializers.py index 1ef38be..483b97c 100644 --- a/geo/serializers.py +++ b/geo/serializers.py @@ -3,50 +3,32 @@ from rest_framework import serializers from . import models -class CountryReadSerializer(serializers.ModelSerializer): +class CountrySerializer(serializers.ModelSerializer): class Meta: model = models.Country - fields = '__all__' + exclude = ['created', 'updated'] -class CountryWriteSerializer(CustomWriteSerializer): +class RegionSerializer(serializers.ModelSerializer): - class Meta: - model = models.Country - fields = '__all__' - - -class RegionWriteSerializer(CustomWriteSerializer): - country = serializers.IntegerField() - - def validate_country(self, value): - return models.Country.objects.using(self.context['db']).filter(id=value).first() + country = CountrySerializer() class Meta: model = models.Region - fields = '__all__' + exclude = ['created', 'updated'] -class RegionReadSerializer(serializers.ModelSerializer): +class ProvinceSerializer(serializers.ModelSerializer): - country = CountryReadSerializer() - - class Meta: - model = models.Region - fields = '__all__' - - -class ProvinceReadSerializer(serializers.ModelSerializer): - - region = RegionReadSerializer() + region = RegionSerializer() class Meta: model = models.Province - fields = '__all__' + exclude = ['created', 'updated'] -class CityWriteSerializer(CustomWriteSerializer): +class CityWriteSerializer(serializers.ModelSerializer): region = serializers.IntegerField() @@ -55,14 +37,12 @@ class CityWriteSerializer(CustomWriteSerializer): class Meta: model = models.City - fields = '__all__' + exclude = ['created', 'updated'] -class CityReadSerializer(serializers.ModelSerializer): - - province = ProvinceReadSerializer() +class CitySerializer(serializers.ModelSerializer): class Meta: model = models.City - fields = '__all__' + exclude = ['created', 'updated'] diff --git a/geo/tests.py b/geo/tests.py index f6f5990..5d44fc0 100644 --- a/geo/tests.py +++ b/geo/tests.py @@ -8,9 +8,7 @@ from django.utils import timezone from rest_framework.test import APITestCase from rest_framework import status -import jwt - -from tenants.factories import TenantUserFactory +from core.factories import CustomUserFactory from . import models from . import factories @@ -68,6 +66,32 @@ class RegionTest(TestCase): self.assertEqual(getattr(instance, field), data[field]) +class ProvinceTest(TestCase): + """Province model tests + """ + + def setUp(self): + """Tests setup + """ + self.model = models.Province + + def test_content(self): + """Test content correctly set + """ + # Define instance data + data = { + 'name': 'region name _test_ data', + 'region': factories.RegionFactory(), + } + + # Create instance + instance = self.model.objects.create(**data) + + # Assert content correctly set + for field in data.keys(): + self.assertEqual(getattr(instance, field), data[field]) + + class CityTest(TestCase): """City model tests """ @@ -94,37 +118,11 @@ class CityTest(TestCase): self.assertEqual(getattr(instance, field), data[field]) -class JurisdictionTest(TestCase): - """Jurisdiction model tests - """ - - def setUp(self): - """Tests setup - """ - self.model = models.Jurisdiction - - def test_content(self): - """Test content correctly set - """ - # Define instance data - data = { - 'name': 'jurisdiction name test data', - 'region': factories.RegionFactory(), - } - - # Create instance - instance = self.model.objects.create(**data) - - # Assert content correctly set - for field in data.keys(): - self.assertEqual(getattr(instance, field), data[field]) - # ViewSet Tests class CountryViewSetTest(APITestCase): """Country viewset tests """ - databases = {'default', 'tenants'} def setUp(self): """Tests setup @@ -182,7 +180,7 @@ class CountryViewSetTest(APITestCase): """Regular logged-in user can list country """ # Create instances - user = TenantUserFactory() + user = CustomUserFactory() instances = [self.factory() for n in range(random.randint(1,5))] # Authenticate user @@ -207,8 +205,7 @@ class CountryViewSetTest(APITestCase): } # Authenticate user - user = TenantUserFactory() - user.db = 'default' + user = CustomUserFactory() self.client.force_authenticate(user=user) # Query endpoint @@ -268,7 +265,6 @@ class CountryViewSetTest(APITestCase): class RegionViewSetTest(APITestCase): """Region viewset tests """ - databases = {'default', 'tenants'} def setUp(self): """Tests setup @@ -415,7 +411,6 @@ class RegionViewSetTest(APITestCase): class CityViewSetTest(APITestCase): """City viewset tests """ - databases = {'default', 'tenants'} def setUp(self): """Tests setup @@ -558,155 +553,3 @@ class CityViewSetTest(APITestCase): # Assert instance doesn't exists on db anymore self.assertFalse(self.model.objects.filter(id=instance.pk).exists()) - -class JurisdictionViewSetTest(APITestCase): - """Jurisdiction viewset tests - """ - databases = {'default', 'tenants'} - - def setUp(self): - """Tests setup - """ - self.endpoint = 'api-v1:jurisdiction-' - self.factory = factories.JurisdictionFactory - self.model = models.Jurisdiction - - def test_not_logged_user_cannot_create_jurisdiction(self): - """Not logged-in user cannot create new city - """ - # Query endpoint - url = reverse(self.endpoint+'list') - response = self.client.post(url, data={}) - - # Assert access is forbidden - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - - def test_not_logged_user_cannot_modify_existing_jurisdiction(self): - """Not logged-in user cannot modify existing city - """ - # Create instance - instance = self.factory() - - # Query endpoint - url = reverse(self.endpoint+'detail', args=[instance.pk]) - response = self.client.put(url, {}, format='json') - - # Assert forbidden code - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - - def test_not_logged_user_cannot_delete_existing_jurisdiction(self): - """Not logged-in user cannot delete existing city - """ - # Create instances - instance = self.factory() - - # Query endpoint - url = reverse(self.endpoint+'detail', args=[instance.pk]) - response = self.client.delete(url) - - # Assert instance still exists on db - self.assertTrue(self.model.objects.get(id=instance.pk)) - - def test_not_logged_user_cant_list_jurisdiction(self): - """Not logged-in user can't read city - """ - # Request list - url = reverse(self.endpoint+'list') - response = self.client.get(url) - - # Assert access is forbidden - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - - def test_logged_user_can_list_jurisdiction(self): - """Regular logged-in user can list city - """ - # Create instances - user = TenantUserFactory() - instances = [self.factory() for n in range(random.randint(1,5))] - - # Authenticate user - user.db = 'default' - self.client.force_authenticate(user=user) - - # Request list - url = reverse(self.endpoint+'list') - response = self.client.get(url) - - # Assert access is allowed - self.assertEqual(response.status_code, status.HTTP_200_OK) - - # Assert all instances are returned - self.assertEqual(len(instances), len(response.data['results'])) - - def test_logged_user_can_create_jurisdiction(self): - """Regular logged-in user can create new city - """ - # Define request data - data = { - 'name': 'jurisdiction name test data', - 'region': factories.RegionFactory().pk, - } - - # Authenticate user - user = TenantUserFactory() - user.db = 'default' - self.client.force_authenticate(user=user) - - # Query endpoint - url = reverse(self.endpoint+'list') - response = self.client.post(url, data=data) - - # Assert endpoint returns created status - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - - # Assert instance exists on db - self.assertTrue(self.model.objects.get(id=response.data['id'])) - - def test_logged_user_can_modify_existing_jurisdiction(self): - """Regular logged-in user can modify existing citycity - """ - # Create instances - instance = self.factory() - - # Define request data - data = { - 'name': 'jurisdiction name test MOD data', - 'region': factories.RegionFactory().pk, - } - - # Authenticate user - user = TenantUserFactory() - user.db = 'default' - self.client.force_authenticate(user=user) - - # Query endpoint - url = reverse(self.endpoint+'detail', args=[instance.pk]) - response = self.client.put(url, data, format='json') - - # Assert endpoint returns OK code - self.assertEqual(response.status_code, status.HTTP_200_OK) - - # Assert instance has been modified - for key in data: - self.assertEqual(data[key], response.data[key]) - - def test_logged_user_can_delete_existing_jurisdiction(self): - """Regular logged-in user can delete existing city - """ - # Create instances - instance = self.factory() - - # Authenticate user - user = TenantUserFactory() - user.db = 'default' - self.client.force_authenticate(user=user) - - # Query endpoint - url = reverse(self.endpoint+'detail', args=[instance.pk]) - response = self.client.delete(url) - - # Assert 204 no content - self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) - # Assert instance not exists anymore on db - self.assertFalse(self.model.objects.filter(id=instance.pk).exists()) - diff --git a/geo/views.py b/geo/views.py index 17037b4..ac6e94a 100644 --- a/geo/views.py +++ b/geo/views.py @@ -1,72 +1,42 @@ -from rest_framework.response import Response -from tenants.views import CustomViewSet, CustomExternalViewSet -from rest_framework import viewsets, status -from rest_framework.decorators import permission_classes -from legalq.permissions import GlobalAccess +from rest_framework import viewsets + +from back_latienda.permissions import IsCreator, ReadOnly from . import models from . import serializers -class CountryViewSet(CustomExternalViewSet): +class CountryViewSet(viewsets.ModelViewSet): model = models.Country - read_serializer_class = serializers.CountryReadSerializer - write_serializer_class = serializers.CountryWriteSerializer + serializer_class = serializers.CountrySerializer model_name = 'country' queryset = models.Country.objects.all() filterset_fields = ('name', ) - - def retrieve(self, request, *args, **kwargs): - instance = models.Country.objects.filter(pk=kwargs['pk']).first() - if instance is not None: - serializer = self.read_serializer_class(instance) - return Response(serializer.data) - return Response(status=status.HTTP_404_NOT_FOUND) - - permission_classes = [GlobalAccess] + permission_classes = [ReadOnly] -class RegionViewSet(viewsets.ReadOnlyModelViewSet): +class RegionViewSet(viewsets.ModelViewSet): model = models.Region - serializer_class = serializers.RegionReadSerializer - write_serializer_class = serializers.RegionWriteSerializer + serializer_class = serializers.RegionSerializer model_name = 'region' queryset = models.Region.objects.all() filterset_fields = ('name', 'country__name') - - permission_classes = [GlobalAccess] + permission_classes = [ReadOnly] -class ProvinceViewSet(CustomExternalViewSet): +class ProvinceViewSet(viewsets.ModelViewSet): model = models.Province - read_serializer_class = serializers.ProvinceReadSerializer + serializer_class = serializers.ProvinceSerializer model_name = 'region' queryset = models.Province.objects.all() filterset_fields = ('name', 'region__country__name') - - def retrieve(self, request, *args, **kwargs): - instance = models.Province.objects.filter(pk=kwargs['pk']).first() - if instance is not None: - serializer = self.read_serializer_class(instance) - return Response(serializer.data) - return Response(status=status.HTTP_404_NOT_FOUND) - - permission_classes = [GlobalAccess] + permission_classes = [ReadOnly] -class CityViewSet(CustomExternalViewSet): +class CityViewSet(viewsets.ModelViewSet): model = models.City - read_serializer_class = serializers.CityReadSerializer - write_serializer_class = serializers.CityWriteSerializer + serializer_class = serializers.CitySerializer model_name = 'city' queryset = models.City.objects.all() - - def retrieve(self, request, *args, **kwargs): - instance = models.City.objects.filter(pk=kwargs['pk']).first() - if instance is not None: - serializer = self.read_serializer_class(instance) - return Response(serializer.data) - return Response(status=status.HTTP_404_NOT_FOUND) - - permission_classes = [GlobalAccess] + permission_classes = [ReadOnly] filterset_fields = ('name', 'province__name', 'province__region__name')