From 7925febc77d103c54c2431d77f3a1b56b378dc5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Tue, 8 Oct 2019 09:57:47 +0300 Subject: [PATCH 01/14] Models role --- apps/account/migrations/0009_role_userrole.py | 47 +++++++++++++++++++ apps/account/models.py | 22 +++++++++ .../migrations/0003_auto_20191004_0928.py | 17 +++++++ 3 files changed, 86 insertions(+) create mode 100644 apps/account/migrations/0009_role_userrole.py create mode 100644 apps/timetable/migrations/0003_auto_20191004_0928.py diff --git a/apps/account/migrations/0009_role_userrole.py b/apps/account/migrations/0009_role_userrole.py new file mode 100644 index 00000000..f69cb34f --- /dev/null +++ b/apps/account/migrations/0009_role_userrole.py @@ -0,0 +1,47 @@ +# Generated by Django 2.2.4 on 2019-10-08 06:54 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('location', '0010_auto_20190904_0711'), + ('account', '0008_auto_20190912_1325'), + ] + + operations = [ + migrations.CreateModel( + name='Role', + 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')), + ('role', models.CharField(choices=[(0, 'Guest'), (1, 'Standard user'), (2, 'Content page manager'), (3, 'Comments moderator')], max_length=250, verbose_name='Role')), + ('is_list', models.BooleanField(default=True, verbose_name='list')), + ('is_create', models.BooleanField(default=False, verbose_name='create')), + ('is_update', models.BooleanField(default=False, verbose_name='update')), + ('is_delete', models.BooleanField(default=False, verbose_name='delete')), + ('country', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='location.Country', verbose_name='Country')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='UserRole', + 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')), + ('role', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='account.Role', verbose_name='Role')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='User')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/account/models.py b/apps/account/models.py index 81ade4fc..86d9bf8c 100644 --- a/apps/account/models.py +++ b/apps/account/models.py @@ -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 location.models import Country from utils.models import GMTokenGenerator from utils.models import ImageMixin, ProjectBaseMixin, PlatformMixin from utils.tokens import GMRefreshToken @@ -195,3 +196,24 @@ class User(AbstractUser): return render_to_string( template_name=settings.CHANGE_EMAIL_TEMPLATE, context=context) + + +class Role(ProjectBaseMixin): + ROLE_CHOICES =( + (0, 'Guest'), + (1, 'Standard user'), + (2, 'Content page manager'), + (3, 'Comments moderator'), + ) + role = models.CharField(verbose_name=_('Role'), max_length=250, + choices=ROLE_CHOICES, null=False, blank=False) + country = models.ForeignKey(Country, verbose_name=_('Country'), on_delete=models.CASCADE) + 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) + is_delete = models.BooleanField(verbose_name=_('delete'), default=False, null=False) + + +class UserRole(ProjectBaseMixin): + 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) \ No newline at end of file diff --git a/apps/timetable/migrations/0003_auto_20191004_0928.py b/apps/timetable/migrations/0003_auto_20191004_0928.py new file mode 100644 index 00000000..6e82c679 --- /dev/null +++ b/apps/timetable/migrations/0003_auto_20191004_0928.py @@ -0,0 +1,17 @@ +# Generated by Django 2.2.4 on 2019-10-04 09:28 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('timetable', '0002_auto_20190919_1124'), + ] + + operations = [ + migrations.AlterModelOptions( + name='timetable', + options={'ordering': ['weekday'], 'verbose_name': 'Timetable', 'verbose_name_plural': 'Timetables'}, + ), + ] From e66a6bcbfaa2f527793d48f57fbf4dade4e0c6dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Tue, 8 Oct 2019 10:18:51 +0300 Subject: [PATCH 02/14] Fix models --- apps/account/admin.py | 10 ++++++++++ apps/account/migrations/0009_role_userrole.py | 4 ++-- apps/account/models.py | 8 +++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/apps/account/admin.py b/apps/account/admin.py index 8429952f..12f2ef03 100644 --- a/apps/account/admin.py +++ b/apps/account/admin.py @@ -6,6 +6,16 @@ from django.utils.translation import ugettext_lazy as _ from account import models +@admin.register(models.Role) +class RoleAdmin(admin.ModelAdmin): + list_display = ['role', 'country', 'is_list', 'is_create', 'is_update', 'is_delete'] + + +@admin.register(models.UserRole) +class UserRoleAdmin(admin.ModelAdmin): + list_display = ['user', 'role'] + + @admin.register(models.User) class UserAdmin(BaseUserAdmin): """User model admin settings.""" diff --git a/apps/account/migrations/0009_role_userrole.py b/apps/account/migrations/0009_role_userrole.py index f69cb34f..e162bfe5 100644 --- a/apps/account/migrations/0009_role_userrole.py +++ b/apps/account/migrations/0009_role_userrole.py @@ -1,4 +1,4 @@ -# Generated by Django 2.2.4 on 2019-10-08 06:54 +# Generated by Django 2.2.4 on 2019-10-08 07:17 from django.conf import settings from django.db import migrations, models @@ -20,7 +20,7 @@ class Migration(migrations.Migration): ('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')), - ('role', models.CharField(choices=[(0, 'Guest'), (1, 'Standard user'), (2, 'Content page manager'), (3, 'Comments moderator')], max_length=250, verbose_name='Role')), + ('role', models.PositiveIntegerField(choices=[(1, 'Standard user'), (2, 'Comments moderator')], verbose_name='Role')), ('is_list', models.BooleanField(default=True, verbose_name='list')), ('is_create', models.BooleanField(default=False, verbose_name='create')), ('is_update', models.BooleanField(default=False, verbose_name='update')), diff --git a/apps/account/models.py b/apps/account/models.py index 86d9bf8c..960860cd 100644 --- a/apps/account/models.py +++ b/apps/account/models.py @@ -200,13 +200,11 @@ class User(AbstractUser): class Role(ProjectBaseMixin): ROLE_CHOICES =( - (0, 'Guest'), (1, 'Standard user'), - (2, 'Content page manager'), - (3, 'Comments moderator'), + (2, 'Comments moderator'), ) - role = models.CharField(verbose_name=_('Role'), max_length=250, - choices=ROLE_CHOICES, null=False, blank=False) + role = models.PositiveIntegerField(verbose_name=_('Role'), choices=ROLE_CHOICES, + null=False, blank=False) country = models.ForeignKey(Country, verbose_name=_('Country'), on_delete=models.CASCADE) is_list = models.BooleanField(verbose_name=_('list'), default=True, null=False) is_create = models.BooleanField(verbose_name=_('create'), default=False, null=False) From eeba02c2aea27b37306b841548f6ca2a0c368be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Tue, 8 Oct 2019 15:26:39 +0300 Subject: [PATCH 03/14] test role --- apps/account/admin.py | 2 +- .../migrations/0010_auto_20191008_0751.py | 29 +++++++++++++++++++ apps/account/models.py | 8 ++--- apps/account/permissions.py | 0 apps/comment/serializers/back.py | 11 +++++++ apps/comment/urls/back.py | 9 ++++++ apps/comment/views/back.py | 0 7 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 apps/account/migrations/0010_auto_20191008_0751.py create mode 100644 apps/account/permissions.py create mode 100644 apps/comment/serializers/back.py create mode 100644 apps/comment/urls/back.py create mode 100644 apps/comment/views/back.py diff --git a/apps/account/admin.py b/apps/account/admin.py index 12f2ef03..a89e6693 100644 --- a/apps/account/admin.py +++ b/apps/account/admin.py @@ -8,7 +8,7 @@ from account import models @admin.register(models.Role) class RoleAdmin(admin.ModelAdmin): - list_display = ['role', 'country', 'is_list', 'is_create', 'is_update', 'is_delete'] + list_display = ['role', 'country'] @admin.register(models.UserRole) diff --git a/apps/account/migrations/0010_auto_20191008_0751.py b/apps/account/migrations/0010_auto_20191008_0751.py new file mode 100644 index 00000000..289f8643 --- /dev/null +++ b/apps/account/migrations/0010_auto_20191008_0751.py @@ -0,0 +1,29 @@ +# Generated by Django 2.2.4 on 2019-10-08 07:51 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0009_role_userrole'), + ] + + operations = [ + migrations.RemoveField( + model_name='role', + name='is_create', + ), + migrations.RemoveField( + model_name='role', + name='is_delete', + ), + migrations.RemoveField( + model_name='role', + name='is_list', + ), + migrations.RemoveField( + model_name='role', + name='is_update', + ), + ] diff --git a/apps/account/models.py b/apps/account/models.py index 960860cd..c7de88e3 100644 --- a/apps/account/models.py +++ b/apps/account/models.py @@ -206,10 +206,10 @@ class Role(ProjectBaseMixin): role = models.PositiveIntegerField(verbose_name=_('Role'), choices=ROLE_CHOICES, null=False, blank=False) country = models.ForeignKey(Country, verbose_name=_('Country'), on_delete=models.CASCADE) - 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) - is_delete = models.BooleanField(verbose_name=_('delete'), default=False, null=False) + # 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) + # is_delete = models.BooleanField(verbose_name=_('delete'), default=False, null=False) class UserRole(ProjectBaseMixin): diff --git a/apps/account/permissions.py b/apps/account/permissions.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/comment/serializers/back.py b/apps/comment/serializers/back.py new file mode 100644 index 00000000..a491168d --- /dev/null +++ b/apps/comment/serializers/back.py @@ -0,0 +1,11 @@ +"""Comment app common serializers.""" +from comment import models +from rest_framework import serializers +from utils.serializers import ProjectModelSerializer + + +class CommentBaseSerializer(ProjectModelSerializer): + + class Meta: + model = models.Comment + fields = ('id', 'text', 'mark', 'user') \ No newline at end of file diff --git a/apps/comment/urls/back.py b/apps/comment/urls/back.py new file mode 100644 index 00000000..6141ceed --- /dev/null +++ b/apps/comment/urls/back.py @@ -0,0 +1,9 @@ +"""Web urlpaths.""" +from comment.urls.common import urlpatterns as common_urlpatterns + +app_name = 'comment' + +urlpatterns_api = [] + +urlpatterns = common_urlpatterns + \ + urlpatterns_api diff --git a/apps/comment/views/back.py b/apps/comment/views/back.py new file mode 100644 index 00000000..e69de29b From 48ca13803eb8a6398519c7ca597ea2ea0ffc94ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Wed, 9 Oct 2019 14:44:01 +0300 Subject: [PATCH 04/14] Pre test permission comment --- apps/account/serializers/back.py | 21 ++++++++ apps/account/tests/tests_back.py | 86 ++++++++++++++++++++++++++++++++ apps/account/urls/back.py | 12 +++++ apps/account/views/back.py | 13 +++++ apps/comment/permissions.py | 28 +++++++++++ apps/comment/serializers/back.py | 4 +- apps/comment/tests.py | 58 ++++++++++++++++++++- apps/comment/urls/back.py | 14 +++--- apps/comment/views/back.py | 16 ++++++ project/urls/back.py | 4 +- 10 files changed, 245 insertions(+), 11 deletions(-) create mode 100644 apps/account/serializers/back.py create mode 100644 apps/account/tests/tests_back.py create mode 100644 apps/account/urls/back.py create mode 100644 apps/account/views/back.py create mode 100644 apps/comment/permissions.py diff --git a/apps/account/serializers/back.py b/apps/account/serializers/back.py new file mode 100644 index 00000000..c1a1c6d4 --- /dev/null +++ b/apps/account/serializers/back.py @@ -0,0 +1,21 @@ +"""Back account serializers""" +from rest_framework import serializers +from account import models + + +class RoleSerializer(serializers.ModelSerializer): + class Meta: + model = models.Role + fields = [ + 'role', + 'country' + ] + + +class UserRoleSerializer(serializers.ModelSerializer): + class Meta: + model = models.UserRole + fields = [ + 'user', + 'role' + ] \ No newline at end of file diff --git a/apps/account/tests/tests_back.py b/apps/account/tests/tests_back.py new file mode 100644 index 00000000..56c0cd3a --- /dev/null +++ b/apps/account/tests/tests_back.py @@ -0,0 +1,86 @@ +from rest_framework.test import APITestCase +from rest_framework import status +from authorization.tests.tests_authorization import get_tokens_for_user +from django.urls import reverse +from http.cookies import SimpleCookie +from location.models import Country +from account.models import Role, User, UserRole + +class RoleTests(APITestCase): + def setUp(self): + self.data = get_tokens_for_user() + self.client.cookies = SimpleCookie( + {'access_token': self.data['tokens'].get('access_token'), + 'refresh_token': self.data['tokens'].get('access_token')}) + + def test_role_get(self): + url = reverse('back:account:role-list-create') + response = self.client.get(url) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_role_post(self): + url = reverse('back:account:role-list-create') + country = Country.objects.create( + name='{"ru-RU":"Russia"}', + code='23', + low_price=15, + high_price=150000 + ) + country.save() + + data = { + "role": 2, + "country": country.pk + } + response = self.client.post(url, data=data, format='json') + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + +class UserRoleTests(APITestCase): + def setUp(self): + self.data = get_tokens_for_user() + self.client.cookies = SimpleCookie( + {'access_token': self.data['tokens'].get('access_token'), + 'refresh_token': self.data['tokens'].get('access_token')}) + + self.country_ru = Country.objects.create( + name='{"ru-RU":"Russia"}', + code='23', + low_price=15, + high_price=150000 + ) + self.country_ru.save() + + self.country_en = Country.objects.create( + name='{"en-GB":"England"}', + code='25', + low_price=15, + high_price=150000 + ) + self.country_en.save() + + self.role = Role.objects.create( + role=2, + country=self.country_ru + ) + self.role.save() + + self.user_test = User.objects.create_user(username='test', + email='testemail@mail.com', + password='passwordtest') + + def test_user_role_post(self): + url = reverse('back:account:user-role-list-create') + # userRole = UserRole.objects.create( + # user=self.user_test, + # role=self.role + # ) + # userRole.save() + + data = { + "user": self.user_test.id, + "role": self.role.id + } + + response = self.client.post(url, data=data, format='json') + self.assertEqual(response.status_code, status.HTTP_201_CREATED) diff --git a/apps/account/urls/back.py b/apps/account/urls/back.py new file mode 100644 index 00000000..ee2e4148 --- /dev/null +++ b/apps/account/urls/back.py @@ -0,0 +1,12 @@ +"""Back account URLs""" +from django.urls import path + +from account.views import back as views + +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'), + +] diff --git a/apps/account/views/back.py b/apps/account/views/back.py new file mode 100644 index 00000000..8799f915 --- /dev/null +++ b/apps/account/views/back.py @@ -0,0 +1,13 @@ +from rest_framework import generics +from account.serializers import back as serializers +from account import models + + +class RoleLstView(generics.ListCreateAPIView): + serializer_class = serializers.RoleSerializer + queryset = models.Role.objects.all() + + +class UserRoleLstView(generics.ListCreateAPIView): + serializer_class = serializers.UserRoleSerializer + queryset = models.Role.objects.all() \ No newline at end of file diff --git a/apps/comment/permissions.py b/apps/comment/permissions.py new file mode 100644 index 00000000..aa57eaca --- /dev/null +++ b/apps/comment/permissions.py @@ -0,0 +1,28 @@ +from rest_framework import permissions +from account.models import UserRole, Role, User + + +class IsCommentModerator(permissions.BasePermission): + """ + 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: + return True + + # Instance must have an attribute named `user`. + role = Role.objects.get(role=2) # 'Comments moderator' + is_access = UserRole.objects.filter(user=request.user, role=role).exists() + if obj.user == request.user and is_access: + return True + + # User is super-user? + if User.objects.filter(pk=request.user.pk).exists(): + return True + + return False + diff --git a/apps/comment/serializers/back.py b/apps/comment/serializers/back.py index a491168d..d0cd47c8 100644 --- a/apps/comment/serializers/back.py +++ b/apps/comment/serializers/back.py @@ -1,11 +1,9 @@ """Comment app common serializers.""" from comment import models from rest_framework import serializers -from utils.serializers import ProjectModelSerializer -class CommentBaseSerializer(ProjectModelSerializer): - +class CommentBaseSerializer(serializers.ModelSerializer): class Meta: model = models.Comment fields = ('id', 'text', 'mark', 'user') \ No newline at end of file diff --git a/apps/comment/tests.py b/apps/comment/tests.py index a39b155a..09287225 100644 --- a/apps/comment/tests.py +++ b/apps/comment/tests.py @@ -1 +1,57 @@ -# Create your tests here. +from rest_framework.test import APITestCase +from rest_framework import status +from authorization.tests.tests_authorization import get_tokens_for_user +from django.urls import reverse +from http.cookies import SimpleCookie +from location.models import Country +from account.models import Role, User, UserRole + + +class CommentModeratorPermissionTests(APITestCase): + def setUp(self): + self.data = get_tokens_for_user() + + self.client.cookies = SimpleCookie( + {'access_token': self.data['tokens'].get('access_token'), + 'refresh_token': self.data['tokens'].get('access_token')}) + + self.country_ru = Country.objects.create( + name='{"ru-RU":"Russia"}', + code='23', + low_price=15, + high_price=150000 + ) + self.country_ru.save() + + self.country_en = Country.objects.create( + name='{"en-GB":"England"}', + code='25', + low_price=15, + high_price=150000 + ) + self.country_en.save() + + self.role = Role.objects.create( + role=2, + country=self.country_ru + ) + self.role.save() + + self.moderator = User.objects.create_user(username='moderator', + email='moderator@mail.com', + password='passwordmoderator') + + self.userRole = UserRole.objects.create( + user=self.moderator, + role=self.role + ) + self.userRole.save() + + tokens = User.create_jwt_tokens(self.moderator) + + self.client.cookies = SimpleCookie( + {'access_token': tokens.get('access_token'), + 'refresh_token': tokens.get('access_token')}) + + def test_permission(self): + self.assertTrue(True) \ No newline at end of file diff --git a/apps/comment/urls/back.py b/apps/comment/urls/back.py index 6141ceed..a1f2e010 100644 --- a/apps/comment/urls/back.py +++ b/apps/comment/urls/back.py @@ -1,9 +1,11 @@ -"""Web urlpaths.""" -from comment.urls.common import urlpatterns as common_urlpatterns +"""Back comment URLs""" +from django.urls import path + +from comment.views import back as views app_name = 'comment' -urlpatterns_api = [] - -urlpatterns = common_urlpatterns + \ - urlpatterns_api +urlpatterns = [ + path('', views.CommentLstView.as_view(), name='comment-list-create'), + path('/', views.CommentRUDView.as_view(), name='comment-crud'), +] diff --git a/apps/comment/views/back.py b/apps/comment/views/back.py index e69de29b..1420ebc2 100644 --- a/apps/comment/views/back.py +++ b/apps/comment/views/back.py @@ -0,0 +1,16 @@ +from rest_framework import generics, permissions +from comment.serializers import back as serializers +from comment import models +from comment.permissions import IsCommentModerator + + +class CommentLstView(generics.ListCreateAPIView): + serializer_class = serializers.CommentBaseSerializer + queryset = models.Comment.objects.all() + permission_classes = [permissions.IsAuthenticatedOrReadOnly,] + + +class CommentRUDView(generics.RetrieveUpdateDestroyAPIView): + serializer_class = serializers.CommentBaseSerializer + queryset = models.Comment.objects.all() + permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsCommentModerator] \ No newline at end of file diff --git a/project/urls/back.py b/project/urls/back.py index 7b4146eb..59758c66 100644 --- a/project/urls/back.py +++ b/project/urls/back.py @@ -7,5 +7,7 @@ urlpatterns = [ namespace='gallery')), path('establishments/', include('establishment.urls.back')), path('location/', include('location.urls.back')), - path('news/', include('news.urls.back')) + path('news/', include('news.urls.back')), + path('account/', include('account.urls.back')), + path('comment/', include('comment.urls.back')), ] \ No newline at end of file From 7ed976dec0a906b604abaaebcb620ccb93968389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Wed, 9 Oct 2019 16:28:14 +0300 Subject: [PATCH 05/14] Test --- apps/account/tests/tests_back.py | 5 -- apps/comment/permissions.py | 9 ++-- apps/comment/tests.py | 83 +++++++++++++++++++++++++++++--- apps/comment/urls/back.py | 2 +- apps/comment/views/back.py | 3 +- 5 files changed, 85 insertions(+), 17 deletions(-) diff --git a/apps/account/tests/tests_back.py b/apps/account/tests/tests_back.py index 56c0cd3a..8adc6b35 100644 --- a/apps/account/tests/tests_back.py +++ b/apps/account/tests/tests_back.py @@ -71,11 +71,6 @@ class UserRoleTests(APITestCase): def test_user_role_post(self): url = reverse('back:account:user-role-list-create') - # userRole = UserRole.objects.create( - # user=self.user_test, - # role=self.role - # ) - # userRole.save() data = { "user": self.user_test.id, diff --git a/apps/comment/permissions.py b/apps/comment/permissions.py index aa57eaca..09860c2c 100644 --- a/apps/comment/permissions.py +++ b/apps/comment/permissions.py @@ -14,14 +14,17 @@ class IsCommentModerator(permissions.BasePermission): if request.method in permissions.SAFE_METHODS: return True + if obj.user == request.user: + return True + # Instance must have an attribute named `user`. role = Role.objects.get(role=2) # 'Comments moderator' is_access = UserRole.objects.filter(user=request.user, role=role).exists() - if obj.user == request.user and is_access: + if obj.user != request.user and is_access: return True - # User is super-user? - if User.objects.filter(pk=request.user.pk).exists(): + super_user=User.objects.filter(pk=request.user.pk, is_superuser=True).exists() + if super_user: return True return False diff --git a/apps/comment/tests.py b/apps/comment/tests.py index 09287225..0b053cb8 100644 --- a/apps/comment/tests.py +++ b/apps/comment/tests.py @@ -2,18 +2,15 @@ from rest_framework.test import APITestCase 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 class CommentModeratorPermissionTests(APITestCase): def setUp(self): - self.data = get_tokens_for_user() - - self.client.cookies = SimpleCookie( - {'access_token': self.data['tokens'].get('access_token'), - 'refresh_token': self.data['tokens'].get('access_token')}) self.country_ru = Country.objects.create( name='{"ru-RU":"Russia"}', @@ -47,11 +44,83 @@ class CommentModeratorPermissionTests(APITestCase): ) self.userRole.save() + content_type = ContentType.objects.get(app_label='location', model='country') + + self.user_test = get_tokens_for_user() + self.comment = Comment.objects.create(text='Test comment', mark=1, + user=self.user_test["user"], + object_id= self.country_ru.pk, + content_type_id=content_type.id + ) + self.comment.save() + + def test_get(self): + url = reverse('back:comment:comment-crud', kwargs={"id": 1}) + response = self.client.get(url, format='json') + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_put_moderator(self): + url = reverse('back:comment:comment-crud', kwargs={"id": self.comment.id}) + tokens = User.create_jwt_tokens(self.moderator) + self.client.cookies = SimpleCookie( + {'access_token': tokens.get('access_token'), + 'refresh_token': tokens.get('access_token')}) + + data = { + "id": self.comment.id, + "text": "test text moderator", + "mark": 1, + "user": self.moderator.id + } + + response = self.client.put(url, data=data, format='json') + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_put_other_user(self): + url = reverse('back:comment:comment-crud', kwargs={"id": self.comment.id}) + other_user = User.objects.create_user(username='test', + email='test@mail.com', + password='passwordtest') + + tokens = User.create_jwt_tokens(other_user) self.client.cookies = SimpleCookie( {'access_token': tokens.get('access_token'), 'refresh_token': tokens.get('access_token')}) - def test_permission(self): - self.assertTrue(True) \ No newline at end of file + data = { + "id": self.comment.id, + "text": "test text moderator", + "mark": 1, + "user": other_user.id + } + + response = self.client.put(url, data=data, format='json') + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + + def test_put_super_user(self): + url = reverse('back:comment:comment-crud', kwargs={"id": self.comment.id}) + super_user = User.objects.create_user(username='super', + email='super@mail.com', + password='passwordtestsuper', + is_superuser=True) + + tokens = User.create_jwt_tokens(super_user) + + self.client.cookies = SimpleCookie( + {'access_token': tokens.get('access_token'), + 'refresh_token': tokens.get('access_token')}) + + data = { + "id": self.comment.id, + "text": "test text moderator", + "mark": 1, + "user": super_user.id + } + + response = self.client.put(url, data=data, format='json') + self.assertEqual(response.status_code, status.HTTP_200_OK) + + + diff --git a/apps/comment/urls/back.py b/apps/comment/urls/back.py index a1f2e010..214eab48 100644 --- a/apps/comment/urls/back.py +++ b/apps/comment/urls/back.py @@ -7,5 +7,5 @@ app_name = 'comment' urlpatterns = [ path('', views.CommentLstView.as_view(), name='comment-list-create'), - path('/', views.CommentRUDView.as_view(), name='comment-crud'), + path('/', views.CommentRUDView.as_view(), name='comment-crud'), ] diff --git a/apps/comment/views/back.py b/apps/comment/views/back.py index 1420ebc2..16450d03 100644 --- a/apps/comment/views/back.py +++ b/apps/comment/views/back.py @@ -13,4 +13,5 @@ class CommentLstView(generics.ListCreateAPIView): class CommentRUDView(generics.RetrieveUpdateDestroyAPIView): serializer_class = serializers.CommentBaseSerializer queryset = models.Comment.objects.all() - permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsCommentModerator] \ No newline at end of file + permission_classes = [permissions.IsAuthenticatedOrReadOnly,IsCommentModerator] + lookup_field = 'id' From 01dd7283234f719170f9ef2e5f28fe1e9ed26034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Wed, 9 Oct 2019 16:44:29 +0300 Subject: [PATCH 06/14] Refactor --- apps/comment/tests.py | 22 +++++-------------- .../migrations/0004_merge_20191009_1341.py | 14 ++++++++++++ 2 files changed, 19 insertions(+), 17 deletions(-) create mode 100644 apps/timetable/migrations/0004_merge_20191009_1341.py diff --git a/apps/comment/tests.py b/apps/comment/tests.py index 0b053cb8..2157933e 100644 --- a/apps/comment/tests.py +++ b/apps/comment/tests.py @@ -20,14 +20,6 @@ class CommentModeratorPermissionTests(APITestCase): ) self.country_ru.save() - self.country_en = Country.objects.create( - name='{"en-GB":"England"}', - code='25', - low_price=15, - high_price=150000 - ) - self.country_en.save() - self.role = Role.objects.create( role=2, country=self.country_ru @@ -53,15 +45,13 @@ class CommentModeratorPermissionTests(APITestCase): content_type_id=content_type.id ) self.comment.save() + self.url = reverse('back:comment:comment-crud', kwargs={"id": self.comment.id}) def test_get(self): - url = reverse('back:comment:comment-crud', kwargs={"id": 1}) - response = self.client.get(url, format='json') + response = self.client.get(self.url, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) def test_put_moderator(self): - url = reverse('back:comment:comment-crud', kwargs={"id": self.comment.id}) - tokens = User.create_jwt_tokens(self.moderator) self.client.cookies = SimpleCookie( {'access_token': tokens.get('access_token'), @@ -74,11 +64,10 @@ class CommentModeratorPermissionTests(APITestCase): "user": self.moderator.id } - response = self.client.put(url, data=data, format='json') + response = self.client.put(self.url, data=data, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) def test_put_other_user(self): - url = reverse('back:comment:comment-crud', kwargs={"id": self.comment.id}) other_user = User.objects.create_user(username='test', email='test@mail.com', password='passwordtest') @@ -96,11 +85,10 @@ class CommentModeratorPermissionTests(APITestCase): "user": other_user.id } - response = self.client.put(url, data=data, format='json') + response = self.client.put(self.url, data=data, format='json') self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_put_super_user(self): - url = reverse('back:comment:comment-crud', kwargs={"id": self.comment.id}) super_user = User.objects.create_user(username='super', email='super@mail.com', password='passwordtestsuper', @@ -119,7 +107,7 @@ class CommentModeratorPermissionTests(APITestCase): "user": super_user.id } - response = self.client.put(url, data=data, format='json') + response = self.client.put(self.url, data=data, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) diff --git a/apps/timetable/migrations/0004_merge_20191009_1341.py b/apps/timetable/migrations/0004_merge_20191009_1341.py new file mode 100644 index 00000000..22d83ca3 --- /dev/null +++ b/apps/timetable/migrations/0004_merge_20191009_1341.py @@ -0,0 +1,14 @@ +# Generated by Django 2.2.4 on 2019-10-09 13:41 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('timetable', '0003_auto_20191004_0928'), + ('timetable', '0003_auto_20191003_0943'), + ] + + operations = [ + ] From 56c0927a52458f306ac1091294774a59fb02721c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Thu, 10 Oct 2019 14:58:19 +0300 Subject: [PATCH 07/14] Add country control --- .../migrations/0002_comment_language.py | 20 +++++++++++++++++++ apps/comment/models.py | 3 ++- apps/comment/permissions.py | 6 +++--- .../migrations/0011_country_language.py | 19 ++++++++++++++++++ apps/location/models.py | 3 ++- 5 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 apps/comment/migrations/0002_comment_language.py create mode 100644 apps/location/migrations/0011_country_language.py diff --git a/apps/comment/migrations/0002_comment_language.py b/apps/comment/migrations/0002_comment_language.py new file mode 100644 index 00000000..4b0b9ab7 --- /dev/null +++ b/apps/comment/migrations/0002_comment_language.py @@ -0,0 +1,20 @@ +# Generated by Django 2.2.4 on 2019-10-10 11:46 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('translation', '0003_auto_20190901_1032'), + ('comment', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='comment', + name='language', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='translation.Language', verbose_name='Locale'), + ), + ] diff --git a/apps/comment/models.py b/apps/comment/models.py index fe781d4d..0193055d 100644 --- a/apps/comment/models.py +++ b/apps/comment/models.py @@ -6,7 +6,7 @@ from django.utils.translation import gettext_lazy as _ from account.models import User from utils.models import ProjectBaseMixin from utils.querysets import ContentTypeQuerySetMixin - +from translation.models import Language class CommentQuerySet(ContentTypeQuerySetMixin): """QuerySets for Comment model.""" @@ -41,6 +41,7 @@ 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) class Meta: """Meta class""" diff --git a/apps/comment/permissions.py b/apps/comment/permissions.py index 09860c2c..3bfb2b3c 100644 --- a/apps/comment/permissions.py +++ b/apps/comment/permissions.py @@ -13,12 +13,12 @@ class IsCommentModerator(permissions.BasePermission): # so we'll always allow GET, HEAD or OPTIONS requests. if request.method in permissions.SAFE_METHODS: return True - + # user owner is user request if obj.user == request.user: return True - # Instance must have an attribute named `user`. - role = Role.objects.get(role=2) # 'Comments moderator' + # Must have role + role = Role.objects.filter(role=2, country__language=obj.language).first() # 'Comments moderator' is_access = UserRole.objects.filter(user=request.user, role=role).exists() if obj.user != request.user and is_access: return True diff --git a/apps/location/migrations/0011_country_language.py b/apps/location/migrations/0011_country_language.py new file mode 100644 index 00000000..9a6b4e8a --- /dev/null +++ b/apps/location/migrations/0011_country_language.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.4 on 2019-10-10 11:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('translation', '0003_auto_20190901_1032'), + ('location', '0010_auto_20190904_0711'), + ] + + operations = [ + migrations.AddField( + model_name='country', + name='language', + field=models.ManyToManyField(to='translation.Language', verbose_name='Language'), + ), + ] diff --git a/apps/location/models.py b/apps/location/models.py index 1cab1815..b11b0ad5 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -6,7 +6,7 @@ from django.db.transaction import on_commit from django.dispatch import receiver from django.utils.translation import gettext_lazy as _ from utils.models import ProjectBaseMixin, SVGImageMixin, TranslatedFieldsMixin, TJSONField - +from translation.models import Language class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin): """Country model.""" @@ -18,6 +18,7 @@ class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin): code = models.CharField(max_length=255, unique=True, verbose_name=_('Code')) low_price = models.IntegerField(default=25, verbose_name=_('Low price')) high_price = models.IntegerField(default=50, verbose_name=_('High price')) + language = models.ManyToManyField(Language, verbose_name=_('Language')) class Meta: """Meta class.""" From ab5a66afe2e579c4b6ae88ca0e85874dcd5938fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Thu, 10 Oct 2019 15:20:13 +0300 Subject: [PATCH 08/14] Test change --- apps/comment/permissions.py | 13 ++++++++----- apps/comment/tests.py | 13 +++++++++++-- .../migrations/0012_auto_20191010_1205.py | 18 ++++++++++++++++++ apps/location/models.py | 2 +- 4 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 apps/location/migrations/0012_auto_20191010_1205.py diff --git a/apps/comment/permissions.py b/apps/comment/permissions.py index 3bfb2b3c..9e0ab58b 100644 --- a/apps/comment/permissions.py +++ b/apps/comment/permissions.py @@ -13,17 +13,20 @@ class IsCommentModerator(permissions.BasePermission): # so we'll always allow GET, HEAD or OPTIONS requests. if request.method in permissions.SAFE_METHODS: return True - # user owner is user request - if obj.user == request.user: - return True + # # user owner is user request + # if obj.user == request.user: + # return True # Must have role - role = Role.objects.filter(role=2, country__language=obj.language).first() # 'Comments moderator' + # ,country__languages__id=obj.language_id + role = Role.objects.filter(role=2, + 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 - super_user=User.objects.filter(pk=request.user.pk, is_superuser=True).exists() + super_user = User.objects.filter(pk=request.user.pk, is_superuser=True).exists() if super_user: return True diff --git a/apps/comment/tests.py b/apps/comment/tests.py index 2157933e..949ba597 100644 --- a/apps/comment/tests.py +++ b/apps/comment/tests.py @@ -7,17 +7,25 @@ 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): 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 + high_price=150000, ) + self.country_ru.languages.add(self.lang) self.country_ru.save() self.role = Role.objects.create( @@ -42,7 +50,8 @@ class CommentModeratorPermissionTests(APITestCase): self.comment = Comment.objects.create(text='Test comment', mark=1, user=self.user_test["user"], object_id= self.country_ru.pk, - content_type_id=content_type.id + content_type_id=content_type.id, + language=self.lang ) self.comment.save() self.url = reverse('back:comment:comment-crud', kwargs={"id": self.comment.id}) diff --git a/apps/location/migrations/0012_auto_20191010_1205.py b/apps/location/migrations/0012_auto_20191010_1205.py new file mode 100644 index 00000000..a2de2917 --- /dev/null +++ b/apps/location/migrations/0012_auto_20191010_1205.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.4 on 2019-10-10 12:05 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('location', '0011_country_language'), + ] + + operations = [ + migrations.RenameField( + model_name='country', + old_name='language', + new_name='languages', + ), + ] diff --git a/apps/location/models.py b/apps/location/models.py index b11b0ad5..f52f9fee 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -18,7 +18,7 @@ class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin): code = models.CharField(max_length=255, unique=True, verbose_name=_('Code')) low_price = models.IntegerField(default=25, verbose_name=_('Low price')) high_price = models.IntegerField(default=50, verbose_name=_('High price')) - language = models.ManyToManyField(Language, verbose_name=_('Language')) + languages = models.ManyToManyField(Language, verbose_name=_('Languages')) class Meta: """Meta class.""" From b83efb7cda31913714c89a78da158be3cb92bbe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Thu, 10 Oct 2019 15:23:44 +0300 Subject: [PATCH 09/14] Fix migrations --- ...y_language.py => 0011_country_languages.py} | 6 +++--- .../migrations/0012_auto_20191010_1205.py | 18 ------------------ 2 files changed, 3 insertions(+), 21 deletions(-) rename apps/location/migrations/{0011_country_language.py => 0011_country_languages.py} (77%) delete mode 100644 apps/location/migrations/0012_auto_20191010_1205.py diff --git a/apps/location/migrations/0011_country_language.py b/apps/location/migrations/0011_country_languages.py similarity index 77% rename from apps/location/migrations/0011_country_language.py rename to apps/location/migrations/0011_country_languages.py index 9a6b4e8a..629f76bc 100644 --- a/apps/location/migrations/0011_country_language.py +++ b/apps/location/migrations/0011_country_languages.py @@ -1,4 +1,4 @@ -# Generated by Django 2.2.4 on 2019-10-10 11:34 +# Generated by Django 2.2.4 on 2019-10-10 12:22 from django.db import migrations, models @@ -13,7 +13,7 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( model_name='country', - name='language', - field=models.ManyToManyField(to='translation.Language', verbose_name='Language'), + name='languages', + field=models.ManyToManyField(to='translation.Language', verbose_name='Languages'), ), ] diff --git a/apps/location/migrations/0012_auto_20191010_1205.py b/apps/location/migrations/0012_auto_20191010_1205.py deleted file mode 100644 index a2de2917..00000000 --- a/apps/location/migrations/0012_auto_20191010_1205.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.2.4 on 2019-10-10 12:05 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('location', '0011_country_language'), - ] - - operations = [ - migrations.RenameField( - model_name='country', - old_name='language', - new_name='languages', - ), - ] From b390b1af26d707092bf9d6e9c18168baddcecfb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Thu, 10 Oct 2019 16:00:23 +0300 Subject: [PATCH 10/14] Fix --- apps/comment/permissions.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/comment/permissions.py b/apps/comment/permissions.py index 9e0ab58b..9dacced4 100644 --- a/apps/comment/permissions.py +++ b/apps/comment/permissions.py @@ -14,11 +14,10 @@ class IsCommentModerator(permissions.BasePermission): if request.method in permissions.SAFE_METHODS: return True # # user owner is user request - # if obj.user == request.user: - # return True + if obj.user == request.user: + return True # Must have role - # ,country__languages__id=obj.language_id role = Role.objects.filter(role=2, country__languages__id=obj.language_id)\ .first() # 'Comments moderator' From a6c56a4bf1d2c468a890fdc6b0effa114c6ab86b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Fri, 11 Oct 2019 14:49:32 +0300 Subject: [PATCH 11/14] Fix and refactor --- apps/account/admin.py | 1 - ...userrole.py => 0009_auto_20191011_1123.py} | 13 +++---- .../migrations/0010_auto_20191008_0751.py | 29 ---------------- apps/account/models.py | 34 +++++++++++-------- apps/comment/permissions.py | 15 +++----- apps/comment/views/back.py | 4 ++- apps/location/models.py | 1 + .../migrations/0003_auto_20191004_0928.py | 17 ---------- .../migrations/0004_merge_20191009_1341.py | 14 -------- 9 files changed, 36 insertions(+), 92 deletions(-) rename apps/account/migrations/{0009_role_userrole.py => 0009_auto_20191011_1123.py} (80%) delete mode 100644 apps/account/migrations/0010_auto_20191008_0751.py delete mode 100644 apps/timetable/migrations/0003_auto_20191004_0928.py delete mode 100644 apps/timetable/migrations/0004_merge_20191009_1341.py diff --git a/apps/account/admin.py b/apps/account/admin.py index a89e6693..3b247289 100644 --- a/apps/account/admin.py +++ b/apps/account/admin.py @@ -2,7 +2,6 @@ from django.contrib import admin from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.utils.translation import ugettext_lazy as _ - from account import models diff --git a/apps/account/migrations/0009_role_userrole.py b/apps/account/migrations/0009_auto_20191011_1123.py similarity index 80% rename from apps/account/migrations/0009_role_userrole.py rename to apps/account/migrations/0009_auto_20191011_1123.py index e162bfe5..f1ec87f9 100644 --- a/apps/account/migrations/0009_role_userrole.py +++ b/apps/account/migrations/0009_auto_20191011_1123.py @@ -1,4 +1,4 @@ -# Generated by Django 2.2.4 on 2019-10-08 07:17 +# Generated by Django 2.2.4 on 2019-10-11 11:23 from django.conf import settings from django.db import migrations, models @@ -9,7 +9,7 @@ import django.utils.timezone class Migration(migrations.Migration): dependencies = [ - ('location', '0010_auto_20190904_0711'), + ('location', '0011_country_languages'), ('account', '0008_auto_20190912_1325'), ] @@ -21,10 +21,6 @@ class Migration(migrations.Migration): ('created', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date created')), ('modified', models.DateTimeField(auto_now=True, verbose_name='Date updated')), ('role', models.PositiveIntegerField(choices=[(1, 'Standard user'), (2, 'Comments moderator')], verbose_name='Role')), - ('is_list', models.BooleanField(default=True, verbose_name='list')), - ('is_create', models.BooleanField(default=False, verbose_name='create')), - ('is_update', models.BooleanField(default=False, verbose_name='update')), - ('is_delete', models.BooleanField(default=False, verbose_name='delete')), ('country', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='location.Country', verbose_name='Country')), ], options={ @@ -44,4 +40,9 @@ class Migration(migrations.Migration): 'abstract': False, }, ), + migrations.AddField( + model_name='user', + name='roles', + field=models.ManyToManyField(through='account.UserRole', to='account.Role', verbose_name='Roles'), + ), ] diff --git a/apps/account/migrations/0010_auto_20191008_0751.py b/apps/account/migrations/0010_auto_20191008_0751.py deleted file mode 100644 index 289f8643..00000000 --- a/apps/account/migrations/0010_auto_20191008_0751.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 2.2.4 on 2019-10-08 07:51 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('account', '0009_role_userrole'), - ] - - operations = [ - migrations.RemoveField( - model_name='role', - name='is_create', - ), - migrations.RemoveField( - model_name='role', - name='is_delete', - ), - migrations.RemoveField( - model_name='role', - name='is_list', - ), - migrations.RemoveField( - model_name='role', - name='is_update', - ), - ] diff --git a/apps/account/models.py b/apps/account/models.py index c7de88e3..206f5e02 100644 --- a/apps/account/models.py +++ b/apps/account/models.py @@ -19,6 +19,24 @@ from utils.models import ImageMixin, ProjectBaseMixin, PlatformMixin from utils.tokens import GMRefreshToken +class Role(ProjectBaseMixin): + """Base Role model.""" + STANDARD_USER = 1 + COMMENTS_MODERATOR = 2 + + ROLE_CHOICES =( + (STANDARD_USER, 'Standard user'), + (COMMENTS_MODERATOR, 'Comments moderator'), + ) + role = models.PositiveIntegerField(verbose_name=_('Role'), choices=ROLE_CHOICES, + null=False, blank=False) + country = models.ForeignKey(Country, verbose_name=_('Country'), on_delete=models.CASCADE) + # 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) + # is_delete = models.BooleanField(verbose_name=_('delete'), default=False, null=False) + + class UserManager(BaseUserManager): """Extended manager for User model.""" @@ -68,6 +86,7 @@ class User(AbstractUser): USERNAME_FIELD = 'username' REQUIRED_FIELDS = ['email'] + roles = models.ManyToManyField(Role, verbose_name=_('Roles'), through='UserRole') objects = UserManager.from_queryset(UserQuerySet)() class Meta: @@ -198,20 +217,7 @@ class User(AbstractUser): context=context) -class Role(ProjectBaseMixin): - ROLE_CHOICES =( - (1, 'Standard user'), - (2, 'Comments moderator'), - ) - role = models.PositiveIntegerField(verbose_name=_('Role'), choices=ROLE_CHOICES, - null=False, blank=False) - country = models.ForeignKey(Country, verbose_name=_('Country'), on_delete=models.CASCADE) - # 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) - # is_delete = models.BooleanField(verbose_name=_('delete'), default=False, null=False) - - 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) \ No newline at end of file diff --git a/apps/comment/permissions.py b/apps/comment/permissions.py index 9dacced4..6d691c07 100644 --- a/apps/comment/permissions.py +++ b/apps/comment/permissions.py @@ -2,7 +2,7 @@ from rest_framework import permissions from account.models import UserRole, Role, User -class IsCommentModerator(permissions.BasePermission): +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. @@ -11,23 +11,18 @@ class IsCommentModerator(permissions.BasePermission): 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: - return True - # # user owner is user request - if obj.user == request.user: + 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=2, + 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 - super_user = User.objects.filter(pk=request.user.pk, is_superuser=True).exists() - if super_user: - return True - return False diff --git a/apps/comment/views/back.py b/apps/comment/views/back.py index 16450d03..77edfa97 100644 --- a/apps/comment/views/back.py +++ b/apps/comment/views/back.py @@ -5,13 +5,15 @@ from comment.permissions import IsCommentModerator class CommentLstView(generics.ListCreateAPIView): + """Comment list create view.""" serializer_class = serializers.CommentBaseSerializer queryset = models.Comment.objects.all() permission_classes = [permissions.IsAuthenticatedOrReadOnly,] class CommentRUDView(generics.RetrieveUpdateDestroyAPIView): + """Comment RUD view.""" serializer_class = serializers.CommentBaseSerializer queryset = models.Comment.objects.all() - permission_classes = [permissions.IsAuthenticatedOrReadOnly,IsCommentModerator] + permission_classes = [IsCommentModerator] lookup_field = 'id' diff --git a/apps/location/models.py b/apps/location/models.py index f52f9fee..2298c28e 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -8,6 +8,7 @@ from django.utils.translation import gettext_lazy as _ from utils.models import ProjectBaseMixin, SVGImageMixin, TranslatedFieldsMixin, TJSONField from translation.models import Language + class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin): """Country model.""" diff --git a/apps/timetable/migrations/0003_auto_20191004_0928.py b/apps/timetable/migrations/0003_auto_20191004_0928.py deleted file mode 100644 index 6e82c679..00000000 --- a/apps/timetable/migrations/0003_auto_20191004_0928.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 2.2.4 on 2019-10-04 09:28 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('timetable', '0002_auto_20190919_1124'), - ] - - operations = [ - migrations.AlterModelOptions( - name='timetable', - options={'ordering': ['weekday'], 'verbose_name': 'Timetable', 'verbose_name_plural': 'Timetables'}, - ), - ] diff --git a/apps/timetable/migrations/0004_merge_20191009_1341.py b/apps/timetable/migrations/0004_merge_20191009_1341.py deleted file mode 100644 index 22d83ca3..00000000 --- a/apps/timetable/migrations/0004_merge_20191009_1341.py +++ /dev/null @@ -1,14 +0,0 @@ -# Generated by Django 2.2.4 on 2019-10-09 13:41 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('timetable', '0003_auto_20191004_0928'), - ('timetable', '0003_auto_20191003_0943'), - ] - - operations = [ - ] From f441896d6a122bce23cf38b65a14c87920775593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Fri, 11 Oct 2019 16:00:23 +0300 Subject: [PATCH 12/14] Migrate data --- apps/location/migrations/0012_data_migrate.py | 20 + apps/location/migrations/migrate_lang.sql | 390 ++++++++++++++++++ 2 files changed, 410 insertions(+) create mode 100644 apps/location/migrations/0012_data_migrate.py create mode 100644 apps/location/migrations/migrate_lang.sql diff --git a/apps/location/migrations/0012_data_migrate.py b/apps/location/migrations/0012_data_migrate.py new file mode 100644 index 00000000..8b638404 --- /dev/null +++ b/apps/location/migrations/0012_data_migrate.py @@ -0,0 +1,20 @@ +# Generated by Django 2.2.4 on 2019-09-01 10:32 + +from django.db import migrations, connection +import os + + +class Migration(migrations.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() + with connection.cursor() as c: + c.execute(sql_statement) + + dependencies = [ + ('location', '0011_country_languages'), + ] + + operations = [ + migrations.RunPython(load_data_from_sql), + ] diff --git a/apps/location/migrations/migrate_lang.sql b/apps/location/migrations/migrate_lang.sql new file mode 100644 index 00000000..409e7bf3 --- /dev/null +++ b/apps/location/migrations/migrate_lang.sql @@ -0,0 +1,390 @@ +delete from comment_comment as cc; +delete from location_country_languages; +delete from translation_language as tl; +delete from location_country as lc; + +CREATE TABLE public.codelang ( + code varchar(100) NULL, + country varchar(10000) NULL +); + +-- Permissions + +ALTER TABLE public.codelang OWNER TO postgres; +GRANT ALL ON TABLE public.codelang TO postgres; + + +INSERT INTO public.codelang (code,country) VALUES +('af','Afrikaans') +,('af-ZA','Afrikaans (South Africa)') +,('ar','Arabic') +,('ar-AE','Arabic (U.A.E.)') +,('ar-BH','Arabic (Bahrain)') +,('ar-DZ','Arabic (Algeria)') +,('ar-EG','Arabic (Egypt)') +,('ar-IQ','Arabic (Iraq)') +,('ar-JO','Arabic (Jordan)') +,('ar-KW','Arabic (Kuwait)') +; +INSERT INTO public.codelang (code,country) VALUES +('ar-LB','Arabic (Lebanon)') +,('ar-LY','Arabic (Libya)') +,('ar-MA','Arabic (Morocco)') +,('ar-OM','Arabic (Oman)') +,('ar-QA','Arabic (Qatar)') +,('ar-SA','Arabic (Saudi Arabia)') +,('ar-SY','Arabic (Syria)') +,('ar-TN','Arabic (Tunisia)') +,('ar-YE','Arabic (Yemen)') +,('az','Azeri (Latin)') +; +INSERT INTO public.codelang (code,country) VALUES +('az-AZ','Azeri (Latin) (Azerbaijan)') +,('az-AZ','Azeri (Cyrillic) (Azerbaijan)') +,('be','Belarusian') +,('be-BY','Belarusian (Belarus)') +,('bg','Bulgarian') +,('bg-BG','Bulgarian (Bulgaria)') +,('bs-BA','Bosnian (Bosnia and Herzegovina)') +,('ca','Catalan') +,('ca-ES','Catalan (Spain)') +,('cs','Czech') +; +INSERT INTO public.codelang (code,country) VALUES +('cs-CZ','Czech (Czech Republic)') +,('cy','Welsh') +,('cy-GB','Welsh (United Kingdom)') +,('da','Danish') +,('da-DK','Danish (Denmark)') +,('de','German') +,('de-AT','German (Austria)') +,('de-CH','German (Switzerland)') +,('de-DE','German (Germany)') +,('de-LI','German (Liechtenstein)') +; +INSERT INTO public.codelang (code,country) VALUES +('de-LU','German (Luxembourg)') +,('dv','Divehi') +,('dv-MV','Divehi (Maldives)') +,('el','Greek') +,('el-GR','Greek (Greece)') +,('en','English') +,('en-AU','English (Australia)') +,('en-BZ','English (Belize)') +,('en-CA','English (Canada)') +,('en-CB','English (Caribbean)') +; +INSERT INTO public.codelang (code,country) VALUES +('en-GB','English (United Kingdom)') +,('en-IE','English (Ireland)') +,('en-JM','English (Jamaica)') +,('en-NZ','English (New Zealand)') +,('en-PH','English (Republic of the Philippines)') +,('en-TT','English (Trinidad and Tobago)') +,('en-US','English (United States)') +,('en-ZA','English (South Africa)') +,('en-ZW','English (Zimbabwe)') +,('eo','Esperanto') +; +INSERT INTO public.codelang (code,country) VALUES +('es','Spanish') +,('es-AR','Spanish (Argentina)') +,('es-BO','Spanish (Bolivia)') +,('es-CL','Spanish (Chile)') +,('es-CO','Spanish (Colombia)') +,('es-CR','Spanish (Costa Rica)') +,('es-DO','Spanish (Dominican Republic)') +,('es-EC','Spanish (Ecuador)') +,('es-ES','Spanish (Castilian)') +,('es-ES','Spanish (Spain)') +; +INSERT INTO public.codelang (code,country) VALUES +('es-GT','Spanish (Guatemala)') +,('es-HN','Spanish (Honduras)') +,('es-MX','Spanish (Mexico)') +,('es-NI','Spanish (Nicaragua)') +,('es-PA','Spanish (Panama)') +,('es-PE','Spanish (Peru)') +,('es-PR','Spanish (Puerto Rico)') +,('es-PY','Spanish (Paraguay)') +,('es-SV','Spanish (El Salvador)') +,('es-UY','Spanish (Uruguay)') +; +INSERT INTO public.codelang (code,country) VALUES +('es-VE','Spanish (Venezuela)') +,('et','Estonian') +,('et-EE','Estonian (Estonia)') +,('eu','Basque') +,('eu-ES','Basque (Spain)') +,('fa','Farsi') +,('fa-IR','Farsi (Iran)') +,('fi','Finnish') +,('fi-FI','Finnish (Finland)') +,('fo','Faroese') +; +INSERT INTO public.codelang (code,country) VALUES +('fo-FO','Faroese (Faroe Islands)') +,('fr','French') +,('fr-BE','French (Belgium)') +,('fr-CA','French (Canada)') +,('fr-CH','French (Switzerland)') +,('fr-FR','French (France)') +,('fr-LU','French (Luxembourg)') +,('fr-MC','French (Principality of Monaco)') +,('gl','Galician') +,('gl-ES','Galician (Spain)') +; +INSERT INTO public.codelang (code,country) VALUES +('gu','Gujarati') +,('gu-IN','Gujarati (India)') +,('he','Hebrew') +,('he-IL','Hebrew (Israel)') +,('hi','Hindi') +,('hi-IN','Hindi (India)') +,('hr','Croatian') +,('hr-BA','Croatian (Bosnia and Herzegovina)') +,('hr-HR','Croatian (Croatia)') +,('hu','Hungarian') +; +INSERT INTO public.codelang (code,country) VALUES +('hu-HU','Hungarian (Hungary)') +,('hy','Armenian') +,('hy-AM','Armenian (Armenia)') +,('id','Indonesian') +,('id-ID','Indonesian (Indonesia)') +,('is','Icelandic') +,('is-IS','Icelandic (Iceland)') +,('it','Italian') +,('it-CH','Italian (Switzerland)') +,('it-IT','Italian (Italy)') +; +INSERT INTO public.codelang (code,country) VALUES +('ja','Japanese') +,('ja-JP','Japanese (Japan)') +,('ka','Georgian') +,('ka-GE','Georgian (Georgia)') +,('kk','Kazakh') +,('kk-KZ','Kazakh (Kazakhstan)') +,('kn','Kannada') +,('kn-IN','Kannada (India)') +,('ko','Korean') +,('ko-KR','Korean (Korea)') +; +INSERT INTO public.codelang (code,country) VALUES +('kok','Konkani') +,('kok-IN','Konkani (India)') +,('ky','Kyrgyz') +,('ky-KG','Kyrgyz (Kyrgyzstan)') +,('lt','Lithuanian') +,('lt-LT','Lithuanian (Lithuania)') +,('lv','Latvian') +,('lv-LV','Latvian (Latvia)') +,('mi','Maori') +,('mi-NZ','Maori (New Zealand)') +; +INSERT INTO public.codelang (code,country) VALUES +('mk','FYRO Macedonian') +,('mk-MK','FYRO Macedonian (Former Yugoslav Republic of Macedonia)') +,('mn','Mongolian') +,('mn-MN','Mongolian (Mongolia)') +,('mr','Marathi') +,('mr-IN','Marathi (India)') +,('ms','Malay') +,('ms-BN','Malay (Brunei Darussalam)') +,('ms-MY','Malay (Malaysia)') +,('mt','Maltese') +; +INSERT INTO public.codelang (code,country) VALUES +('mt-MT','Maltese (Malta)') +,('nb','Norwegian (Bokm?l)') +,('nb-NO','Norwegian (Bokm?l) (Norway)') +,('nl','Dutch') +,('nl-BE','Dutch (Belgium)') +,('nl-NL','Dutch (Netherlands)') +,('nn-NO','Norwegian (Nynorsk) (Norway)') +,('ns','Northern Sotho') +,('ns-ZA','Northern Sotho (South Africa)') +,('pa','Punjabi') +; +INSERT INTO public.codelang (code,country) VALUES +('pa-IN','Punjabi (India)') +,('pl','Polish') +,('pl-PL','Polish (Poland)') +,('ps','Pashto') +,('ps-AR','Pashto (Afghanistan)') +,('pt','Portuguese') +,('pt-BR','Portuguese (Brazil)') +,('pt-PT','Portuguese (Portugal)') +,('qu','Quechua') +,('qu-BO','Quechua (Bolivia)') +; +INSERT INTO public.codelang (code,country) VALUES +('qu-EC','Quechua (Ecuador)') +,('qu-PE','Quechua (Peru)') +,('ro','Romanian') +,('ro-RO','Romanian (Romania)') +,('ru','Russian') +,('ru-RU','Russian (Russia)') +,('sa','Sanskrit') +,('sa-IN','Sanskrit (India)') +,('se','Sami (Northern)') +,('se-FI','Sami (Northern) (Finland)') +; +INSERT INTO public.codelang (code,country) VALUES +('se-FI','Sami (Skolt) (Finland)') +,('se-FI','Sami (Inari) (Finland)') +,('se-NO','Sami (Northern) (Norway)') +,('se-NO','Sami (Lule) (Norway)') +,('se-NO','Sami (Southern) (Norway)') +,('se-SE','Sami (Northern) (Sweden)') +,('se-SE','Sami (Lule) (Sweden)') +,('se-SE','Sami (Southern) (Sweden)') +,('sk','Slovak') +,('sk-SK','Slovak (Slovakia)') +; +INSERT INTO public.codelang (code,country) VALUES +('sl','Slovenian') +,('sl-SI','Slovenian (Slovenia)') +,('sq','Albanian') +,('sq-AL','Albanian (Albania)') +,('sr-BA','Serbian (Latin) (Bosnia and Herzegovina)') +,('sr-BA','Serbian (Cyrillic) (Bosnia and Herzegovina)') +,('sr-SP','Serbian (Latin) (Serbia and Montenegro)') +,('sr-SP','Serbian (Cyrillic) (Serbia and Montenegro)') +,('sv','Swedish') +,('sv-FI','Swedish (Finland)') +; +INSERT INTO public.codelang (code,country) VALUES +('sv-SE','Swedish (Sweden)') +,('sw','Swahili') +,('sw-KE','Swahili (Kenya)') +,('syr','Syriac') +,('syr-SY','Syriac (Syria)') +,('ta','Tamil') +,('ta-IN','Tamil (India)') +,('te','Telugu') +,('te-IN','Telugu (India)') +,('th','Thai') +; +INSERT INTO public.codelang (code,country) VALUES +('th-TH','Thai (Thailand)') +,('tl','Tagalog') +,('tl-PH','Tagalog (Philippines)') +,('tn','Tswana') +,('tn-ZA','Tswana (South Africa)') +,('tr','Turkish') +,('tr-TR','Turkish (Turkey)') +,('tt','Tatar') +,('tt-RU','Tatar (Russia)') +,('ts','Tsonga') +; +INSERT INTO public.codelang (code,country) VALUES +('uk','Ukrainian') +,('uk-UA','Ukrainian (Ukraine)') +,('ur','Urdu') +,('ur-PK','Urdu (Islamic Republic of Pakistan)') +,('uz','Uzbek (Latin)') +,('uz-UZ','Uzbek (Latin) (Uzbekistan)') +,('uz-UZ','Uzbek (Cyrillic) (Uzbekistan)') +,('vi','Vietnamese') +,('vi-VN','Vietnamese (Viet Nam)') +,('xh','Xhosa') +; +INSERT INTO public.codelang (code,country) VALUES +('xh-ZA','Xhosa (South Africa)') +,('zh','Chinese') +,('zh-CN','Chinese (S)') +,('zh-HK','Chinese (Hong Kong)') +,('zh-MO','Chinese (Macau)') +,('zh-SG','Chinese (Singapore)') +,('zh-TW','Chinese (T)') +,('zu','Zulu') +,('zu-ZA','Zulu (South Africa)') +; +/***************************/ +-- Manual migrate + +CREATE TABLE public.country_code ( + code varchar(100) NULL, + country varchar(10000) NULL +); + +insert into country_code(code, country) +select distinct + t.code, + coalesce( + case when length(t.country_name2) = 1 then null else t.country_name2 end, + case when length(t.contry_name1) = 1 then null else t.contry_name1 end, + t.country + ) as country +from +( + select trim(c.code) as code, + substring(trim(c.country) from '\((.+)\)') as contry_name1, + substring( + substring(trim(c.country) from '\((.+)\)') + from '\((.*)$') as country_name2, + trim(c.country) as country + from codelang as c +) t; + +commit; + +--delete from location_country as lc + +INSERT INTO public.location_country +(code, "name", low_price, high_price, created, modified) +select + 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, + 100 as high_price, + now() as created, + now() as modified +from +( + select + distinct c.country + from country_code c +) t +; + +commit; + +--delete from translation_language as tl; + +INSERT INTO public.translation_language +(title, locale) +select + t.country as title, + t.code as locale +from +( + select + distinct c.country, c.code + from country_code c +) t +; + +commit; + + +--delete from location_country_languages + +INSERT INTO public.location_country_languages +(country_id, language_id) +select lc.id as country_id, + l.id as language_id +from location_country as lc +join ( + select tl.*, '"'||tl.title||'"' as country + from translation_language as tl +) l on l.country = (lc."name"::json->'en-GB')::text +; + +commit; + +drop table country_code; +drop table codelang; + +commit; \ No newline at end of file From e9ad418976a6f371dbb7f32955b71f5f560c8d62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Fri, 11 Oct 2019 16:57:59 +0300 Subject: [PATCH 13/14] Revert migrate location --- apps/location/migrations/0012_data_migrate.py | 12 +- apps/location/migrations/remigrate_lang.sql | 394 ++++++++++++++++++ 2 files changed, 403 insertions(+), 3 deletions(-) create mode 100644 apps/location/migrations/remigrate_lang.sql diff --git a/apps/location/migrations/0012_data_migrate.py b/apps/location/migrations/0012_data_migrate.py index 8b638404..d32454bf 100644 --- a/apps/location/migrations/0012_data_migrate.py +++ b/apps/location/migrations/0012_data_migrate.py @@ -1,20 +1,26 @@ -# Generated by Django 2.2.4 on 2019-09-01 10:32 - from django.db import migrations, connection import os class Migration(migrations.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() with connection.cursor() as c: c.execute(sql_statement) + def revert_data(apps, schema_editor): + file_path = os.path.join(os.path.dirname(__file__), 'remigrate_lang.sql') + sql_statement = open(file_path).read() + with connection.cursor() as c: + c.execute(sql_statement) + dependencies = [ ('location', '0011_country_languages'), ] operations = [ - migrations.RunPython(load_data_from_sql), + migrations.RunPython(load_data_from_sql, revert_data), + # migrations.RunPython(load_data_from_sql, revert_data), ] diff --git a/apps/location/migrations/remigrate_lang.sql b/apps/location/migrations/remigrate_lang.sql new file mode 100644 index 00000000..910dfcfa --- /dev/null +++ b/apps/location/migrations/remigrate_lang.sql @@ -0,0 +1,394 @@ +CREATE TABLE public.codelang ( + code varchar(100) NULL, + country varchar(10000) NULL +); + +-- Permissions + +ALTER TABLE public.codelang OWNER TO postgres; +GRANT ALL ON TABLE public.codelang TO postgres; + + +INSERT INTO public.codelang (code,country) VALUES +('af','Afrikaans') +,('af-ZA','Afrikaans (South Africa)') +,('ar','Arabic') +,('ar-AE','Arabic (U.A.E.)') +,('ar-BH','Arabic (Bahrain)') +,('ar-DZ','Arabic (Algeria)') +,('ar-EG','Arabic (Egypt)') +,('ar-IQ','Arabic (Iraq)') +,('ar-JO','Arabic (Jordan)') +,('ar-KW','Arabic (Kuwait)') +; +INSERT INTO public.codelang (code,country) VALUES +('ar-LB','Arabic (Lebanon)') +,('ar-LY','Arabic (Libya)') +,('ar-MA','Arabic (Morocco)') +,('ar-OM','Arabic (Oman)') +,('ar-QA','Arabic (Qatar)') +,('ar-SA','Arabic (Saudi Arabia)') +,('ar-SY','Arabic (Syria)') +,('ar-TN','Arabic (Tunisia)') +,('ar-YE','Arabic (Yemen)') +,('az','Azeri (Latin)') +; +INSERT INTO public.codelang (code,country) VALUES +('az-AZ','Azeri (Latin) (Azerbaijan)') +,('az-AZ','Azeri (Cyrillic) (Azerbaijan)') +,('be','Belarusian') +,('be-BY','Belarusian (Belarus)') +,('bg','Bulgarian') +,('bg-BG','Bulgarian (Bulgaria)') +,('bs-BA','Bosnian (Bosnia and Herzegovina)') +,('ca','Catalan') +,('ca-ES','Catalan (Spain)') +,('cs','Czech') +; +INSERT INTO public.codelang (code,country) VALUES +('cs-CZ','Czech (Czech Republic)') +,('cy','Welsh') +,('cy-GB','Welsh (United Kingdom)') +,('da','Danish') +,('da-DK','Danish (Denmark)') +,('de','German') +,('de-AT','German (Austria)') +,('de-CH','German (Switzerland)') +,('de-DE','German (Germany)') +,('de-LI','German (Liechtenstein)') +; +INSERT INTO public.codelang (code,country) VALUES +('de-LU','German (Luxembourg)') +,('dv','Divehi') +,('dv-MV','Divehi (Maldives)') +,('el','Greek') +,('el-GR','Greek (Greece)') +,('en','English') +,('en-AU','English (Australia)') +,('en-BZ','English (Belize)') +,('en-CA','English (Canada)') +,('en-CB','English (Caribbean)') +; +INSERT INTO public.codelang (code,country) VALUES +('en-GB','English (United Kingdom)') +,('en-IE','English (Ireland)') +,('en-JM','English (Jamaica)') +,('en-NZ','English (New Zealand)') +,('en-PH','English (Republic of the Philippines)') +,('en-TT','English (Trinidad and Tobago)') +,('en-US','English (United States)') +,('en-ZA','English (South Africa)') +,('en-ZW','English (Zimbabwe)') +,('eo','Esperanto') +; +INSERT INTO public.codelang (code,country) VALUES +('es','Spanish') +,('es-AR','Spanish (Argentina)') +,('es-BO','Spanish (Bolivia)') +,('es-CL','Spanish (Chile)') +,('es-CO','Spanish (Colombia)') +,('es-CR','Spanish (Costa Rica)') +,('es-DO','Spanish (Dominican Republic)') +,('es-EC','Spanish (Ecuador)') +,('es-ES','Spanish (Castilian)') +,('es-ES','Spanish (Spain)') +; +INSERT INTO public.codelang (code,country) VALUES +('es-GT','Spanish (Guatemala)') +,('es-HN','Spanish (Honduras)') +,('es-MX','Spanish (Mexico)') +,('es-NI','Spanish (Nicaragua)') +,('es-PA','Spanish (Panama)') +,('es-PE','Spanish (Peru)') +,('es-PR','Spanish (Puerto Rico)') +,('es-PY','Spanish (Paraguay)') +,('es-SV','Spanish (El Salvador)') +,('es-UY','Spanish (Uruguay)') +; +INSERT INTO public.codelang (code,country) VALUES +('es-VE','Spanish (Venezuela)') +,('et','Estonian') +,('et-EE','Estonian (Estonia)') +,('eu','Basque') +,('eu-ES','Basque (Spain)') +,('fa','Farsi') +,('fa-IR','Farsi (Iran)') +,('fi','Finnish') +,('fi-FI','Finnish (Finland)') +,('fo','Faroese') +; +INSERT INTO public.codelang (code,country) VALUES +('fo-FO','Faroese (Faroe Islands)') +,('fr','French') +,('fr-BE','French (Belgium)') +,('fr-CA','French (Canada)') +,('fr-CH','French (Switzerland)') +,('fr-FR','French (France)') +,('fr-LU','French (Luxembourg)') +,('fr-MC','French (Principality of Monaco)') +,('gl','Galician') +,('gl-ES','Galician (Spain)') +; +INSERT INTO public.codelang (code,country) VALUES +('gu','Gujarati') +,('gu-IN','Gujarati (India)') +,('he','Hebrew') +,('he-IL','Hebrew (Israel)') +,('hi','Hindi') +,('hi-IN','Hindi (India)') +,('hr','Croatian') +,('hr-BA','Croatian (Bosnia and Herzegovina)') +,('hr-HR','Croatian (Croatia)') +,('hu','Hungarian') +; +INSERT INTO public.codelang (code,country) VALUES +('hu-HU','Hungarian (Hungary)') +,('hy','Armenian') +,('hy-AM','Armenian (Armenia)') +,('id','Indonesian') +,('id-ID','Indonesian (Indonesia)') +,('is','Icelandic') +,('is-IS','Icelandic (Iceland)') +,('it','Italian') +,('it-CH','Italian (Switzerland)') +,('it-IT','Italian (Italy)') +; +INSERT INTO public.codelang (code,country) VALUES +('ja','Japanese') +,('ja-JP','Japanese (Japan)') +,('ka','Georgian') +,('ka-GE','Georgian (Georgia)') +,('kk','Kazakh') +,('kk-KZ','Kazakh (Kazakhstan)') +,('kn','Kannada') +,('kn-IN','Kannada (India)') +,('ko','Korean') +,('ko-KR','Korean (Korea)') +; +INSERT INTO public.codelang (code,country) VALUES +('kok','Konkani') +,('kok-IN','Konkani (India)') +,('ky','Kyrgyz') +,('ky-KG','Kyrgyz (Kyrgyzstan)') +,('lt','Lithuanian') +,('lt-LT','Lithuanian (Lithuania)') +,('lv','Latvian') +,('lv-LV','Latvian (Latvia)') +,('mi','Maori') +,('mi-NZ','Maori (New Zealand)') +; +INSERT INTO public.codelang (code,country) VALUES +('mk','FYRO Macedonian') +,('mk-MK','FYRO Macedonian (Former Yugoslav Republic of Macedonia)') +,('mn','Mongolian') +,('mn-MN','Mongolian (Mongolia)') +,('mr','Marathi') +,('mr-IN','Marathi (India)') +,('ms','Malay') +,('ms-BN','Malay (Brunei Darussalam)') +,('ms-MY','Malay (Malaysia)') +,('mt','Maltese') +; +INSERT INTO public.codelang (code,country) VALUES +('mt-MT','Maltese (Malta)') +,('nb','Norwegian (Bokm?l)') +,('nb-NO','Norwegian (Bokm?l) (Norway)') +,('nl','Dutch') +,('nl-BE','Dutch (Belgium)') +,('nl-NL','Dutch (Netherlands)') +,('nn-NO','Norwegian (Nynorsk) (Norway)') +,('ns','Northern Sotho') +,('ns-ZA','Northern Sotho (South Africa)') +,('pa','Punjabi') +; +INSERT INTO public.codelang (code,country) VALUES +('pa-IN','Punjabi (India)') +,('pl','Polish') +,('pl-PL','Polish (Poland)') +,('ps','Pashto') +,('ps-AR','Pashto (Afghanistan)') +,('pt','Portuguese') +,('pt-BR','Portuguese (Brazil)') +,('pt-PT','Portuguese (Portugal)') +,('qu','Quechua') +,('qu-BO','Quechua (Bolivia)') +; +INSERT INTO public.codelang (code,country) VALUES +('qu-EC','Quechua (Ecuador)') +,('qu-PE','Quechua (Peru)') +,('ro','Romanian') +,('ro-RO','Romanian (Romania)') +,('ru','Russian') +,('ru-RU','Russian (Russia)') +,('sa','Sanskrit') +,('sa-IN','Sanskrit (India)') +,('se','Sami (Northern)') +,('se-FI','Sami (Northern) (Finland)') +; +INSERT INTO public.codelang (code,country) VALUES +('se-FI','Sami (Skolt) (Finland)') +,('se-FI','Sami (Inari) (Finland)') +,('se-NO','Sami (Northern) (Norway)') +,('se-NO','Sami (Lule) (Norway)') +,('se-NO','Sami (Southern) (Norway)') +,('se-SE','Sami (Northern) (Sweden)') +,('se-SE','Sami (Lule) (Sweden)') +,('se-SE','Sami (Southern) (Sweden)') +,('sk','Slovak') +,('sk-SK','Slovak (Slovakia)') +; +INSERT INTO public.codelang (code,country) VALUES +('sl','Slovenian') +,('sl-SI','Slovenian (Slovenia)') +,('sq','Albanian') +,('sq-AL','Albanian (Albania)') +,('sr-BA','Serbian (Latin) (Bosnia and Herzegovina)') +,('sr-BA','Serbian (Cyrillic) (Bosnia and Herzegovina)') +,('sr-SP','Serbian (Latin) (Serbia and Montenegro)') +,('sr-SP','Serbian (Cyrillic) (Serbia and Montenegro)') +,('sv','Swedish') +,('sv-FI','Swedish (Finland)') +; +INSERT INTO public.codelang (code,country) VALUES +('sv-SE','Swedish (Sweden)') +,('sw','Swahili') +,('sw-KE','Swahili (Kenya)') +,('syr','Syriac') +,('syr-SY','Syriac (Syria)') +,('ta','Tamil') +,('ta-IN','Tamil (India)') +,('te','Telugu') +,('te-IN','Telugu (India)') +,('th','Thai') +; +INSERT INTO public.codelang (code,country) VALUES +('th-TH','Thai (Thailand)') +,('tl','Tagalog') +,('tl-PH','Tagalog (Philippines)') +,('tn','Tswana') +,('tn-ZA','Tswana (South Africa)') +,('tr','Turkish') +,('tr-TR','Turkish (Turkey)') +,('tt','Tatar') +,('tt-RU','Tatar (Russia)') +,('ts','Tsonga') +; +INSERT INTO public.codelang (code,country) VALUES +('uk','Ukrainian') +,('uk-UA','Ukrainian (Ukraine)') +,('ur','Urdu') +,('ur-PK','Urdu (Islamic Republic of Pakistan)') +,('uz','Uzbek (Latin)') +,('uz-UZ','Uzbek (Latin) (Uzbekistan)') +,('uz-UZ','Uzbek (Cyrillic) (Uzbekistan)') +,('vi','Vietnamese') +,('vi-VN','Vietnamese (Viet Nam)') +,('xh','Xhosa') +; +INSERT INTO public.codelang (code,country) VALUES +('xh-ZA','Xhosa (South Africa)') +,('zh','Chinese') +,('zh-CN','Chinese (S)') +,('zh-HK','Chinese (Hong Kong)') +,('zh-MO','Chinese (Macau)') +,('zh-SG','Chinese (Singapore)') +,('zh-TW','Chinese (T)') +,('zu','Zulu') +,('zu-ZA','Zulu (South Africa)') +; +/***************************/ +-- Manual migrate + +CREATE TABLE public.country_code ( + code varchar(100) NULL, + country varchar(10000) NULL +); + +insert into country_code(code, country) +select distinct + t.code, + coalesce( + case when length(t.country_name2) = 1 then null else t.country_name2 end, + case when length(t.contry_name1) = 1 then null else t.contry_name1 end, + t.country + ) as country +from +( + select trim(c.code) as code, + substring(trim(c.country) from '\((.+)\)') as contry_name1, + substring( + substring(trim(c.country) from '\((.+)\)') + from '\((.*)$') as country_name2, + trim(c.country) as country + from codelang as c +) t; + +commit; + + +delete from location_country_languages as lcl +where lcl.country_id in +( + select + lc.id + from + ( + select + lpad((row_number() over (order by t.country asc))::text, 3, '0') as code, + jsonb_build_object('en-GB', t.country) as "name" + from + ( + select + distinct c.country + from country_code c + ) t + ) d + join location_country lc on lc.code = d.code and d."name"=lc."name" +) +; +commit; + + +delete from location_country as lcl +where lcl.id in +( + select + lc.id + from + ( + select + lpad((row_number() over (order by t.country asc))::text, 3, '0') as code, + jsonb_build_object('en-GB', t.country) as "name" + from + ( + select + distinct c.country + from country_code c + ) t + ) d + join location_country lc on lc.code = d.code and d."name"=lc."name" +) +; + +commit; + + +delete from translation_language tl +where tl.id in +( + SELECT tl.id + FROM + ( + select + distinct c.country, c.code + from country_code c + ) t + JOIN translation_language tl ON tl.locale = t.code and tl.title = t.country +); + +commit; + +drop table country_code; +drop table codelang; + +commit; \ No newline at end of file From 1f44777a15b23391f5c2329ea40ffe3023a5ca14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Fri, 11 Oct 2019 17:04:55 +0300 Subject: [PATCH 14/14] Fix --- apps/location/migrations/0012_data_migrate.py | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/location/migrations/0012_data_migrate.py b/apps/location/migrations/0012_data_migrate.py index d32454bf..511990db 100644 --- a/apps/location/migrations/0012_data_migrate.py +++ b/apps/location/migrations/0012_data_migrate.py @@ -22,5 +22,4 @@ class Migration(migrations.Migration): operations = [ migrations.RunPython(load_data_from_sql, revert_data), - # migrations.RunPython(load_data_from_sql, revert_data), ]