Merge branch 'develop' into feature/gm-192

# Conflicts:
#	apps/account/views/common.py
#	project/urls/back.py
This commit is contained in:
Anatoly 2019-10-15 11:47:14 +03:00
commit 6f6717efdc
30 changed files with 1269 additions and 96 deletions

View File

@ -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."""

View 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'),
),
]

View 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',
),
]

View File

@ -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)

View File

View 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'
]

View File

@ -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

View File

@ -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):

View 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
View 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'),
]

View File

@ -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'),
]

View 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()

View File

@ -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.

View File

@ -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:

View 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'),
),
]

View File

@ -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"""

View 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

View 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')

View File

@ -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
View 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'),
]

View 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'

View 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'),
),
]

View 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),
]

View 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;

View 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;

View File

@ -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."""

View File

@ -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

View File

@ -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"

View File

@ -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 %}

View File

@ -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')),
]