Merge branch 'develop' into feature/gm-148
This commit is contained in:
commit
6c195bc185
|
|
@ -12,7 +12,7 @@ class RoleAdmin(admin.ModelAdmin):
|
|||
|
||||
@admin.register(models.UserRole)
|
||||
class UserRoleAdmin(admin.ModelAdmin):
|
||||
list_display = ['user', 'role']
|
||||
list_display = ['user', 'role', 'establishment']
|
||||
|
||||
|
||||
@admin.register(models.User)
|
||||
|
|
|
|||
14
apps/account/migrations/0011_merge_20191014_0839.py
Normal file
14
apps/account/migrations/0011_merge_20191014_0839.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Generated by Django 2.2.4 on 2019-10-14 08:39
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('account', '0009_auto_20191011_1123'),
|
||||
('account', '0010_user_password_confirmed'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
]
|
||||
14
apps/account/migrations/0012_merge_20191015_0708.py
Normal file
14
apps/account/migrations/0012_merge_20191015_0708.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Generated by Django 2.2.4 on 2019-10-15 07:08
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('account', '0011_merge_20191014_0839'),
|
||||
('account', '0011_merge_20191014_1258'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
]
|
||||
30
apps/account/migrations/0013_auto_20191016_0810.py
Normal file
30
apps/account/migrations/0013_auto_20191016_0810.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Generated by Django 2.2.4 on 2019-10-16 08:10
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('establishment', '0033_auto_20191003_0943_squashed_0034_auto_20191003_1036'),
|
||||
('account', '0012_merge_20191015_0708'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='userrole',
|
||||
name='establishment',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='establishment.Establishment', verbose_name='Establishment'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='role',
|
||||
name='country',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='location.Country', verbose_name='Country'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='role',
|
||||
name='role',
|
||||
field=models.PositiveIntegerField(choices=[(1, 'Standard user'), (2, 'Comments moderator'), (3, 'Country admin'), (4, 'Content page manager'), (5, 'Establishment manager')], verbose_name='Role'),
|
||||
),
|
||||
]
|
||||
|
|
@ -13,6 +13,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 location.models import Country
|
||||
from utils.models import GMTokenGenerator
|
||||
from utils.models import ImageMixin, ProjectBaseMixin, PlatformMixin
|
||||
|
|
@ -23,14 +24,25 @@ class Role(ProjectBaseMixin):
|
|||
"""Base Role model."""
|
||||
STANDARD_USER = 1
|
||||
COMMENTS_MODERATOR = 2
|
||||
COUNTRY_ADMIN = 3
|
||||
CONTENT_PAGE_MANAGER = 4
|
||||
ESTABLISHMENT_MANAGER = 5
|
||||
REVIEWER_MANGER = 6
|
||||
RESTAURANT_REVIEWER = 7
|
||||
|
||||
ROLE_CHOICES =(
|
||||
ROLE_CHOICES = (
|
||||
(STANDARD_USER, 'Standard user'),
|
||||
(COMMENTS_MODERATOR, 'Comments moderator'),
|
||||
(COUNTRY_ADMIN, 'Country admin'),
|
||||
(CONTENT_PAGE_MANAGER, 'Content page manager'),
|
||||
(ESTABLISHMENT_MANAGER, 'Establishment manager'),
|
||||
(REVIEWER_MANGER, 'Reviewer manager'),
|
||||
(RESTAURANT_REVIEWER, 'Restaurant reviewer')
|
||||
)
|
||||
role = models.PositiveIntegerField(verbose_name=_('Role'), choices=ROLE_CHOICES,
|
||||
null=False, blank=False)
|
||||
country = models.ForeignKey(Country, verbose_name=_('Country'), on_delete=models.CASCADE)
|
||||
country = models.ForeignKey(Country, verbose_name=_('Country'),
|
||||
null=True, blank=True, on_delete=models.SET_NULL)
|
||||
# is_list = models.BooleanField(verbose_name=_('list'), default=True, null=False)
|
||||
# is_create = models.BooleanField(verbose_name=_('create'), default=False, null=False)
|
||||
# is_update = models.BooleanField(verbose_name=_('update'), default=False, null=False)
|
||||
|
|
@ -224,4 +236,6 @@ class User(AbstractUser):
|
|||
class UserRole(ProjectBaseMixin):
|
||||
"""UserRole model."""
|
||||
user = models.ForeignKey(User, verbose_name=_('User'), on_delete=models.CASCADE)
|
||||
role = models.ForeignKey(Role, verbose_name=_('Role'), on_delete=models.SET_NULL, null=True)
|
||||
role = models.ForeignKey(Role, verbose_name=_('Role'), on_delete=models.SET_NULL, null=True)
|
||||
establishment = models.ForeignKey(Establishment, verbose_name=_('Establishment'),
|
||||
on_delete=models.SET_NULL, null=True, blank=True)
|
||||
|
|
@ -40,12 +40,13 @@ class CollectionDetailTests(BaseTestCase):
|
|||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
country = Country.objects.first()
|
||||
if not country:
|
||||
country = Country.objects.create(
|
||||
name=json.dumps({"en-GB": "Test country"}),
|
||||
code="en"
|
||||
)
|
||||
# country = Country.objects.first()
|
||||
# if not country:
|
||||
country = Country.objects.create(
|
||||
name=json.dumps({"en-GB": "Test country"}),
|
||||
code="en"
|
||||
)
|
||||
country.save()
|
||||
|
||||
self.collection = Collection.objects.create(
|
||||
name='Test collection',
|
||||
|
|
@ -56,6 +57,8 @@ class CollectionDetailTests(BaseTestCase):
|
|||
slug='test-collection-slug',
|
||||
)
|
||||
|
||||
self.collection.save()
|
||||
|
||||
def test_collection_detail_Read(self):
|
||||
response = self.client.get(f'/api/web/collections/{self.collection.slug}/establishments/?country_code=en',
|
||||
format='json')
|
||||
|
|
@ -66,7 +69,7 @@ class CollectionGuideTests(CollectionDetailTests):
|
|||
|
||||
def test_guide_list_Read(self):
|
||||
response = self.client.get('/api/web/collections/guides/', format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||
|
||||
|
||||
class CollectionGuideDetailTests(CollectionDetailTests):
|
||||
|
|
@ -78,6 +81,7 @@ class CollectionGuideDetailTests(CollectionDetailTests):
|
|||
start=datetime.now(pytz.utc),
|
||||
end=datetime.now(pytz.utc)
|
||||
)
|
||||
self.guide.save()
|
||||
|
||||
def test_guide_detail_Read(self):
|
||||
response = self.client.get(f'/api/web/collections/guides/{self.guide.id}/', format='json')
|
||||
|
|
|
|||
24
apps/comment/migrations/0003_auto_20191015_0704.py
Normal file
24
apps/comment/migrations/0003_auto_20191015_0704.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 2.2.4 on 2019-10-15 07:04
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('location', '0012_data_migrate'),
|
||||
('comment', '0002_comment_language'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='comment',
|
||||
name='language',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='comment',
|
||||
name='country',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='location.Country', verbose_name='Country'),
|
||||
),
|
||||
]
|
||||
|
|
@ -7,6 +7,8 @@ from account.models import User
|
|||
from utils.models import ProjectBaseMixin
|
||||
from utils.querysets import ContentTypeQuerySetMixin
|
||||
from translation.models import Language
|
||||
from location.models import Country
|
||||
|
||||
|
||||
class CommentQuerySet(ContentTypeQuerySetMixin):
|
||||
"""QuerySets for Comment model."""
|
||||
|
|
@ -41,7 +43,8 @@ class Comment(ProjectBaseMixin):
|
|||
content_object = generic.GenericForeignKey('content_type', 'object_id')
|
||||
|
||||
objects = CommentQuerySet.as_manager()
|
||||
language = models.ForeignKey(Language, verbose_name=_('Locale'), on_delete=models.SET_NULL, null=True)
|
||||
country = models.ForeignKey(Country, verbose_name=_('Country'),
|
||||
on_delete=models.SET_NULL, null=True)
|
||||
|
||||
class Meta:
|
||||
"""Meta class"""
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
from rest_framework import permissions
|
||||
from account.models import UserRole, Role, User
|
||||
|
||||
|
||||
class IsCommentModerator(permissions.IsAuthenticatedOrReadOnly):
|
||||
"""
|
||||
Object-level permission to only allow owners of an object to edit it.
|
||||
Assumes the model instance has an `owner` attribute.
|
||||
"""
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
# Read permissions are allowed to any request,
|
||||
# so we'll always allow GET, HEAD or OPTIONS requests.
|
||||
if request.method in permissions.SAFE_METHODS or \
|
||||
obj.user == request.user or request.user.is_superuser:
|
||||
return True
|
||||
|
||||
# Must have role
|
||||
role = Role.objects.filter(role=Role.COMMENTS_MODERATOR,
|
||||
country__languages__id=obj.language_id)\
|
||||
.first() # 'Comments moderator'
|
||||
|
||||
is_access = UserRole.objects.filter(user=request.user, role=role).exists()
|
||||
if obj.user != request.user and is_access:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
|
@ -1,32 +1,16 @@
|
|||
from rest_framework.test import APITestCase
|
||||
from utils.tests.tests_permissions import BasePermissionTests
|
||||
from rest_framework import status
|
||||
from authorization.tests.tests_authorization import get_tokens_for_user
|
||||
from django.urls import reverse
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from http.cookies import SimpleCookie
|
||||
from location.models import Country
|
||||
from account.models import Role, User, UserRole
|
||||
from comment.models import Comment
|
||||
from translation.models import Language
|
||||
|
||||
|
||||
class CommentModeratorPermissionTests(APITestCase):
|
||||
class CommentModeratorPermissionTests(BasePermissionTests):
|
||||
def setUp(self):
|
||||
|
||||
self.lang = Language.objects.create(
|
||||
title='Russia',
|
||||
locale='ru-RU'
|
||||
)
|
||||
self.lang.save()
|
||||
|
||||
self.country_ru = Country.objects.create(
|
||||
name='{"ru-RU":"Russia"}',
|
||||
code='23',
|
||||
low_price=15,
|
||||
high_price=150000,
|
||||
)
|
||||
self.country_ru.languages.add(self.lang)
|
||||
self.country_ru.save()
|
||||
super().setUp()
|
||||
|
||||
self.role = Role.objects.create(
|
||||
role=2,
|
||||
|
|
@ -51,14 +35,11 @@ class CommentModeratorPermissionTests(APITestCase):
|
|||
user=self.user_test["user"],
|
||||
object_id= self.country_ru.pk,
|
||||
content_type_id=content_type.id,
|
||||
language=self.lang
|
||||
country=self.country_ru
|
||||
)
|
||||
self.comment.save()
|
||||
self.url = reverse('back:comment:comment-crud', kwargs={"id": self.comment.id})
|
||||
|
||||
def test_get(self):
|
||||
response = self.client.get(self.url, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
def test_put_moderator(self):
|
||||
tokens = User.create_jwt_tokens(self.moderator)
|
||||
|
|
@ -76,6 +57,10 @@ class CommentModeratorPermissionTests(APITestCase):
|
|||
response = self.client.put(self.url, data=data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
def test_get(self):
|
||||
response = self.client.get(self.url, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
def test_put_other_user(self):
|
||||
other_user = User.objects.create_user(username='test',
|
||||
email='test@mail.com',
|
||||
|
|
@ -120,4 +105,3 @@ class CommentModeratorPermissionTests(APITestCase):
|
|||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from rest_framework import generics, permissions
|
||||
from comment.serializers import back as serializers
|
||||
from comment import models
|
||||
from comment.permissions import IsCommentModerator
|
||||
from utils.permissions import IsCommentModerator, IsCountryAdmin
|
||||
|
||||
|
||||
class CommentLstView(generics.ListCreateAPIView):
|
||||
|
|
@ -15,5 +15,5 @@ class CommentRUDView(generics.RetrieveUpdateDestroyAPIView):
|
|||
"""Comment RUD view."""
|
||||
serializer_class = serializers.CommentBaseSerializer
|
||||
queryset = models.Comment.objects.all()
|
||||
permission_classes = [IsCommentModerator]
|
||||
permission_classes = [IsCountryAdmin|IsCommentModerator]
|
||||
lookup_field = 'id'
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class Migration(migrations.Migration):
|
|||
name='index_name',
|
||||
field=models.CharField(blank=True, db_index=True, max_length=50, null=True, unique=True, default=None, verbose_name='Index name'),
|
||||
),
|
||||
migrations.RunPython(fill_establishment_subtype),
|
||||
migrations.RunPython(fill_establishment_subtype, migrations.RunPython.noop),
|
||||
migrations.AlterField(
|
||||
model_name='establishmentsubtype',
|
||||
name='index_name',
|
||||
|
|
|
|||
|
|
@ -466,6 +466,20 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
|
|||
return Award.objects.filter(Q(establishment=self) | Q(employees__establishments=self)) \
|
||||
.latest(field_name='vintage_year')
|
||||
|
||||
@property
|
||||
def country_id(self):
|
||||
"""
|
||||
Return Country id of establishment location
|
||||
"""
|
||||
return self.address.country_id
|
||||
|
||||
@property
|
||||
def establishment_id(self):
|
||||
"""
|
||||
Return establishment id of establishment location
|
||||
"""
|
||||
return self.id
|
||||
|
||||
|
||||
class Position(BaseAttributes, TranslatedFieldsMixin):
|
||||
"""Position model."""
|
||||
|
|
@ -600,6 +614,10 @@ class Plate(TranslatedFieldsMixin, models.Model):
|
|||
menu = models.ForeignKey(
|
||||
'establishment.Menu', verbose_name=_('menu'), on_delete=models.CASCADE)
|
||||
|
||||
@property
|
||||
def establishment_id(self):
|
||||
return self.menu.establishment.id
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('plate')
|
||||
verbose_name_plural = _('plates')
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@ from main.models import Currency
|
|||
from establishment.models import Establishment, EstablishmentType, Menu
|
||||
# Create your tests here.
|
||||
from translation.models import Language
|
||||
from account.models import Role, UserRole
|
||||
from location.models import Country, Address, City, Region
|
||||
|
||||
|
||||
class BaseTestCase(APITestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.username = 'sedragurda'
|
||||
self.password = 'sedragurdaredips19'
|
||||
|
|
@ -27,11 +28,44 @@ class BaseTestCase(APITestCase):
|
|||
self.establishment_type = EstablishmentType.objects.create(name="Test establishment type")
|
||||
|
||||
# Create lang object
|
||||
Language.objects.create(
|
||||
title='English',
|
||||
locale='en-GB'
|
||||
self.lang = Language.objects.get(
|
||||
title='Russia',
|
||||
locale='ru-RU'
|
||||
)
|
||||
|
||||
self.country_ru = Country.objects.get(
|
||||
name={"en-GB": "Russian"}
|
||||
)
|
||||
|
||||
self.region = Region.objects.create(name='Moscow area', code='01',
|
||||
country=self.country_ru)
|
||||
self.region.save()
|
||||
|
||||
self.city = City.objects.create(name='Mosocow', code='01',
|
||||
region=self.region, country=self.country_ru)
|
||||
self.city.save()
|
||||
|
||||
self.address = Address.objects.create(city=self.city, street_name_1='Krasnaya',
|
||||
number=2, postal_code='010100')
|
||||
self.address.save()
|
||||
|
||||
self.role = Role.objects.create(role=Role.ESTABLISHMENT_MANAGER)
|
||||
self.role.save()
|
||||
|
||||
self.establishment = Establishment.objects.create(
|
||||
name="Test establishment",
|
||||
establishment_type_id=self.establishment_type.id,
|
||||
is_publish=True,
|
||||
slug="test",
|
||||
address=self.address
|
||||
)
|
||||
|
||||
self.establishment.save()
|
||||
|
||||
self.user_role = UserRole.objects.create(user=self.user, role=self.role,
|
||||
establishment=self.establishment)
|
||||
self.user_role.save()
|
||||
|
||||
|
||||
class EstablishmentBTests(BaseTestCase):
|
||||
def test_establishment_CRUD(self):
|
||||
|
|
@ -43,25 +77,25 @@ class EstablishmentBTests(BaseTestCase):
|
|||
'name': 'Test establishment',
|
||||
'type_id': self.establishment_type.id,
|
||||
'is_publish': True,
|
||||
'slug': 'test-establishment-slug',
|
||||
'slug': 'test-establishment-slug'
|
||||
}
|
||||
|
||||
response = self.client.post('/api/back/establishments/', data=data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||
|
||||
establishment = response.json()
|
||||
|
||||
response = self.client.get(f'/api/back/establishments/{establishment["id"]}/', format='json')
|
||||
response = self.client.get(f'/api/back/establishments/{self.establishment.id}/', format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
update_data = {
|
||||
'name': 'Test new establishment'
|
||||
}
|
||||
|
||||
response = self.client.patch(f'/api/back/establishments/{establishment["id"]}/', data=update_data)
|
||||
response = self.client.patch(f'/api/back/establishments/{self.establishment.id}/',
|
||||
data=update_data)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
response = self.client.delete(f'/api/back/establishments/{establishment["id"]}/', format='json')
|
||||
response = self.client.delete(f'/api/back/establishments/{self.establishment.id}/',
|
||||
format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
||||
|
|
@ -96,39 +130,45 @@ class EmployeeTests(BaseTestCase):
|
|||
class ChildTestCase(BaseTestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.establishment = Establishment.objects.create(
|
||||
name="Test establishment",
|
||||
establishment_type_id=self.establishment_type.id,
|
||||
is_publish=True,
|
||||
slug="test"
|
||||
)
|
||||
|
||||
|
||||
# Test childs
|
||||
class EmailTests(ChildTestCase):
|
||||
def test_email_CRUD(self):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
def test_get(self):
|
||||
response = self.client.get('/api/back/establishments/emails/', format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
def test_post(self):
|
||||
data = {
|
||||
'email': "test@test.com",
|
||||
'establishment': self.establishment.id
|
||||
}
|
||||
|
||||
response = self.client.post('/api/back/establishments/emails/', data=data)
|
||||
self.id_email = response.json()['id']
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||
|
||||
response = self.client.get('/api/back/establishments/emails/1/', format='json')
|
||||
def test_get_by_pk(self):
|
||||
self.test_post()
|
||||
response = self.client.get(f'/api/back/establishments/emails/{self.id_email}/', format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
def test_patch(self):
|
||||
self.test_post()
|
||||
|
||||
update_data = {
|
||||
'email': 'testnew@test.com'
|
||||
}
|
||||
|
||||
response = self.client.patch('/api/back/establishments/emails/1/', data=update_data)
|
||||
response = self.client.patch(f'/api/back/establishments/emails/{self.id_email}/',
|
||||
data=update_data)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
response = self.client.delete('/api/back/establishments/emails/1/')
|
||||
def test_email_CRUD(self):
|
||||
self.test_post()
|
||||
response = self.client.delete(f'/api/back/establishments/emails/{self.id_email}/')
|
||||
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
||||
|
|
@ -285,7 +325,7 @@ class EstablishmentWebTagTests(BaseTestCase):
|
|||
|
||||
def test_tag_Read(self):
|
||||
response = self.client.get('/api/web/establishments/tags/', format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||
|
||||
|
||||
class EstablishmentWebSlugTests(ChildTestCase):
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
from django.shortcuts import get_object_or_404
|
||||
from rest_framework import generics
|
||||
|
||||
from utils.permissions import IsCountryAdmin, IsEstablishmentManager
|
||||
from establishment import models, serializers
|
||||
from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer
|
||||
|
||||
|
|
@ -18,11 +19,13 @@ class EstablishmentListCreateView(EstablishmentMixinViews, generics.ListCreateAP
|
|||
"""Establishment list/create view."""
|
||||
queryset = models.Establishment.objects.all()
|
||||
serializer_class = serializers.EstablishmentListCreateSerializer
|
||||
permission_classes = [IsCountryAdmin|IsEstablishmentManager]
|
||||
|
||||
|
||||
class EstablishmentRUDView(generics.RetrieveUpdateDestroyAPIView):
|
||||
queryset = models.Establishment.objects.all()
|
||||
serializer_class = serializers.EstablishmentRUDSerializer
|
||||
permission_classes = [IsCountryAdmin|IsEstablishmentManager]
|
||||
|
||||
|
||||
class EstablishmentScheduleRUDView(generics.RetrieveUpdateDestroyAPIView):
|
||||
|
|
@ -57,12 +60,14 @@ class MenuListCreateView(generics.ListCreateAPIView):
|
|||
"""Menu list create view."""
|
||||
serializer_class = serializers.MenuSerializers
|
||||
queryset = models.Menu.objects.all()
|
||||
permission_classes = [IsEstablishmentManager]
|
||||
|
||||
|
||||
class MenuRUDView(generics.RetrieveUpdateDestroyAPIView):
|
||||
"""Menu RUD view."""
|
||||
serializer_class = serializers.MenuRUDSerializers
|
||||
queryset = models.Menu.objects.all()
|
||||
permission_classes = [IsEstablishmentManager]
|
||||
|
||||
|
||||
class SocialListCreateView(generics.ListCreateAPIView):
|
||||
|
|
@ -70,12 +75,14 @@ class SocialListCreateView(generics.ListCreateAPIView):
|
|||
serializer_class = serializers.SocialNetworkSerializers
|
||||
queryset = models.SocialNetwork.objects.all()
|
||||
pagination_class = None
|
||||
permission_classes = [IsEstablishmentManager]
|
||||
|
||||
|
||||
class SocialRUDView(generics.RetrieveUpdateDestroyAPIView):
|
||||
"""Social RUD view."""
|
||||
serializer_class = serializers.SocialNetworkSerializers
|
||||
queryset = models.SocialNetwork.objects.all()
|
||||
permission_classes = [IsEstablishmentManager]
|
||||
|
||||
|
||||
class PlateListCreateView(generics.ListCreateAPIView):
|
||||
|
|
@ -83,12 +90,14 @@ class PlateListCreateView(generics.ListCreateAPIView):
|
|||
serializer_class = serializers.PlatesSerializers
|
||||
queryset = models.Plate.objects.all()
|
||||
pagination_class = None
|
||||
permission_classes = [IsEstablishmentManager]
|
||||
|
||||
|
||||
class PlateRUDView(generics.RetrieveUpdateDestroyAPIView):
|
||||
"""Social RUD view."""
|
||||
serializer_class = serializers.PlatesSerializers
|
||||
queryset = models.Plate.objects.all()
|
||||
permission_classes = [IsEstablishmentManager]
|
||||
|
||||
|
||||
class PhonesListCreateView(generics.ListCreateAPIView):
|
||||
|
|
@ -96,12 +105,14 @@ class PhonesListCreateView(generics.ListCreateAPIView):
|
|||
serializer_class = serializers.ContactPhoneBackSerializers
|
||||
queryset = models.ContactPhone.objects.all()
|
||||
pagination_class = None
|
||||
permission_classes = [IsEstablishmentManager]
|
||||
|
||||
|
||||
class PhonesRUDView(generics.RetrieveUpdateDestroyAPIView):
|
||||
"""Social RUD view."""
|
||||
serializer_class = serializers.ContactPhoneBackSerializers
|
||||
queryset = models.ContactPhone.objects.all()
|
||||
permission_classes = [IsEstablishmentManager]
|
||||
|
||||
|
||||
class EmailListCreateView(generics.ListCreateAPIView):
|
||||
|
|
@ -109,12 +120,14 @@ class EmailListCreateView(generics.ListCreateAPIView):
|
|||
serializer_class = serializers.ContactEmailBackSerializers
|
||||
queryset = models.ContactEmail.objects.all()
|
||||
pagination_class = None
|
||||
permission_classes = [IsEstablishmentManager]
|
||||
|
||||
|
||||
class EmailRUDView(generics.RetrieveUpdateDestroyAPIView):
|
||||
"""Social RUD view."""
|
||||
serializer_class = serializers.ContactEmailBackSerializers
|
||||
queryset = models.ContactEmail.objects.all()
|
||||
permission_classes = [IsEstablishmentManager]
|
||||
|
||||
|
||||
class EmployeeListCreateView(generics.ListCreateAPIView):
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ from establishment import models, serializers
|
|||
from main import methods
|
||||
from main.models import MetaDataContent
|
||||
from utils.pagination import EstablishmentPortionPagination
|
||||
|
||||
from utils.permissions import IsCountryAdmin
|
||||
|
||||
class EstablishmentMixinView:
|
||||
"""Establishment mixin."""
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import os
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
# Check migration
|
||||
def load_data_from_sql(apps, schema_editor):
|
||||
file_path = os.path.join(os.path.dirname(__file__), 'migrate_lang.sql')
|
||||
sql_statement = open(file_path).read()
|
||||
|
|
|
|||
|
|
@ -87,7 +87,6 @@ INSERT INTO codelang (code,country) VALUES
|
|||
,('es-CR','Spanish (Costa Rica)')
|
||||
,('es-DO','Spanish (Dominican Republic)')
|
||||
,('es-EC','Spanish (Ecuador)')
|
||||
,('es-ES','Spanish (Castilian)')
|
||||
,('es-ES','Spanish (Spain)')
|
||||
;
|
||||
INSERT INTO codelang (code,country) VALUES
|
||||
|
|
@ -326,7 +325,7 @@ commit;
|
|||
|
||||
INSERT INTO location_country
|
||||
(code, "name", low_price, high_price, created, modified)
|
||||
select
|
||||
select distinct
|
||||
lpad((row_number() over (order by t.country asc))::text, 3, '0') as code,
|
||||
jsonb_build_object('en-GB', t.country),
|
||||
0 as low_price,
|
||||
|
|
@ -335,7 +334,7 @@ select
|
|||
now() as modified
|
||||
from
|
||||
(
|
||||
select
|
||||
select
|
||||
distinct c.country
|
||||
from country_code c
|
||||
) t
|
||||
|
|
@ -348,6 +347,7 @@ commit;
|
|||
INSERT INTO translation_language
|
||||
(title, locale)
|
||||
select
|
||||
distinct
|
||||
t.country as title,
|
||||
t.code as locale
|
||||
from
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@ class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin):
|
|||
high_price = models.IntegerField(default=50, verbose_name=_('High price'))
|
||||
languages = models.ManyToManyField(Language, verbose_name=_('Languages'))
|
||||
|
||||
@property
|
||||
def country_id(self):
|
||||
return self.id
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
||||
|
|
@ -119,6 +123,10 @@ class Address(models.Model):
|
|||
return {'lat': self.latitude,
|
||||
'lon': self.longitude}
|
||||
|
||||
@property
|
||||
def country_id(self):
|
||||
return self.city.country_id
|
||||
|
||||
|
||||
# todo: Make recalculate price levels
|
||||
@receiver(post_save, sender=Country)
|
||||
|
|
|
|||
|
|
@ -5,11 +5,12 @@ from account.models import User
|
|||
from rest_framework import status
|
||||
from http.cookies import SimpleCookie
|
||||
|
||||
from location.models import City, Region, Country
|
||||
from location.models import City, Region, Country, Language
|
||||
from django.contrib.gis.geos import Point
|
||||
from account.models import Role, UserRole
|
||||
|
||||
|
||||
class BaseTestCase(APITestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.username = 'sedragurda'
|
||||
self.password = 'sedragurdaredips19'
|
||||
|
|
@ -20,27 +21,57 @@ class BaseTestCase(APITestCase):
|
|||
|
||||
# get tokens
|
||||
|
||||
# self.user.is_superuser = True
|
||||
# self.user.save()
|
||||
|
||||
tokkens = User.create_jwt_tokens(self.user)
|
||||
self.client.cookies = SimpleCookie(
|
||||
{'access_token': tokkens.get('access_token'),
|
||||
'refresh_token': tokkens.get('refresh_token')})
|
||||
|
||||
self.lang = Language.objects.get(
|
||||
title='Russia',
|
||||
locale='ru-RU'
|
||||
)
|
||||
|
||||
self.country_ru = Country.objects.get(
|
||||
name={"en-GB": "Russian"}
|
||||
)
|
||||
|
||||
self.role = Role.objects.create(role=Role.COUNTRY_ADMIN,
|
||||
country=self.country_ru)
|
||||
self.role.save()
|
||||
|
||||
self.user_role = UserRole.objects.create(user=self.user, role=self.role)
|
||||
|
||||
self.user_role.save()
|
||||
|
||||
|
||||
class CountryTests(BaseTestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
def test_country_CRUD(self):
|
||||
response = self.client.get('/api/back/location/countries/', format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
data = {
|
||||
'name': 'Test country',
|
||||
'code': 'test'
|
||||
'name': {"ru-RU": "NewCountry"},
|
||||
'code': 'test1'
|
||||
}
|
||||
|
||||
response = self.client.post('/api/back/location/countries/', data=data, format='json')
|
||||
response_data = response.json()
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||
|
||||
country = Country.objects.get(pk=response_data["id"])
|
||||
role = Role.objects.create(role=Role.COUNTRY_ADMIN, country=country)
|
||||
role.save()
|
||||
|
||||
user_role = UserRole.objects.create(user=self.user, role=role)
|
||||
|
||||
user_role.save()
|
||||
|
||||
response = self.client.get('/api/back/location/countries/', format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
response = self.client.get(f'/api/back/location/countries/{response_data["id"]}/', format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
|
|
@ -64,6 +95,14 @@ class RegionTests(BaseTestCase):
|
|||
code="test"
|
||||
)
|
||||
|
||||
role = Role.objects.create(role=Role.COUNTRY_ADMIN, country=self.country)
|
||||
role.save()
|
||||
|
||||
user_role = UserRole.objects.create(user=self.user, role=role)
|
||||
|
||||
user_role.save()
|
||||
|
||||
|
||||
def test_region_CRUD(self):
|
||||
response = self.client.get('/api/back/location/regions/', format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
|
@ -108,6 +147,13 @@ class CityTests(BaseTestCase):
|
|||
country=self.country
|
||||
)
|
||||
|
||||
role = Role.objects.create(role=Role.COUNTRY_ADMIN, country=self.country)
|
||||
role.save()
|
||||
|
||||
user_role = UserRole.objects.create(user=self.user, role=role)
|
||||
|
||||
user_role.save()
|
||||
|
||||
def test_city_CRUD(self):
|
||||
response = self.client.get('/api/back/location/cities/', format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
|
@ -142,6 +188,7 @@ class AddressTests(BaseTestCase):
|
|||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
|
||||
self.country = Country.objects.create(
|
||||
name=json.dumps({"en-GB": "Test country"}),
|
||||
code="test"
|
||||
|
|
@ -160,6 +207,13 @@ class AddressTests(BaseTestCase):
|
|||
country=self.country
|
||||
)
|
||||
|
||||
role = Role.objects.create(role=Role.COUNTRY_ADMIN, country=self.country)
|
||||
role.save()
|
||||
|
||||
user_role = UserRole.objects.create(user=self.user, role=role)
|
||||
|
||||
user_role.save()
|
||||
|
||||
def test_address_CRUD(self):
|
||||
response = self.client.get('/api/back/location/addresses/', format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
|
@ -167,10 +221,8 @@ class AddressTests(BaseTestCase):
|
|||
data = {
|
||||
'city_id': self.city.id,
|
||||
'number': '+79999999',
|
||||
"coordinates": {
|
||||
"latitude": 37.0625,
|
||||
"longitude": -95.677068
|
||||
},
|
||||
"latitude": 37.0625,
|
||||
"longitude": -95.677068,
|
||||
"geo_lon": -95.677068,
|
||||
"geo_lat": 37.0625
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,50 +3,57 @@ from rest_framework import generics
|
|||
|
||||
from location import models, serializers
|
||||
from location.views import common
|
||||
|
||||
from utils.permissions import IsCountryAdmin
|
||||
|
||||
# Address
|
||||
class AddressListCreateView(common.AddressViewMixin, generics.ListCreateAPIView):
|
||||
"""Create view for model Address."""
|
||||
serializer_class = serializers.AddressDetailSerializer
|
||||
queryset = models.Address.objects.all()
|
||||
permission_classes = [IsCountryAdmin]
|
||||
|
||||
|
||||
class AddressRUDView(common.AddressViewMixin, generics.RetrieveUpdateDestroyAPIView):
|
||||
"""RUD view for model Address."""
|
||||
serializer_class = serializers.AddressDetailSerializer
|
||||
queryset = models.Address.objects.all()
|
||||
permission_classes = [IsCountryAdmin]
|
||||
|
||||
|
||||
# City
|
||||
class CityListCreateView(common.CityViewMixin, generics.ListCreateAPIView):
|
||||
"""Create view for model City."""
|
||||
serializer_class = serializers.CitySerializer
|
||||
|
||||
permission_classes = [IsCountryAdmin]
|
||||
|
||||
class CityRUDView(common.CityViewMixin, generics.RetrieveUpdateDestroyAPIView):
|
||||
"""RUD view for model City."""
|
||||
serializer_class = serializers.CitySerializer
|
||||
permission_classes = [IsCountryAdmin]
|
||||
|
||||
|
||||
# Region
|
||||
class RegionListCreateView(common.RegionViewMixin, generics.ListCreateAPIView):
|
||||
"""Create view for model Region"""
|
||||
serializer_class = serializers.RegionSerializer
|
||||
|
||||
permission_classes = [IsCountryAdmin]
|
||||
|
||||
class RegionRUDView(common.RegionViewMixin, generics.RetrieveUpdateDestroyAPIView):
|
||||
"""Retrieve view for model Region"""
|
||||
serializer_class = serializers.RegionSerializer
|
||||
permission_classes = [IsCountryAdmin]
|
||||
|
||||
|
||||
# Country
|
||||
class CountryListCreateView(common.CountryViewMixin, generics.ListCreateAPIView):
|
||||
class CountryListCreateView(generics.ListCreateAPIView):
|
||||
"""List/Create view for model Country."""
|
||||
queryset = models.Country.objects.all()
|
||||
serializer_class = serializers.CountryBackSerializer
|
||||
pagination_class = None
|
||||
permission_classes = [IsCountryAdmin]
|
||||
|
||||
|
||||
class CountryRUDView(common.CountryViewMixin, generics.RetrieveUpdateDestroyAPIView):
|
||||
class CountryRUDView(generics.RetrieveUpdateDestroyAPIView):
|
||||
"""RUD view for model Country."""
|
||||
serializer_class = serializers.CountryBackSerializer
|
||||
permission_classes = [IsCountryAdmin]
|
||||
queryset = models.Country.objects.all()
|
||||
57
apps/news/migrations/0022_auto_20191021_1306.py
Normal file
57
apps/news/migrations/0022_auto_20191021_1306.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# Generated by Django 2.2.4 on 2019-10-21 13:06
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
import utils.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('location', '0012_data_migrate'),
|
||||
('news', '0021_auto_20191009_1408'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='NewsBanner',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date created')),
|
||||
('modified', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
|
||||
('title', utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='title')),
|
||||
('image_url', models.URLField(blank=True, default=None, null=True, verbose_name='Image URL path')),
|
||||
('content_url', models.URLField(blank=True, default=None, null=True, verbose_name='Content URL path')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=(models.Model, utils.models.TranslatedFieldsMixin),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Agenda',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date created')),
|
||||
('modified', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
|
||||
('event_datetime', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Event datetime')),
|
||||
('content', utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='content')),
|
||||
('address', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, to='location.Address', verbose_name='address')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=(models.Model, utils.models.TranslatedFieldsMixin),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='news',
|
||||
name='agenda',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='news.Agenda', verbose_name='agenda'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='news',
|
||||
name='banner',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='news.NewsBanner', verbose_name='banner'),
|
||||
),
|
||||
]
|
||||
|
|
@ -4,7 +4,7 @@ from django.contrib.contenttypes import fields as generic
|
|||
from django.utils import timezone
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework.reverse import reverse
|
||||
from utils.models import BaseAttributes, TJSONField, TranslatedFieldsMixin
|
||||
from utils.models import BaseAttributes, TJSONField, TranslatedFieldsMixin, ProjectBaseMixin
|
||||
from rating.models import Rating
|
||||
|
||||
|
||||
|
|
@ -38,7 +38,7 @@ class NewsQuerySet(models.QuerySet):
|
|||
|
||||
def with_extended_related(self):
|
||||
"""Return qs with related objects."""
|
||||
return self.select_related('created_by')
|
||||
return self.select_related('created_by', 'agenda', 'banner')
|
||||
|
||||
def by_type(self, news_type):
|
||||
"""Filter News by type"""
|
||||
|
|
@ -61,15 +61,39 @@ class NewsQuerySet(models.QuerySet):
|
|||
# todo: filter by best score
|
||||
# todo: filter by country?
|
||||
def should_read(self, news):
|
||||
return self.model.objects.exclude(pk=news.pk).published().\
|
||||
return self.model.objects.exclude(pk=news.pk).published(). \
|
||||
with_base_related().by_type(news.news_type).distinct().order_by('?')
|
||||
|
||||
def same_theme(self, news):
|
||||
return self.model.objects.exclude(pk=news.pk).published().\
|
||||
with_base_related().by_type(news.news_type).\
|
||||
return self.model.objects.exclude(pk=news.pk).published(). \
|
||||
with_base_related().by_type(news.news_type). \
|
||||
by_tags(news.tags.all()).distinct().order_by('-start')
|
||||
|
||||
|
||||
class Agenda(ProjectBaseMixin, TranslatedFieldsMixin):
|
||||
"""News agenda model"""
|
||||
|
||||
event_datetime = models.DateTimeField(default=timezone.now, editable=False,
|
||||
verbose_name=_('Event datetime'))
|
||||
address = models.ForeignKey('location.Address', blank=True, null=True,
|
||||
default=None, verbose_name=_('address'),
|
||||
on_delete=models.SET_NULL)
|
||||
content = TJSONField(blank=True, null=True, default=None,
|
||||
verbose_name=_('content'),
|
||||
help_text='{"en-GB":"some text"}')
|
||||
|
||||
|
||||
class NewsBanner(ProjectBaseMixin, TranslatedFieldsMixin):
|
||||
"""News banner model"""
|
||||
title = TJSONField(blank=True, null=True, default=None,
|
||||
verbose_name=_('title'),
|
||||
help_text='{"en-GB":"some text"}')
|
||||
image_url = models.URLField(verbose_name=_('Image URL path'),
|
||||
blank=True, null=True, default=None)
|
||||
content_url = models.URLField(verbose_name=_('Content URL path'),
|
||||
blank=True, null=True, default=None)
|
||||
|
||||
|
||||
class News(BaseAttributes, TranslatedFieldsMixin):
|
||||
"""News model."""
|
||||
|
||||
|
|
@ -140,6 +164,14 @@ class News(BaseAttributes, TranslatedFieldsMixin):
|
|||
gallery = models.ManyToManyField('gallery.Image', through='news.NewsGallery')
|
||||
ratings = generic.GenericRelation(Rating)
|
||||
|
||||
agenda = models.ForeignKey('news.Agenda', blank=True, null=True,
|
||||
on_delete=models.SET_NULL,
|
||||
verbose_name=_('agenda'))
|
||||
|
||||
banner = models.ForeignKey('news.NewsBanner', blank=True, null=True,
|
||||
on_delete=models.SET_NULL,
|
||||
verbose_name=_('banner'))
|
||||
|
||||
objects = NewsQuerySet.as_manager()
|
||||
|
||||
class Meta:
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ from rest_framework import serializers
|
|||
from account.serializers.common import UserBaseSerializer
|
||||
from gallery.models import Image
|
||||
from location import models as location_models
|
||||
from location.serializers import CountrySimpleSerializer
|
||||
from location.serializers import CountrySimpleSerializer, AddressBaseSerializer
|
||||
from news import models
|
||||
from tag.serializers import TagBaseSerializer
|
||||
from utils.serializers import TranslatedField, ProjectModelSerializer
|
||||
|
|
@ -13,6 +13,7 @@ from utils.serializers import TranslatedField, ProjectModelSerializer
|
|||
|
||||
class CropImageSerializer(serializers.Serializer):
|
||||
"""Serializer for crop images for News object."""
|
||||
|
||||
preview_url = serializers.SerializerMethodField()
|
||||
promo_horizontal_web_url = serializers.SerializerMethodField()
|
||||
promo_horizontal_mobile_url = serializers.SerializerMethodField()
|
||||
|
|
@ -81,6 +82,40 @@ class NewsImageSerializer(serializers.ModelSerializer):
|
|||
}
|
||||
|
||||
|
||||
class AgendaSerializer(ProjectModelSerializer):
|
||||
event_datetime = serializers.DateTimeField()
|
||||
address = AddressBaseSerializer()
|
||||
content_translated = TranslatedField()
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
||||
model = models.Agenda
|
||||
fields = (
|
||||
'id',
|
||||
'event_datetime',
|
||||
'address',
|
||||
'content_translated'
|
||||
)
|
||||
|
||||
|
||||
class NewsBannerSerializer(ProjectModelSerializer):
|
||||
title_translated = TranslatedField()
|
||||
image_url = serializers.URLField()
|
||||
content_url = serializers.URLField()
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
||||
model = models.NewsBanner
|
||||
fields = (
|
||||
'id',
|
||||
'title_translated',
|
||||
'image_url',
|
||||
'content_url'
|
||||
)
|
||||
|
||||
|
||||
class NewsTypeSerializer(serializers.ModelSerializer):
|
||||
"""News type serializer."""
|
||||
|
||||
|
|
@ -95,7 +130,7 @@ class NewsBaseSerializer(ProjectModelSerializer):
|
|||
"""Base serializer for News model."""
|
||||
|
||||
# read only fields
|
||||
title_translated = TranslatedField()
|
||||
title_translated = TranslatedField(source='title')
|
||||
subtitle_translated = TranslatedField()
|
||||
|
||||
# related fields
|
||||
|
|
@ -151,6 +186,8 @@ class NewsDetailWebSerializer(NewsDetailSerializer):
|
|||
|
||||
same_theme = NewsBaseSerializer(many=True, read_only=True)
|
||||
should_read = NewsBaseSerializer(many=True, read_only=True)
|
||||
agenda = AgendaSerializer()
|
||||
banner = NewsBannerSerializer()
|
||||
|
||||
class Meta(NewsDetailSerializer.Meta):
|
||||
"""Meta class."""
|
||||
|
|
@ -158,6 +195,8 @@ class NewsDetailWebSerializer(NewsDetailSerializer):
|
|||
fields = NewsDetailSerializer.Meta.fields + (
|
||||
'same_theme',
|
||||
'should_read',
|
||||
'agenda',
|
||||
'banner'
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -191,11 +230,11 @@ class NewsBackOfficeDetailSerializer(NewsBackOfficeBaseSerializer,
|
|||
|
||||
fields = NewsBackOfficeBaseSerializer.Meta.fields + \
|
||||
NewsDetailSerializer.Meta.fields + (
|
||||
'description',
|
||||
'news_type_id',
|
||||
'country_id',
|
||||
'template',
|
||||
'template_display',
|
||||
'description',
|
||||
'news_type_id',
|
||||
'country_id',
|
||||
'template',
|
||||
'template_display',
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
from django.urls import reverse
|
||||
from http.cookies import SimpleCookie
|
||||
|
||||
from rest_framework.test import APITestCase
|
||||
|
|
@ -5,8 +6,9 @@ from rest_framework import status
|
|||
from datetime import datetime, timedelta
|
||||
|
||||
from news.models import NewsType, News
|
||||
from account.models import User
|
||||
|
||||
from account.models import User, Role, UserRole
|
||||
from translation.models import Language
|
||||
from location.models import Country
|
||||
# Create your tests here.
|
||||
|
||||
|
||||
|
|
@ -22,23 +24,51 @@ class BaseTestCase(APITestCase):
|
|||
self.client.cookies = SimpleCookie({'access_token': tokkens.get('access_token'),
|
||||
'refresh_token': tokkens.get('refresh_token')})
|
||||
self.test_news_type = NewsType.objects.create(name="Test news type")
|
||||
self.test_news = News.objects.create(created_by=self.user, modified_by=self.user, title={"en-GB": "Test news"},
|
||||
news_type=self.test_news_type, description={"en-GB": "Description test news"},
|
||||
|
||||
self.lang = Language.objects.get(
|
||||
title='Russia',
|
||||
locale='ru-RU'
|
||||
)
|
||||
|
||||
self.country_ru = Country.objects.get(
|
||||
name={"en-GB": "Russian"}
|
||||
)
|
||||
|
||||
role = Role.objects.create(
|
||||
role=Role.CONTENT_PAGE_MANAGER,
|
||||
country=self.country_ru
|
||||
)
|
||||
role.save()
|
||||
|
||||
user_role = UserRole.objects.create(
|
||||
user=self.user,
|
||||
role=role
|
||||
)
|
||||
user_role.save()
|
||||
|
||||
self.test_news = News.objects.create(created_by=self.user, modified_by=self.user,
|
||||
title={"en-GB": "Test news"},
|
||||
news_type=self.test_news_type,
|
||||
description={"en-GB": "Description test news"},
|
||||
playlist=1, start=datetime.now() + timedelta(hours=-2),
|
||||
end=datetime.now() + timedelta(hours=2),
|
||||
state=News.PUBLISHED, slug='test-news-slug',)
|
||||
|
||||
state=News.PUBLISHED, slug='test-news-slug',
|
||||
country=self.country_ru)
|
||||
|
||||
class NewsTestCase(BaseTestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
def test_news_list(self):
|
||||
def test_web_news(self):
|
||||
response = self.client.get("/api/web/news/")
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
def test_news_web_detail(self):
|
||||
response = self.client.get(f"/api/web/news/slug/{self.test_news.slug}/")
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
response = self.client.get("/api/web/news/types/")
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
def test_news_back_detail(self):
|
||||
response = self.client.get(f"/api/back/news/{self.test_news.id}/")
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
|
@ -47,6 +77,18 @@ class NewsTestCase(BaseTestCase):
|
|||
response = self.client.get("/api/back/news/")
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
def test_news_type_list(self):
|
||||
response = self.client.get("/api/web/news/types/")
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
def test_news_back_detail_put(self):
|
||||
# retrieve-update-destroy
|
||||
url = reverse('back:news:retrieve-update-destroy', kwargs={'pk': self.test_news.id})
|
||||
data = {
|
||||
'id': self.test_news.id,
|
||||
'description': {"en-GB": "Description test news!"},
|
||||
'slug': self.test_news.slug,
|
||||
'start': self.test_news.start,
|
||||
'playlist': self.test_news.playlist,
|
||||
'news_type_id':self.test_news.news_type_id,
|
||||
'country_id': self.country_ru.id
|
||||
}
|
||||
|
||||
response = self.client.put(url, data=data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
|
@ -8,6 +8,7 @@ from rest_framework.response import Response
|
|||
from gallery.tasks import delete_image
|
||||
from news import filters, models, serializers
|
||||
from rating.tasks import add_rating
|
||||
from utils.permissions import IsCountryAdmin, IsContentPageManager
|
||||
|
||||
|
||||
class NewsMixinView:
|
||||
|
|
@ -65,6 +66,7 @@ class NewsBackOfficeLCView(NewsBackOfficeMixinView,
|
|||
|
||||
serializer_class = serializers.NewsBackOfficeBaseSerializer
|
||||
create_serializers_class = serializers.NewsBackOfficeDetailSerializer
|
||||
permission_classes = [IsCountryAdmin|IsContentPageManager]
|
||||
|
||||
def get_serializer_class(self):
|
||||
"""Override serializer class."""
|
||||
|
|
@ -140,6 +142,7 @@ class NewsBackOfficeRUDView(NewsBackOfficeMixinView,
|
|||
"""Resource for detailed information about news for back-office users."""
|
||||
|
||||
serializer_class = serializers.NewsBackOfficeDetailSerializer
|
||||
permission_classes = [IsCountryAdmin|IsContentPageManager]
|
||||
|
||||
def get(self, request, pk, *args, **kwargs):
|
||||
add_rating(remote_addr=request.META.get('REMOTE_ADDR'),
|
||||
|
|
|
|||
0
apps/products/views/back.py
Normal file
0
apps/products/views/back.py
Normal file
20
apps/review/migrations/0004_review_country.py
Normal file
20
apps/review/migrations/0004_review_country.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 2.2.4 on 2019-10-17 12:17
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('location', '0012_data_migrate'),
|
||||
('review', '0003_review_text'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='review',
|
||||
name='country',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='country', to='location.Country', verbose_name='Country'),
|
||||
),
|
||||
]
|
||||
|
|
@ -65,6 +65,9 @@ class Review(BaseAttributes, TranslatedFieldsMixin):
|
|||
validators=[MinValueValidator(1900),
|
||||
MaxValueValidator(2100)])
|
||||
|
||||
country = models.ForeignKey('location.Country', on_delete=models.CASCADE,
|
||||
related_name='country', verbose_name=_('Country'),
|
||||
null=True)
|
||||
objects = ReviewQuerySet.as_manager()
|
||||
|
||||
class Meta:
|
||||
|
|
|
|||
18
apps/review/serializers/back.py
Normal file
18
apps/review/serializers/back.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
"""Review app common serializers."""
|
||||
from review import models
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class ReviewBaseSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = models.Review
|
||||
fields = ('id',
|
||||
'reviewer',
|
||||
'text',
|
||||
'language',
|
||||
'status',
|
||||
'child',
|
||||
'published_at',
|
||||
'vintage',
|
||||
'country'
|
||||
)
|
||||
11
apps/review/urls/back.py
Normal file
11
apps/review/urls/back.py
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
"""Back review URLs"""
|
||||
from django.urls import path
|
||||
|
||||
from review.views import back as views
|
||||
|
||||
app_name = 'review'
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.ReviewLstView.as_view(), name='review-list-create'),
|
||||
path('<int:id>/', views.ReviewRUDView.as_view(), name='review-crud'),
|
||||
]
|
||||
19
apps/review/views/back.py
Normal file
19
apps/review/views/back.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
from rest_framework import generics, permissions
|
||||
from review.serializers import back as serializers
|
||||
from review import models
|
||||
from utils.permissions import IsReviewerManager, IsRestaurantReviewer
|
||||
|
||||
|
||||
class ReviewLstView(generics.ListCreateAPIView):
|
||||
"""Comment list create view."""
|
||||
serializer_class = serializers.ReviewBaseSerializer
|
||||
queryset = models.Review.objects.all()
|
||||
permission_classes = [permissions.IsAuthenticatedOrReadOnly,]
|
||||
|
||||
|
||||
class ReviewRUDView(generics.RetrieveUpdateDestroyAPIView):
|
||||
"""Comment RUD view."""
|
||||
serializer_class = serializers.ReviewBaseSerializer
|
||||
queryset = models.Review.objects.all()
|
||||
permission_classes = [IsReviewerManager|IsRestaurantReviewer]
|
||||
lookup_field = 'id'
|
||||
|
|
@ -29,16 +29,20 @@ def update_document(sender, **kwargs):
|
|||
registry.update(establishment)
|
||||
|
||||
if app_label == 'establishment':
|
||||
# todo: remove after migration
|
||||
from establishment import models as establishment_models
|
||||
if model_name == 'establishmenttype':
|
||||
establishments = Establishment.objects.filter(
|
||||
establishment_type=instance)
|
||||
for establishment in establishments:
|
||||
registry.update(establishment)
|
||||
if isinstance(instance, establishment_models.EstablishmentType):
|
||||
establishments = Establishment.objects.filter(
|
||||
establishment_type=instance)
|
||||
for establishment in establishments:
|
||||
registry.update(establishment)
|
||||
if model_name == 'establishmentsubtype':
|
||||
establishments = Establishment.objects.filter(
|
||||
establishment_subtypes=instance)
|
||||
for establishment in establishments:
|
||||
registry.update(establishment)
|
||||
if instance(instance, establishment_models.EstablishmentSubType):
|
||||
establishments = Establishment.objects.filter(
|
||||
establishment_subtypes=instance)
|
||||
for establishment in establishments:
|
||||
registry.update(establishment)
|
||||
|
||||
if app_label == 'tag':
|
||||
if model_name == 'tag':
|
||||
|
|
|
|||
22
apps/translation/migrations/0005_auto_20191021_1201.py
Normal file
22
apps/translation/migrations/0005_auto_20191021_1201.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# Generated by Django 2.2.4 on 2019-10-21 12:01
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('translation', '0004_auto_20191018_0832'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='language',
|
||||
name='locale',
|
||||
field=models.CharField(max_length=10, verbose_name='Locale identifier'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='language',
|
||||
unique_together={('title', 'locale')},
|
||||
),
|
||||
]
|
||||
|
|
@ -22,7 +22,7 @@ class Language(models.Model):
|
|||
|
||||
title = models.CharField(max_length=255,
|
||||
verbose_name=_('Language title'))
|
||||
locale = models.CharField(max_length=10, unique=True,
|
||||
locale = models.CharField(max_length=10,
|
||||
verbose_name=_('Locale identifier'))
|
||||
|
||||
objects = LanguageQuerySet.as_manager()
|
||||
|
|
@ -32,6 +32,7 @@ class Language(models.Model):
|
|||
|
||||
verbose_name = _('Language')
|
||||
verbose_name_plural = _('Languages')
|
||||
unique_together = ('title', 'locale')
|
||||
|
||||
def __str__(self):
|
||||
"""String method"""
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
"""Project custom permissions"""
|
||||
from rest_framework.permissions import BasePermission
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
from rest_framework import permissions
|
||||
from rest_framework_simplejwt.tokens import AccessToken
|
||||
|
||||
from account.models import UserRole, Role
|
||||
from authorization.models import JWTRefreshToken
|
||||
from utils.tokens import GMRefreshToken
|
||||
|
||||
|
||||
class IsAuthenticatedAndTokenIsValid(BasePermission):
|
||||
class IsAuthenticatedAndTokenIsValid(permissions.BasePermission):
|
||||
"""
|
||||
Check if user has a valid token and authenticated
|
||||
"""
|
||||
|
|
@ -24,7 +27,7 @@ class IsAuthenticatedAndTokenIsValid(BasePermission):
|
|||
return False
|
||||
|
||||
|
||||
class IsRefreshTokenValid(BasePermission):
|
||||
class IsRefreshTokenValid(permissions.BasePermission):
|
||||
"""
|
||||
Check if user has a valid refresh token and authenticated
|
||||
"""
|
||||
|
|
@ -38,3 +41,158 @@ class IsRefreshTokenValid(BasePermission):
|
|||
return refresh_token_qs.exists()
|
||||
else:
|
||||
return False
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
# Read permissions are allowed to any request,
|
||||
# so we'll always allow GET, HEAD or OPTIONS requests.
|
||||
if request.method in permissions.SAFE_METHODS or \
|
||||
obj.user == request.user or request.user.is_superuser:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class IsGuest(permissions.IsAuthenticatedOrReadOnly):
|
||||
"""
|
||||
Object-level permission to only allow owners of an object to edit it.
|
||||
"""
|
||||
def has_permission(self, request, view):
|
||||
return request.user.is_authenticated
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
|
||||
rules = [
|
||||
request.user.is_superuser,
|
||||
request.method in permissions.SAFE_METHODS
|
||||
]
|
||||
return any(rules)
|
||||
|
||||
|
||||
class IsStandardUser(IsGuest):
|
||||
"""
|
||||
Object-level permission to only allow owners of an object to edit it.
|
||||
Assumes the model instance has an `owner` attribute.
|
||||
"""
|
||||
def has_object_permission(self, request, view, obj):
|
||||
# Read permissions are allowed to any request
|
||||
rules = [
|
||||
super().has_object_permission(request, view, obj)
|
||||
]
|
||||
|
||||
if hasattr(obj, 'user'):
|
||||
rules = [
|
||||
obj.user == request.user and obj.user.email_confirmed,
|
||||
super().has_object_permission(request, view, obj)
|
||||
]
|
||||
|
||||
return any(rules)
|
||||
|
||||
|
||||
class IsContentPageManager(IsStandardUser):
|
||||
"""
|
||||
Object-level permission to only allow owners of an object to edit it.
|
||||
Assumes the model instance has an `owner` attribute.
|
||||
"""
|
||||
def has_object_permission(self, request, view, obj):
|
||||
# Read permissions are allowed to any request.
|
||||
|
||||
role = Role.objects.filter(role=Role.CONTENT_PAGE_MANAGER,
|
||||
country_id=obj.country_id)\
|
||||
.first() # 'Comments moderator'
|
||||
|
||||
rules = [
|
||||
UserRole.objects.filter(user=request.user, role=role).exists(),
|
||||
# and obj.user != request.user,
|
||||
super().has_object_permission(request, view, obj)
|
||||
]
|
||||
return any(rules)
|
||||
|
||||
|
||||
class IsCountryAdmin(IsStandardUser):
|
||||
"""
|
||||
Object-level permission to only allow owners of an object to edit it.
|
||||
Assumes the model instance has an `owner` attribute.
|
||||
"""
|
||||
def has_object_permission(self, request, view, obj):
|
||||
# Read permissions are allowed to any request.
|
||||
role = Role.objects.filter(role=Role.COUNTRY_ADMIN,
|
||||
country_id=obj.country_id) \
|
||||
.first() # 'Comments moderator'
|
||||
|
||||
rules = [
|
||||
UserRole.objects.filter(user=request.user, role=role).exists(),
|
||||
super().has_object_permission(request, view, obj),
|
||||
]
|
||||
|
||||
return any(rules)
|
||||
|
||||
|
||||
class IsCommentModerator(IsStandardUser):
|
||||
"""
|
||||
Object-level permission to only allow owners of an object to edit it.
|
||||
Assumes the model instance has an `owner` attribute.
|
||||
"""
|
||||
def has_object_permission(self, request, view, obj):
|
||||
# Read permissions are allowed to any request.
|
||||
role = Role.objects.filter(role=Role.COMMENTS_MODERATOR,
|
||||
country_id=obj.country_id)\
|
||||
.first() # 'Comments moderator'
|
||||
|
||||
rules = [
|
||||
UserRole.objects.filter(user=request.user, role=role).exists() and
|
||||
obj.user != request.user,
|
||||
super().has_object_permission(request, view, obj)
|
||||
]
|
||||
return any(rules)
|
||||
|
||||
|
||||
class IsEstablishmentManager(IsStandardUser):
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
role = Role.objects.filter(role=Role.ESTABLISHMENT_MANAGER)\
|
||||
.first() # 'Comments moderator'
|
||||
|
||||
rules = [
|
||||
UserRole.objects.filter(user=request.user, role=role,
|
||||
establishment_id=obj.establishment_id
|
||||
).exists(),
|
||||
super().has_object_permission(request, view, obj)
|
||||
]
|
||||
|
||||
return any(rules)
|
||||
|
||||
|
||||
class IsReviewerManager(IsStandardUser):
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
|
||||
role = Role.objects.filter(role=Role.REVIEWER_MANGER,
|
||||
country_id=obj.country_id)\
|
||||
.first()
|
||||
|
||||
rules = [
|
||||
UserRole.objects.filter(user=request.user, role=role).exists(),
|
||||
super().has_object_permission(request, view, obj)
|
||||
]
|
||||
|
||||
return any(rules)
|
||||
|
||||
|
||||
class IsRestaurantReviewer(IsStandardUser):
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
|
||||
content_type = ContentType.objects.get(app_lable='establishment',
|
||||
model='establishment')
|
||||
|
||||
role = Role.objects.filter(role=Role.RESTAURANT_REVIEWER,
|
||||
country=obj.country_id).first()
|
||||
|
||||
rules = [
|
||||
obj.content_type_id == content_type.id and
|
||||
UserRole.objects.filter(user=request.user, role=role,
|
||||
establishment_id=obj.object_id
|
||||
).exists(),
|
||||
super().has_object_permission(request, view, obj)
|
||||
]
|
||||
|
||||
return any(rules)
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ def validate_tjson(value):
|
|||
code='invalid_json',
|
||||
params={'value': value},
|
||||
)
|
||||
lang_count = Language.objects.filter(locale__in=value.keys()).count()
|
||||
if lang_count != len(value.keys()):
|
||||
is_lang = Language.objects.filter(locale__in=value.keys()).exists()
|
||||
if not is_lang:
|
||||
raise exceptions.ValidationError(
|
||||
'invalid_translated_keys',
|
||||
code='invalid_translated_keys',
|
||||
|
|
|
|||
0
apps/utils/tests/__init__.py
Normal file
0
apps/utils/tests/__init__.py
Normal file
37
apps/utils/tests/tests_json_field.py
Normal file
37
apps/utils/tests/tests_json_field.py
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
from django.test import TestCase
|
||||
from translation.models import Language
|
||||
from django.core import exceptions
|
||||
from utils.serializers import validate_tjson
|
||||
|
||||
|
||||
class ValidJSONTest(TestCase):
|
||||
|
||||
def test_valid_json(self):
|
||||
lang = Language.objects.create(title='English', locale='en-GB')
|
||||
lang.save()
|
||||
|
||||
data = 'str'
|
||||
|
||||
with self.assertRaises(exceptions.ValidationError) as err:
|
||||
validate_tjson(data)
|
||||
|
||||
self.assertEqual(err.exception.code, 'invalid_json')
|
||||
|
||||
data = {
|
||||
"string": "value"
|
||||
}
|
||||
|
||||
with self.assertRaises(exceptions.ValidationError) as err:
|
||||
validate_tjson(data)
|
||||
|
||||
self.assertEqual(err.exception.code, 'invalid_translated_keys')
|
||||
|
||||
data = {
|
||||
"en-GB": "English"
|
||||
}
|
||||
|
||||
try:
|
||||
validate_tjson(data)
|
||||
self.assertTrue(True)
|
||||
except exceptions.ValidationError:
|
||||
self.assert_(False, "Test json translated FAILED")
|
||||
18
apps/utils/tests/tests_permissions.py
Normal file
18
apps/utils/tests/tests_permissions.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
from rest_framework.test import APITestCase
|
||||
from location.models import Country
|
||||
from translation.models import Language
|
||||
|
||||
|
||||
class BasePermissionTests(APITestCase):
|
||||
def setUp(self):
|
||||
self.lang = Language.objects.get(
|
||||
title='Russia',
|
||||
locale='ru-RU'
|
||||
)
|
||||
|
||||
self.country_ru = Country.objects.get(
|
||||
name={"en-GB": "Russian"}
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
|
@ -8,11 +8,6 @@ from http.cookies import SimpleCookie
|
|||
from account.models import User
|
||||
from news.models import News, NewsType
|
||||
|
||||
from django.test import TestCase
|
||||
from translation.models import Language
|
||||
from django.core import exceptions
|
||||
from .serializers import validate_tjson
|
||||
|
||||
from establishment.models import Establishment, EstablishmentType, Employee
|
||||
|
||||
|
||||
|
|
@ -42,6 +37,7 @@ class TranslateFieldTests(BaseTestCase):
|
|||
super().setUp()
|
||||
|
||||
self.news_type = NewsType.objects.create(name="Test news type")
|
||||
self.news_type.save()
|
||||
|
||||
self.news_item = News.objects.create(
|
||||
created_by=self.user,
|
||||
|
|
@ -58,9 +54,11 @@ class TranslateFieldTests(BaseTestCase):
|
|||
slug='test',
|
||||
state=News.PUBLISHED,
|
||||
)
|
||||
self.news_item.save()
|
||||
|
||||
def test_model_field(self):
|
||||
self.assertIsNotNone(getattr(self.news_item, "title_translated", None))
|
||||
self.assertTrue(hasattr(self.news_item, "title_translated"))
|
||||
|
||||
|
||||
def test_read_locale(self):
|
||||
response = self.client.get(f"/api/web/news/slug/{self.news_item.slug}/", format='json')
|
||||
|
|
@ -69,7 +67,7 @@ class TranslateFieldTests(BaseTestCase):
|
|||
|
||||
self.assertIn("title_translated", news_data)
|
||||
|
||||
self.assertEqual(news_data['title_translated'], "Test news item")
|
||||
self.assertIn("Test news item", news_data['title_translated'])
|
||||
|
||||
|
||||
class BaseAttributeTests(BaseTestCase):
|
||||
|
|
@ -125,36 +123,3 @@ class BaseAttributeTests(BaseTestCase):
|
|||
employee.refresh_from_db()
|
||||
self.assertEqual(modify_user, employee.modified_by)
|
||||
self.assertEqual(self.user, employee.created_by)
|
||||
|
||||
|
||||
class ValidJSONTest(TestCase):
|
||||
|
||||
def test_valid_json(self):
|
||||
lang = Language.objects.create(title='English', locale='en-GB')
|
||||
lang.save()
|
||||
|
||||
data = 'str'
|
||||
|
||||
with self.assertRaises(exceptions.ValidationError) as err:
|
||||
validate_tjson(data)
|
||||
|
||||
self.assertEqual(err.exception.code, 'invalid_json')
|
||||
|
||||
data = {
|
||||
"string": "value"
|
||||
}
|
||||
|
||||
with self.assertRaises(exceptions.ValidationError) as err:
|
||||
validate_tjson(data)
|
||||
|
||||
self.assertEqual(err.exception.code, 'invalid_translated_keys')
|
||||
|
||||
data = {
|
||||
"en-GB": "English"
|
||||
}
|
||||
|
||||
try:
|
||||
validate_tjson(data)
|
||||
self.assertTrue(True)
|
||||
except exceptions.ValidationError:
|
||||
self.assert_(False, "Test json translated FAILED")
|
||||
|
|
@ -9,5 +9,7 @@ urlpatterns = [
|
|||
path('gallery/', include(('gallery.urls', 'gallery'), namespace='gallery')),
|
||||
path('location/', include('location.urls.back')),
|
||||
path('news/', include('news.urls.back')),
|
||||
path('review/', include('review.urls.back')),
|
||||
path('tags/', include(('tag.urls.back', 'tag'), namespace='tag')),
|
||||
]
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user