Merge branch 'develop' into feature/permission_liquor
This commit is contained in:
commit
d441e69b81
23
apps/account/migrations/0025_auto_20191210_0623.py
Normal file
23
apps/account/migrations/0025_auto_20191210_0623.py
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 2.2.7 on 2019-12-10 06:23
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('account', '0024_role_establishment_subtype'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='user',
|
||||||
|
name='city',
|
||||||
|
field=models.TextField(blank=True, default=None, null=True, verbose_name='User last visited from city'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='user',
|
||||||
|
name='locale',
|
||||||
|
field=models.CharField(blank=True, default=None, max_length=10, null=True, verbose_name='User last used locale'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -110,6 +110,10 @@ class User(AbstractUser):
|
||||||
email_confirmed = models.BooleanField(_('email status'), default=False)
|
email_confirmed = models.BooleanField(_('email status'), default=False)
|
||||||
newsletter = models.NullBooleanField(default=True)
|
newsletter = models.NullBooleanField(default=True)
|
||||||
old_id = models.IntegerField(null=True, blank=True, default=None)
|
old_id = models.IntegerField(null=True, blank=True, default=None)
|
||||||
|
locale = models.CharField(max_length=10, blank=True, default=None, null=True,
|
||||||
|
verbose_name=_('User last used locale'))
|
||||||
|
city = models.TextField(default=None, blank=True, null=True,
|
||||||
|
verbose_name=_('User last visited from city'))
|
||||||
|
|
||||||
EMAIL_FIELD = 'email'
|
EMAIL_FIELD = 'email'
|
||||||
USERNAME_FIELD = 'username'
|
USERNAME_FIELD = 'username'
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,14 @@ class BackUserSerializer(serializers.ModelSerializer):
|
||||||
'email_confirmed',
|
'email_confirmed',
|
||||||
'newsletter',
|
'newsletter',
|
||||||
'roles',
|
'roles',
|
||||||
'password'
|
'password',
|
||||||
|
'city',
|
||||||
|
'locale',
|
||||||
)
|
)
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
'password': {'write_only': True}
|
'password': {'write_only': True},
|
||||||
}
|
}
|
||||||
read_only_fields = ('old_password', 'last_login', 'date_joined')
|
read_only_fields = ('old_password', 'last_login', 'date_joined', 'city', 'locale')
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
user = super().create(validated_data)
|
user = super().create(validated_data)
|
||||||
|
|
|
||||||
32
apps/main/management/commands/add_footers.py
Normal file
32
apps/main/management/commands/add_footers.py
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
from main.models import SiteSettings, Footer
|
||||||
|
from transfer.models import Footers
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = '''Add footers from legacy DB.'''
|
||||||
|
|
||||||
|
def handle(self, *args, **kwargs):
|
||||||
|
objects = []
|
||||||
|
deleted = 0
|
||||||
|
footers_list = Footers.objects.all()
|
||||||
|
|
||||||
|
for old_footer in tqdm(footers_list, desc='Add footers'):
|
||||||
|
site = SiteSettings.objects.filter(old_id=old_footer.site_id).first()
|
||||||
|
if site:
|
||||||
|
if site.footers.exists():
|
||||||
|
site.footers.all().delete()
|
||||||
|
deleted += 1
|
||||||
|
footer = Footer(
|
||||||
|
site=site,
|
||||||
|
about_us=old_footer.about_us,
|
||||||
|
copyright=old_footer.copyright,
|
||||||
|
created=old_footer.created_at,
|
||||||
|
modified=old_footer.updated_at
|
||||||
|
)
|
||||||
|
objects.append(footer)
|
||||||
|
Footer.objects.bulk_create(objects)
|
||||||
|
self.stdout.write(
|
||||||
|
self.style.WARNING(f'Created {len(objects)}/Deleted {deleted} footer objects.'))
|
||||||
29
apps/main/migrations/0040_footer.py
Normal file
29
apps/main/migrations/0040_footer.py
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Generated by Django 2.2.7 on 2019-12-09 13:21
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('main', '0039_sitefeature_old_id'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Footer',
|
||||||
|
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')),
|
||||||
|
('about_us', models.TextField(verbose_name='about_us')),
|
||||||
|
('copyright', models.TextField(verbose_name='copyright')),
|
||||||
|
('site', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='footers', to='main.SiteSettings', verbose_name='footer')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -351,3 +351,12 @@ class PageType(ProjectBaseMixin):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""Overridden dunder method."""
|
"""Overridden dunder method."""
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
class Footer(ProjectBaseMixin):
|
||||||
|
site = models.ForeignKey(
|
||||||
|
'main.SiteSettings', related_name='footers', verbose_name=_('footer'),
|
||||||
|
on_delete=models.PROTECT
|
||||||
|
)
|
||||||
|
about_us = models.TextField(_('about_us'))
|
||||||
|
copyright = models.TextField(_('copyright'))
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ class FeatureSerializer(serializers.ModelSerializer):
|
||||||
'site_settings',
|
'site_settings',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class CurrencySerializer(ProjectModelSerializer):
|
class CurrencySerializer(ProjectModelSerializer):
|
||||||
"""Currency serializer."""
|
"""Currency serializer."""
|
||||||
|
|
||||||
|
|
@ -36,6 +37,33 @@ class CurrencySerializer(ProjectModelSerializer):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class FooterSerializer(serializers.ModelSerializer):
|
||||||
|
"""Footer serializer."""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.Footer
|
||||||
|
fields = [
|
||||||
|
'id',
|
||||||
|
'about_us',
|
||||||
|
'copyright',
|
||||||
|
'created',
|
||||||
|
'modified',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class FooterBackSerializer(FooterSerializer):
|
||||||
|
site_id = serializers.PrimaryKeyRelatedField(
|
||||||
|
queryset=models.SiteSettings.objects.all(),
|
||||||
|
source='site'
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.Footer
|
||||||
|
fields = FooterSerializer.Meta.fields + [
|
||||||
|
'site_id'
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class SiteFeatureSerializer(serializers.ModelSerializer):
|
class SiteFeatureSerializer(serializers.ModelSerializer):
|
||||||
id = serializers.IntegerField(source='feature.id')
|
id = serializers.IntegerField(source='feature.id')
|
||||||
slug = serializers.CharField(source='feature.slug')
|
slug = serializers.CharField(source='feature.slug')
|
||||||
|
|
@ -68,6 +96,7 @@ class SiteSettingsSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
country_name = serializers.CharField(source='country.name_translated', read_only=True)
|
country_name = serializers.CharField(source='country.name_translated', read_only=True)
|
||||||
time_format = serializers.CharField(source='country.time_format', read_only=True)
|
time_format = serializers.CharField(source='country.time_format', read_only=True)
|
||||||
|
footers = FooterSerializer(many=True, read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Meta class."""
|
"""Meta class."""
|
||||||
|
|
@ -87,6 +116,7 @@ class SiteSettingsSerializer(serializers.ModelSerializer):
|
||||||
'published_features',
|
'published_features',
|
||||||
'currency',
|
'currency',
|
||||||
'country_name',
|
'country_name',
|
||||||
|
'footers',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ urlpatterns = [
|
||||||
name='site-feature-list-create'),
|
name='site-feature-list-create'),
|
||||||
path('site-feature/<int:id>/', views.SiteFeatureRUDBackView.as_view(),
|
path('site-feature/<int:id>/', views.SiteFeatureRUDBackView.as_view(),
|
||||||
name='site-feature-rud'),
|
name='site-feature-rud'),
|
||||||
|
path('footer/', views.FooterBackView.as_view(), name='footer-list-create'),
|
||||||
|
path('footer/<int:pk>/', views.FooterRUDBackView.as_view(), name='footer-rud'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from rest_framework import generics, permissions
|
||||||
|
|
||||||
from main import serializers
|
from main import serializers
|
||||||
from main.filters import AwardFilter
|
from main.filters import AwardFilter
|
||||||
from main.models import Award
|
from main.models import Award, Footer
|
||||||
from main.views import SiteSettingsView, SiteListView
|
from main.views import SiteSettingsView, SiteListView
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -67,3 +67,17 @@ class SiteSettingsBackOfficeView(SiteSettingsView):
|
||||||
class SiteListBackOfficeView(SiteListView):
|
class SiteListBackOfficeView(SiteListView):
|
||||||
"""Site settings View."""
|
"""Site settings View."""
|
||||||
serializer_class = serializers.SiteSerializer
|
serializer_class = serializers.SiteSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class FooterBackView(generics.ListCreateAPIView):
|
||||||
|
"""Footer back list/create view."""
|
||||||
|
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
|
||||||
|
serializer_class = serializers.FooterBackSerializer
|
||||||
|
queryset = Footer.objects.all()
|
||||||
|
|
||||||
|
|
||||||
|
class FooterRUDBackView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
|
"""Footer back RUD view."""
|
||||||
|
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
|
||||||
|
serializer_class = serializers.FooterBackSerializer
|
||||||
|
queryset = Footer.objects.all()
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,7 @@ class ProductBaseSerializer(serializers.ModelSerializer):
|
||||||
'wine_regions',
|
'wine_regions',
|
||||||
'wine_colors',
|
'wine_colors',
|
||||||
'in_favorites',
|
'in_favorites',
|
||||||
|
'wine_origins',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django_elasticsearch_dsl import Document, Index, fields
|
from django_elasticsearch_dsl import Document, Index, fields
|
||||||
from tag import models
|
from tag import models
|
||||||
|
from news.models import News
|
||||||
|
|
||||||
TagCategoryIndex = Index(settings.ELASTICSEARCH_INDEX_NAMES.get(__name__, 'tag_category'))
|
TagCategoryIndex = Index(settings.ELASTICSEARCH_INDEX_NAMES.get(__name__, 'tag_category'))
|
||||||
TagCategoryIndex.settings(number_of_shards=2, number_of_replicas=2)
|
TagCategoryIndex.settings(number_of_shards=2, number_of_replicas=2)
|
||||||
|
|
@ -26,8 +27,20 @@ class TagCategoryDocument(Document):
|
||||||
'public',
|
'public',
|
||||||
'value_type'
|
'value_type'
|
||||||
)
|
)
|
||||||
related_models = [models.Tag]
|
related_models = [models.Tag, News]
|
||||||
|
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return super().get_queryset().with_base_related()
|
return super().get_queryset().with_base_related()
|
||||||
|
|
||||||
|
def get_instances_from_related(self, related_instance):
|
||||||
|
"""If related_models is set, define how to retrieve the Car instance(s) from the related model.
|
||||||
|
The related_models option should be used with caution because it can lead in the index
|
||||||
|
to the updating of a lot of items.
|
||||||
|
"""
|
||||||
|
if isinstance(related_instance, News):
|
||||||
|
tag_categories = []
|
||||||
|
for tag in related_instance.tags.all():
|
||||||
|
if tag.category not in tag_categories:
|
||||||
|
tag_categories.append(tag.category)
|
||||||
|
return tag_categories
|
||||||
|
|
@ -1208,3 +1208,17 @@ class NewsletterSubscriber(MigrateMixin):
|
||||||
class Meta:
|
class Meta:
|
||||||
managed = False
|
managed = False
|
||||||
db_table = 'newsletter_subscriptions'
|
db_table = 'newsletter_subscriptions'
|
||||||
|
|
||||||
|
|
||||||
|
class Footers(MigrateMixin):
|
||||||
|
using = 'legacy'
|
||||||
|
|
||||||
|
about_us = models.TextField(blank=True, null=True)
|
||||||
|
copyright = models.TextField(blank=True, null=True)
|
||||||
|
site = models.ForeignKey('Sites', models.DO_NOTHING, blank=True, null=True)
|
||||||
|
created_at = models.DateTimeField()
|
||||||
|
updated_at = models.DateTimeField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'footers'
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
"""Custom middleware."""
|
"""Custom middlewares."""
|
||||||
from django.utils import translation, timezone
|
from django.utils import translation, timezone
|
||||||
from account.models import User
|
|
||||||
|
|
||||||
|
from account.models import User
|
||||||
from configuration.models import TranslationSettings
|
from configuration.models import TranslationSettings
|
||||||
|
from main.methods import determine_user_city
|
||||||
from translation.models import Language
|
from translation.models import Language
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -18,7 +19,11 @@ def user_last_visit(get_response):
|
||||||
def middleware(request):
|
def middleware(request):
|
||||||
response = get_response(request)
|
response = get_response(request)
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
User.objects.filter(pk=request.user.pk).update(last_login=timezone.now())
|
User.objects.filter(pk=request.user.pk).update(**{
|
||||||
|
'last_login': timezone.now(),
|
||||||
|
'locale': request.locale,
|
||||||
|
'city': determine_user_city(request),
|
||||||
|
})
|
||||||
return response
|
return response
|
||||||
return middleware
|
return middleware
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,15 @@
|
||||||
./manage.py transfer --fill_city_gallery
|
./manage.py transfer --fill_city_gallery
|
||||||
./manage.py transfer -l
|
./manage.py transfer -l
|
||||||
./manage.py transfer --product
|
./manage.py transfer --product
|
||||||
|
# Утеряна четкая связь между последовательностью миграций для импорта тегов продуктов,
|
||||||
|
# что может привести к удалению уже импортированных тегов командой выше.
|
||||||
./manage.py transfer --souvenir
|
./manage.py transfer --souvenir
|
||||||
./manage.py transfer --establishment_note
|
./manage.py transfer --establishment_note
|
||||||
./manage.py transfer --product_note
|
./manage.py transfer --product_note
|
||||||
|
./manage.py transfer --check_serial_number
|
||||||
./manage.py transfer --wine_characteristics
|
./manage.py transfer --wine_characteristics
|
||||||
./manage.py transfer --inquiries
|
./manage.py transfer --inquiries
|
||||||
./manage.py transfer --assemblage
|
./manage.py transfer --assemblage
|
||||||
./manage.py transfer --purchased_plaques
|
./manage.py transfer --purchased_plaques
|
||||||
./manage.py rm_empty_images
|
./manage.py rm_empty_images
|
||||||
|
./manage.py add_artisan_subtype # добавляет подтипы для заведений артизанов
|
||||||
Loading…
Reference in New Issue
Block a user