Merge branch 'develop' into feature/permission_liquor

This commit is contained in:
Виктор Гладких 2019-12-10 12:51:30 +03:00
commit d441e69b81
14 changed files with 191 additions and 9 deletions

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -115,6 +115,7 @@ class ProductBaseSerializer(serializers.ModelSerializer):
'wine_regions', 'wine_regions',
'wine_colors', 'wine_colors',
'in_favorites', 'in_favorites',
'wine_origins',
] ]

View File

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

View File

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

View File

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

View File

@ -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 # добавляет подтипы для заведений артизанов