diff --git a/apps/account/admin.py b/apps/account/admin.py index 8429952f..3b247289 100644 --- a/apps/account/admin.py +++ b/apps/account/admin.py @@ -2,10 +2,19 @@ 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 +@admin.register(models.Role) +class RoleAdmin(admin.ModelAdmin): + list_display = ['role', 'country'] + + +@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_auto_20191011_1123.py b/apps/account/migrations/0009_auto_20191011_1123.py new file mode 100644 index 00000000..f1ec87f9 --- /dev/null +++ b/apps/account/migrations/0009_auto_20191011_1123.py @@ -0,0 +1,48 @@ +# Generated by Django 2.2.4 on 2019-10-11 11:23 + +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', '0011_country_languages'), + ('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.PositiveIntegerField(choices=[(1, 'Standard user'), (2, 'Comments moderator')], verbose_name='Role')), + ('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, + }, + ), + 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/0011_merge_20191014_1258.py b/apps/account/migrations/0011_merge_20191014_1258.py new file mode 100644 index 00000000..cee0a824 --- /dev/null +++ b/apps/account/migrations/0011_merge_20191014_1258.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.4 on 2019-10-14 12:58 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0009_auto_20191011_1123'), + ('account', '0010_user_password_confirmed'), + ] + + operations = [ + migrations.RemoveField( + model_name='user', + name='password_confirmed', + ), + ] diff --git a/apps/account/models.py b/apps/account/models.py index b4023816..5052969e 100644 --- a/apps/account/models.py +++ b/apps/account/models.py @@ -13,11 +13,30 @@ 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 +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.""" @@ -63,12 +82,12 @@ class User(AbstractUser): unconfirmed_email = models.EmailField(_('unconfirmed email'), blank=True, null=True, default=None) email_confirmed = models.BooleanField(_('email status'), default=False) newsletter = models.NullBooleanField(default=True) - password_confirmed = models.BooleanField(_('is new password confirmed'), default=True, null=False) EMAIL_FIELD = 'email' USERNAME_FIELD = 'username' REQUIRED_FIELDS = ['email'] + roles = models.ManyToManyField(Role, verbose_name=_('Roles'), through='UserRole') objects = UserManager.from_queryset(UserQuerySet)() class Meta: @@ -114,15 +133,12 @@ class User(AbstractUser): def confirm_email(self): """Method to confirm user email address""" - self.email = self.unconfirmed_email - self.unconfirmed_email = None + if self.unconfirmed_email is not None: + self.email = self.unconfirmed_email + self.unconfirmed_email = None self.email_confirmed = True self.save() - def confirm_password(self): - self.password_confirmed = True - self.save() - def approve(self): """Set user is_active status to True""" self.is_active = True @@ -157,11 +173,6 @@ class User(AbstractUser): """Make a token for finish signup.""" return password_token_generator.make_token(self) - @property - def confirm_password_token(self): - """Make a token for new password confirmation """ - return GMTokenGenerator(purpose=GMTokenGenerator.CONFIRM_PASSWORD).make_token(self) - @property def get_user_uidb64(self): """Get base64 value for user by primary key identifier""" @@ -191,16 +202,6 @@ class User(AbstractUser): template_name=settings.RESETTING_TOKEN_TEMPLATE, context=context) - def confirm_password_template(self, country_code): - """Get confirm password template""" - context = {'token': self.confirm_password_token, - 'country_code': country_code} - context.update(self.base_template) - return render_to_string( - template_name=settings.CONFIRM_PASSWORD_TEMPLATE, - context=context, - ) - def confirm_email_template(self, country_code): """Get confirm email template""" context = {'token': self.confirm_email_token, @@ -218,3 +219,9 @@ class User(AbstractUser): return render_to_string( template_name=settings.CHANGE_EMAIL_TEMPLATE, context=context) + + +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/account/permissions.py b/apps/account/permissions.py new file mode 100644 index 00000000..e69de29b 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/serializers/web.py b/apps/account/serializers/web.py index dd8ccec8..8be73afa 100644 --- a/apps/account/serializers/web.py +++ b/apps/account/serializers/web.py @@ -1,10 +1,8 @@ """Serializers for account web""" from django.contrib.auth import password_validation as password_validators -from django.conf import settings from rest_framework import serializers from account import models -from account import tasks from utils import exceptions as utils_exceptions from utils.methods import username_validator @@ -69,16 +67,5 @@ class PasswordResetConfirmSerializer(serializers.ModelSerializer): """Override update method""" # Update user password from instance instance.set_password(validated_data.get('password')) - instance.password_confirmed = False instance.save() - if settings.USE_CELERY: - tasks.send_reset_password_confirm.delay( - user=instance, - country_code=self.context.get('request').country_code, - ) - else: - tasks.send_reset_password_confirm( - user=instance, - country_code=self.context.get('request').country_code, - ) return instance diff --git a/apps/account/tasks.py b/apps/account/tasks.py index 3729c40c..03a231b3 100644 --- a/apps/account/tasks.py +++ b/apps/account/tasks.py @@ -22,17 +22,6 @@ def send_reset_password_email(user_id, country_code): f'DETAIL: Exception occurred for reset password: ' f'{user_id}') -@shared_task -def send_reset_password_confirm(user: models.User, country_code): - """ Send email to user for applying new password. """ - try: - user.send_email(subject=_('New password confirmation'), - message=user.confirm_password_template(country_code)) - except: - logger.error(f'METHOD_NAME: {send_reset_password_confirm.__name__}\n' - f'DETAIL: Exception occured for new passwordconfirmation', - f'{user.id}') - @shared_task def confirm_new_email_address(user_id, country_code): diff --git a/apps/account/tests/tests_back.py b/apps/account/tests/tests_back.py new file mode 100644 index 00000000..8adc6b35 --- /dev/null +++ b/apps/account/tests/tests_back.py @@ -0,0 +1,81 @@ +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') + + 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/urls/common.py b/apps/account/urls/common.py index a440c5bf..4ea2af66 100644 --- a/apps/account/urls/common.py +++ b/apps/account/urls/common.py @@ -8,7 +8,6 @@ app_name = 'account' urlpatterns = [ path('user/', views.UserRetrieveUpdateView.as_view(), name='user-retrieve-update'), path('change-password/', views.ChangePasswordView.as_view(), name='change-password'), - path('change-password-confirm///', views.ConfirmPasswordView.as_view(), name='change-password'), path('email/confirm/', views.SendConfirmationEmailView.as_view(), name='send-confirm-email'), path('email/confirm///', views.ConfirmEmailView.as_view(), name='confirm-email'), ] 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/account/views/common.py b/apps/account/views/common.py index 0a9a4d98..d29ce2bb 100644 --- a/apps/account/views/common.py +++ b/apps/account/views/common.py @@ -92,33 +92,6 @@ class ConfirmEmailView(JWTGenericViewMixin): raise utils_exceptions.UserNotFoundError() -class ConfirmPasswordView(JWTGenericViewMixin): - """View for applying newly set password""" - - permission_classes = (permissions.AllowAny,) - - def get(self, request, *args, **kwargs): - uidb64 = kwargs.get('uidb64') - token = kwargs.get('token') - uid = force_text(urlsafe_base64_decode(uidb64)) - user_qs = models.User.objects.filter(pk=uid) - if user_qs.exists(): - user = user_qs.first() - if not GMTokenGenerator(GMTokenGenerator.CONFIRM_PASSWORD).check_token( - user, token): - raise utils_exceptions.NotValidTokenError() - user.confirm_password() - tokens = user.create_jwt_tokens() - return self._put_cookies_in_response( - cookies=self._put_data_in_cookies( - access_token=tokens.get('access_token'), - refresh_token=tokens.get('refresh_token')), - response=Response(status=status.HTTP_200_OK)) - else: - raise utils_exceptions.UserNotFoundError() - - - # Firebase Cloud Messaging class FCMDeviceViewSet(generics.GenericAPIView): """FCMDevice registration view. diff --git a/apps/authorization/serializers/common.py b/apps/authorization/serializers/common.py index 6be76a00..ed68ba9f 100644 --- a/apps/authorization/serializers/common.py +++ b/apps/authorization/serializers/common.py @@ -108,8 +108,8 @@ class LoginByUsernameOrEmailSerializer(SourceSerializerMixin, """Override validate method""" username_or_email = attrs.pop('username_or_email') password = attrs.pop('password') - user_qs = account_models.User.objects.filter(password_confirmed=True)\ - .filter(Q(username=username_or_email) | Q(email=username_or_email)) + user_qs = account_models.User.objects.filter(Q(username=username_or_email) | + Q(email=username_or_email)) if not user_qs.exists(): raise utils_exceptions.WrongAuthCredentials() else: 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 new file mode 100644 index 00000000..6d691c07 --- /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.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 + diff --git a/apps/comment/serializers/back.py b/apps/comment/serializers/back.py new file mode 100644 index 00000000..d0cd47c8 --- /dev/null +++ b/apps/comment/serializers/back.py @@ -0,0 +1,9 @@ +"""Comment app common serializers.""" +from comment import models +from rest_framework import serializers + + +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..949ba597 100644 --- a/apps/comment/tests.py +++ b/apps/comment/tests.py @@ -1 +1,123 @@ -# 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 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): + 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() + + 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() + + 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, + language=self.lang + ) + 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) + 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(self.url, data=data, format='json') + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_put_other_user(self): + 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')}) + + data = { + "id": self.comment.id, + "text": "test text moderator", + "mark": 1, + "user": other_user.id + } + + 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): + 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(self.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 new file mode 100644 index 00000000..214eab48 --- /dev/null +++ b/apps/comment/urls/back.py @@ -0,0 +1,11 @@ +"""Back comment URLs""" +from django.urls import path + +from comment.views import back as views + +app_name = 'comment' + +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 new file mode 100644 index 00000000..77edfa97 --- /dev/null +++ b/apps/comment/views/back.py @@ -0,0 +1,19 @@ +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): + """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 = [IsCommentModerator] + lookup_field = 'id' diff --git a/apps/location/migrations/0011_country_languages.py b/apps/location/migrations/0011_country_languages.py new file mode 100644 index 00000000..629f76bc --- /dev/null +++ b/apps/location/migrations/0011_country_languages.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.4 on 2019-10-10 12:22 + +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='languages', + field=models.ManyToManyField(to='translation.Language', verbose_name='Languages'), + ), + ] diff --git a/apps/location/migrations/0012_data_migrate.py b/apps/location/migrations/0012_data_migrate.py new file mode 100644 index 00000000..511990db --- /dev/null +++ b/apps/location/migrations/0012_data_migrate.py @@ -0,0 +1,25 @@ +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, revert_data), + ] diff --git a/apps/location/migrations/migrate_lang.sql b/apps/location/migrations/migrate_lang.sql new file mode 100644 index 00000000..11c93573 --- /dev/null +++ b/apps/location/migrations/migrate_lang.sql @@ -0,0 +1,382 @@ +SET search_path TO gm, public; + +CREATE TABLE codelang ( + code varchar(100) NULL, + country varchar(10000) NULL +); + + +INSERT INTO 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 diff --git a/apps/location/migrations/remigrate_lang.sql b/apps/location/migrations/remigrate_lang.sql new file mode 100644 index 00000000..160ac93e --- /dev/null +++ b/apps/location/migrations/remigrate_lang.sql @@ -0,0 +1,391 @@ +SET search_path TO gm, public; + +CREATE TABLE codelang ( + code varchar(100) NULL, + country varchar(10000) NULL +); + + +INSERT INTO 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 diff --git a/apps/location/models.py b/apps/location/models.py index 1cab1815..2298c28e 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -6,6 +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): @@ -18,6 +19,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')) + languages = models.ManyToManyField(Language, verbose_name=_('Languages')) class Meta: """Meta class.""" diff --git a/apps/utils/models.py b/apps/utils/models.py index e5a39895..4e6df35e 100644 --- a/apps/utils/models.py +++ b/apps/utils/models.py @@ -258,14 +258,12 @@ class GMTokenGenerator(PasswordResetTokenGenerator): RESET_PASSWORD = 1 CHANGE_PASSWORD = 2 CONFIRM_EMAIL = 3 - CONFIRM_PASSWORD = 4 TOKEN_CHOICES = ( CHANGE_EMAIL, RESET_PASSWORD, CHANGE_PASSWORD, - CONFIRM_EMAIL, - CONFIRM_PASSWORD, + CONFIRM_EMAIL ) def __init__(self, purpose: int): @@ -281,8 +279,7 @@ class GMTokenGenerator(PasswordResetTokenGenerator): self.purpose == self.CONFIRM_EMAIL: fields.extend([str(user.email_confirmed), str(user.email)]) elif self.purpose == self.RESET_PASSWORD or \ - self.purpose == self.CHANGE_PASSWORD or \ - self.purpose == self.CONFIRM_PASSWORD: + self.purpose == self.CHANGE_PASSWORD: fields.append(str(user.password)) return fields diff --git a/project/settings/base.py b/project/settings/base.py index a51547ff..4618887d 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -406,7 +406,6 @@ PASSWORD_RESET_TIMEOUT_DAYS = 1 # TEMPLATES RESETTING_TOKEN_TEMPLATE = 'account/password_reset_email.html' CHANGE_EMAIL_TEMPLATE = 'account/change_email.html' -CONFIRM_PASSWORD_TEMPLATE = 'account/password_confirm_email.html' CONFIRM_EMAIL_TEMPLATE = 'authorization/confirm_email.html' NEWS_EMAIL_TEMPLATE = "news/news_email.html" diff --git a/project/templates/account/password_confirm_email.html b/project/templates/account/password_confirm_email.html deleted file mode 100644 index 29f27afb..00000000 --- a/project/templates/account/password_confirm_email.html +++ /dev/null @@ -1,11 +0,0 @@ -{% load i18n %}{% autoescape off %} -{% blocktrans %}Confirm a password reset for your user account at {{ site_name }}.{% endblocktrans %} - -{% trans "Please go to the following page:" %} - -https://{{ country_code }}.{{ domain_uri }}/confirm-new-password/{{ uidb64 }}/{{ token }}/ - -{% trans "Thanks for using our site!" %} - -{% blocktrans %}The {{ site_name }} team{% endblocktrans %} -{% endautoescape %} \ No newline at end of file diff --git a/project/urls/back.py b/project/urls/back.py index 77e573d0..7cfcd038 100644 --- a/project/urls/back.py +++ b/project/urls/back.py @@ -8,4 +8,6 @@ urlpatterns = [ path('location/', include('location.urls.back')), path('news/', include('news.urls.back')), path('tags/', include(('tag.urls', 'tag'), namespace='tag')) + path('account/', include('account.urls.back')), + path('comment/', include('comment.urls.back')), ]