Merge branch 'develop' into feature/gm-192
# Conflicts: # apps/account/views/common.py # project/urls/back.py
This commit is contained in:
commit
6f6717efdc
|
|
@ -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."""
|
||||
|
|
|
|||
48
apps/account/migrations/0009_auto_20191011_1123.py
Normal file
48
apps/account/migrations/0009_auto_20191011_1123.py
Normal file
|
|
@ -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'),
|
||||
),
|
||||
]
|
||||
18
apps/account/migrations/0011_merge_20191014_1258.py
Normal file
18
apps/account/migrations/0011_merge_20191014_1258.py
Normal file
|
|
@ -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',
|
||||
),
|
||||
]
|
||||
|
|
@ -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)
|
||||
0
apps/account/permissions.py
Normal file
0
apps/account/permissions.py
Normal file
21
apps/account/serializers/back.py
Normal file
21
apps/account/serializers/back.py
Normal file
|
|
@ -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'
|
||||
]
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
81
apps/account/tests/tests_back.py
Normal file
81
apps/account/tests/tests_back.py
Normal file
|
|
@ -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)
|
||||
12
apps/account/urls/back.py
Normal file
12
apps/account/urls/back.py
Normal file
|
|
@ -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'),
|
||||
|
||||
]
|
||||
|
|
@ -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/<uuid64>/<token>/', views.ConfirmPasswordView.as_view(), name='change-password'),
|
||||
path('email/confirm/', views.SendConfirmationEmailView.as_view(), name='send-confirm-email'),
|
||||
path('email/confirm/<uidb64>/<token>/', views.ConfirmEmailView.as_view(), name='confirm-email'),
|
||||
]
|
||||
|
|
|
|||
13
apps/account/views/back.py
Normal file
13
apps/account/views/back.py
Normal file
|
|
@ -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()
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
20
apps/comment/migrations/0002_comment_language.py
Normal file
20
apps/comment/migrations/0002_comment_language.py
Normal file
|
|
@ -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'),
|
||||
),
|
||||
]
|
||||
|
|
@ -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"""
|
||||
|
|
|
|||
28
apps/comment/permissions.py
Normal file
28
apps/comment/permissions.py
Normal file
|
|
@ -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
|
||||
|
||||
9
apps/comment/serializers/back.py
Normal file
9
apps/comment/serializers/back.py
Normal file
|
|
@ -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')
|
||||
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
11
apps/comment/urls/back.py
Normal file
11
apps/comment/urls/back.py
Normal file
|
|
@ -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('<int:id>/', views.CommentRUDView.as_view(), name='comment-crud'),
|
||||
]
|
||||
19
apps/comment/views/back.py
Normal file
19
apps/comment/views/back.py
Normal file
|
|
@ -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'
|
||||
19
apps/location/migrations/0011_country_languages.py
Normal file
19
apps/location/migrations/0011_country_languages.py
Normal file
|
|
@ -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'),
|
||||
),
|
||||
]
|
||||
25
apps/location/migrations/0012_data_migrate.py
Normal file
25
apps/location/migrations/0012_data_migrate.py
Normal file
|
|
@ -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),
|
||||
]
|
||||
382
apps/location/migrations/migrate_lang.sql
Normal file
382
apps/location/migrations/migrate_lang.sql
Normal file
|
|
@ -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;
|
||||
391
apps/location/migrations/remigrate_lang.sql
Normal file
391
apps/location/migrations/remigrate_lang.sql
Normal file
|
|
@ -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;
|
||||
|
|
@ -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."""
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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 %}
|
||||
|
|
@ -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')),
|
||||
]
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user