gm-148: refactored
This commit is contained in:
parent
aeebdd02c6
commit
d9635a8599
18
apps/account/migrations/0009_auto_20191002_0648.py
Normal file
18
apps/account/migrations/0009_auto_20191002_0648.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-10-02 06:48
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('account', '0008_auto_20190912_1325'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='user',
|
||||||
|
name='email',
|
||||||
|
field=models.EmailField(default=None, max_length=254, null=True, unique=True, verbose_name='email address'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -58,7 +58,7 @@ class User(AbstractUser):
|
||||||
blank=True, null=True, default=None)
|
blank=True, null=True, default=None)
|
||||||
cropped_image_url = models.URLField(verbose_name=_('Cropped image URL path'),
|
cropped_image_url = models.URLField(verbose_name=_('Cropped image URL path'),
|
||||||
blank=True, null=True, default=None)
|
blank=True, null=True, default=None)
|
||||||
email = models.EmailField(_('email address'), blank=True,
|
email = models.EmailField(_('email address'), unique=True,
|
||||||
null=True, default=None)
|
null=True, default=None)
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,6 @@ from utils.tokens import GMRefreshToken
|
||||||
# Serializers
|
# Serializers
|
||||||
class SignupSerializer(serializers.ModelSerializer):
|
class SignupSerializer(serializers.ModelSerializer):
|
||||||
"""Signup serializer serializer mixin"""
|
"""Signup serializer serializer mixin"""
|
||||||
# REQUEST
|
|
||||||
username = serializers.CharField(write_only=True)
|
|
||||||
password = serializers.CharField(write_only=True)
|
|
||||||
email = serializers.EmailField(write_only=True)
|
|
||||||
newsletter = serializers.BooleanField(write_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = account_models.User
|
model = account_models.User
|
||||||
fields = (
|
fields = (
|
||||||
|
|
@ -32,6 +26,12 @@ class SignupSerializer(serializers.ModelSerializer):
|
||||||
'email',
|
'email',
|
||||||
'newsletter'
|
'newsletter'
|
||||||
)
|
)
|
||||||
|
extra_kwargs = {
|
||||||
|
'username': {'write_only': True},
|
||||||
|
'password': {'write_only': True},
|
||||||
|
'email': {'write_only': True},
|
||||||
|
'newsletter': {'write_only': True}
|
||||||
|
}
|
||||||
|
|
||||||
def validate_username(self, value):
|
def validate_username(self, value):
|
||||||
"""Custom username validation"""
|
"""Custom username validation"""
|
||||||
|
|
|
||||||
20
apps/gallery/migrations/0003_auto_20191001_0647.py
Normal file
20
apps/gallery/migrations/0003_auto_20191001_0647.py
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-10-01 06:47
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
import sorl.thumbnail.fields
|
||||||
|
import utils.methods
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('gallery', '0002_auto_20190930_0714'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='image',
|
||||||
|
name='image',
|
||||||
|
field=sorl.thumbnail.fields.ImageField(upload_to=utils.methods.image_path, verbose_name='image file'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from easy_thumbnails.fields import ThumbnailerImageField
|
from sorl.thumbnail.fields import ImageField as SORLImageField
|
||||||
|
|
||||||
from utils.methods import image_path
|
from utils.methods import image_path
|
||||||
from utils.models import ProjectBaseMixin, ImageMixin, PlatformMixin
|
from utils.models import ProjectBaseMixin, SORLImageMixin, PlatformMixin
|
||||||
|
|
||||||
|
|
||||||
class ImageQuerySet(models.QuerySet):
|
class ImageQuerySet(models.QuerySet):
|
||||||
"""QuerySet for model Image."""
|
"""QuerySet for model Image."""
|
||||||
|
|
||||||
|
|
||||||
class Image(ProjectBaseMixin, ImageMixin, PlatformMixin):
|
class Image(ProjectBaseMixin, SORLImageMixin, PlatformMixin):
|
||||||
"""Image model."""
|
"""Image model."""
|
||||||
HORIZONTAL = 0
|
HORIZONTAL = 0
|
||||||
VERTICAL = 1
|
VERTICAL = 1
|
||||||
|
|
@ -20,7 +20,7 @@ class Image(ProjectBaseMixin, ImageMixin, PlatformMixin):
|
||||||
(VERTICAL, _('Vertical')),
|
(VERTICAL, _('Vertical')),
|
||||||
)
|
)
|
||||||
|
|
||||||
image = ThumbnailerImageField(upload_to=image_path,
|
image = SORLImageField(upload_to=image_path,
|
||||||
verbose_name=_('image file'))
|
verbose_name=_('image file'))
|
||||||
parent = models.ForeignKey('self',
|
parent = models.ForeignKey('self',
|
||||||
blank=True, null=True, default=None,
|
blank=True, null=True, default=None,
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ class ImageSerializer(serializers.ModelSerializer):
|
||||||
# REQUEST
|
# REQUEST
|
||||||
file = serializers.ImageField(source='image',
|
file = serializers.ImageField(source='image',
|
||||||
write_only=True)
|
write_only=True)
|
||||||
title = serializers.CharField()
|
|
||||||
orientation = serializers.ChoiceField(choices=models.Image.ORIENTATIONS,
|
orientation = serializers.ChoiceField(choices=models.Image.ORIENTATIONS,
|
||||||
write_only=True)
|
write_only=True)
|
||||||
|
|
||||||
|
|
@ -21,7 +20,7 @@ class ImageSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Meta class"""
|
"""Meta class"""
|
||||||
model = models.Image
|
model = models.Image
|
||||||
fields = (
|
fields = [
|
||||||
'id',
|
'id',
|
||||||
'file',
|
'file',
|
||||||
'url',
|
'url',
|
||||||
|
|
@ -29,5 +28,4 @@ class ImageSerializer(serializers.ModelSerializer):
|
||||||
'orientation',
|
'orientation',
|
||||||
'orientation_display',
|
'orientation_display',
|
||||||
'title',
|
'title',
|
||||||
)
|
]
|
||||||
|
|
||||||
|
|
|
||||||
14
apps/news/migrations/0020_merge_20190930_1251.py
Normal file
14
apps/news/migrations/0020_merge_20190930_1251.py
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-09-30 12:51
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('news', '0019_news_author'),
|
||||||
|
('news', '0016_news_gallery'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
]
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from account.serializers.common import UserSerializer
|
||||||
from gallery.models import Image
|
from gallery.models import Image
|
||||||
from gallery.serializers import ImageSerializer
|
from gallery.serializers import ImageSerializer
|
||||||
from location import models as location_models
|
from location import models as location_models
|
||||||
|
|
@ -9,7 +10,26 @@ from location.serializers import CountrySimpleSerializer
|
||||||
from main.serializers import MetaDataContentSerializer
|
from main.serializers import MetaDataContentSerializer
|
||||||
from news import models
|
from news import models
|
||||||
from utils.serializers import TranslatedField
|
from utils.serializers import TranslatedField
|
||||||
from account.serializers.common import UserSerializer
|
|
||||||
|
|
||||||
|
class NewsImageSerializer(ImageSerializer):
|
||||||
|
"""News images"""
|
||||||
|
promo_web_url = serializers.SerializerMethodField()
|
||||||
|
promo_mobile_url = serializers.SerializerMethodField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Image
|
||||||
|
fields = ImageSerializer.Meta.fields + [
|
||||||
|
'promo_web_url',
|
||||||
|
'promo_mobile_url'
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_promo_web_url(self, obj):
|
||||||
|
return obj.get_image_url(thumbnail_key='news_promo_horizontal_web')
|
||||||
|
|
||||||
|
def get_promo_mobile_url(self, obj):
|
||||||
|
return obj.get_image_url(thumbnail_key='news_promo_horizontal_mobile')
|
||||||
|
|
||||||
|
|
||||||
class NewsTypeSerializer(serializers.ModelSerializer):
|
class NewsTypeSerializer(serializers.ModelSerializer):
|
||||||
"""News type serializer."""
|
"""News type serializer."""
|
||||||
|
|
@ -31,7 +51,7 @@ class NewsBaseSerializer(serializers.ModelSerializer):
|
||||||
# related fields
|
# related fields
|
||||||
news_type = NewsTypeSerializer(read_only=True)
|
news_type = NewsTypeSerializer(read_only=True)
|
||||||
tags = MetaDataContentSerializer(read_only=True, many=True)
|
tags = MetaDataContentSerializer(read_only=True, many=True)
|
||||||
gallery = ImageSerializer(read_only=True, many=True)
|
gallery = NewsImageSerializer(read_only=True, many=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Meta class."""
|
"""Meta class."""
|
||||||
|
|
@ -115,14 +135,11 @@ class NewsBackOfficeDetailSerializer(NewsBackOfficeBaseSerializer,
|
||||||
|
|
||||||
class NewsBackOfficeGallerySerializer(serializers.ModelSerializer):
|
class NewsBackOfficeGallerySerializer(serializers.ModelSerializer):
|
||||||
"""Serializer class for model NewsGallery."""
|
"""Serializer class for model NewsGallery."""
|
||||||
image = ImageSerializer(read_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Meta class"""
|
"""Meta class"""
|
||||||
model = models.NewsGallery
|
model = models.NewsGallery
|
||||||
fields = [
|
fields = [
|
||||||
'id',
|
'id',
|
||||||
'image',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_request_kwargs(self):
|
def get_request_kwargs(self):
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
"""News app views."""
|
"""News app views."""
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from rest_framework import generics, permissions
|
from rest_framework import generics, permissions, status
|
||||||
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from gallery.serializers import ImageSerializer
|
|
||||||
from news import filters, models, serializers
|
from news import filters, models, serializers
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -82,10 +82,15 @@ class NewsBackOfficeGalleryCreateDestroyView(NewsBackOfficeMixinView,
|
||||||
|
|
||||||
return gallery
|
return gallery
|
||||||
|
|
||||||
|
def create(self, request, *args, **kwargs):
|
||||||
|
"""Override create method"""
|
||||||
|
super().create(request, *args, **kwargs)
|
||||||
|
return Response(status=status.HTTP_201_CREATED)
|
||||||
|
|
||||||
|
|
||||||
class NewsBackOfficeGalleryListView(NewsBackOfficeMixinView, generics.ListAPIView):
|
class NewsBackOfficeGalleryListView(NewsBackOfficeMixinView, generics.ListAPIView):
|
||||||
"""Resource for returning gallery for news for back-office users."""
|
"""Resource for returning gallery for news for back-office users."""
|
||||||
serializer_class = ImageSerializer
|
serializer_class = serializers.NewsImageSerializer
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
"""Override get_object method."""
|
"""Override get_object method."""
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
"""Utils app method."""
|
"""Utils app method."""
|
||||||
|
import logging
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
import string
|
import string
|
||||||
|
|
@ -10,6 +11,9 @@ from django.http.request import HttpRequest
|
||||||
from django.utils.timezone import datetime
|
from django.utils.timezone import datetime
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
|
from os.path import exists
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def generate_code(digits=6, string_output=True):
|
def generate_code(digits=6, string_output=True):
|
||||||
|
|
@ -91,12 +95,18 @@ def get_contenttype(app_label: str, model: str):
|
||||||
|
|
||||||
|
|
||||||
def image_url_valid(url: str):
|
def image_url_valid(url: str):
|
||||||
# In case if image storage is not on CDN
|
"""
|
||||||
if url.startswith('/media/'):
|
Check if requested URL is valid.
|
||||||
url = f'{settings.SCHEMA_URI}://{settings.DOMAIN_URI}{url}'
|
:param url: string
|
||||||
|
:return: boolean
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
assert url.startswith('http')
|
||||||
response = requests.request('head', url)
|
response = requests.request('head', url)
|
||||||
if response.status_code == status.HTTP_200_OK:
|
except Exception as e:
|
||||||
return True
|
logger.info(f'ConnectionError: {e}')
|
||||||
|
else:
|
||||||
|
return response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
|
|
||||||
def absolute_url_decorator(func):
|
def absolute_url_decorator(func):
|
||||||
|
|
@ -105,7 +115,7 @@ def absolute_url_decorator(func):
|
||||||
url_path = func(self, obj)
|
url_path = func(self, obj)
|
||||||
if url_path:
|
if url_path:
|
||||||
if url_path.startswith('/media/'):
|
if url_path.startswith('/media/'):
|
||||||
return f'{settings.SCHEMA_URI}://{settings.DOMAIN_URI}{url_path}/'
|
return f'{settings.MEDIA_URL}{url_path}/'
|
||||||
else:
|
else:
|
||||||
return url_path
|
return url_path
|
||||||
return get_absolute_image_url
|
return get_absolute_image_url
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
"""Utils app models."""
|
"""Utils app models."""
|
||||||
|
import logging
|
||||||
from os.path import exists
|
from os.path import exists
|
||||||
from django.contrib.auth.tokens import PasswordResetTokenGenerator
|
from django.contrib.auth.tokens import PasswordResetTokenGenerator
|
||||||
from django.contrib.gis.db import models
|
from django.contrib.gis.db import models
|
||||||
|
|
@ -10,8 +11,12 @@ from django.utils.translation import ugettext_lazy as _, get_language
|
||||||
from easy_thumbnails.fields import ThumbnailerImageField
|
from easy_thumbnails.fields import ThumbnailerImageField
|
||||||
from utils.methods import image_path, svg_image_path
|
from utils.methods import image_path, svg_image_path
|
||||||
from utils.validators import svg_image_validator
|
from utils.validators import svg_image_validator
|
||||||
from django.db.models.fields import Field
|
from sorl.thumbnail.fields import ImageField as SORLImageField
|
||||||
from django.core import exceptions
|
from sorl.thumbnail import get_thumbnail
|
||||||
|
from django.conf import settings
|
||||||
|
from utils.methods import image_url_valid
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class ProjectBaseMixin(models.Model):
|
class ProjectBaseMixin(models.Model):
|
||||||
|
|
@ -177,6 +182,38 @@ class ImageMixin(models.Model):
|
||||||
image_tag.allow_tags = True
|
image_tag.allow_tags = True
|
||||||
|
|
||||||
|
|
||||||
|
class SORLImageMixin(models.Model):
|
||||||
|
"""Abstract model for SORL ImageField"""
|
||||||
|
|
||||||
|
image = SORLImageField(upload_to=image_path,
|
||||||
|
blank=True, null=True, default=None,
|
||||||
|
verbose_name=_('Image'))
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""Meta class."""
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def get_image(self, thumbnail_key=None):
|
||||||
|
"""Get thumbnail image file."""
|
||||||
|
if thumbnail_key in settings.SORL_THUMBNAIL_ALIASES:
|
||||||
|
return get_thumbnail(file_=self.image,
|
||||||
|
**settings.SORL_THUMBNAIL_ALIASES[thumbnail_key])
|
||||||
|
|
||||||
|
def get_image_url(self, thumbnail_key=None):
|
||||||
|
"""Get image thumbnail url."""
|
||||||
|
return self.get_image(thumbnail_key).url
|
||||||
|
|
||||||
|
def image_tag(self):
|
||||||
|
"""Admin preview tag."""
|
||||||
|
if self.image:
|
||||||
|
return mark_safe('<img src="%s" />' % self.image.url)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
image_tag.short_description = _('Image')
|
||||||
|
image_tag.allow_tags = True
|
||||||
|
|
||||||
|
|
||||||
class SVGImageMixin(models.Model):
|
class SVGImageMixin(models.Model):
|
||||||
"""SVG image model."""
|
"""SVG image model."""
|
||||||
|
|
||||||
|
|
|
||||||
19
project/settings/amazon_s3.py
Normal file
19
project/settings/amazon_s3.py
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
"""Settings for Amazon S3"""
|
||||||
|
import os
|
||||||
|
from .base import MEDIA_LOCATION
|
||||||
|
|
||||||
|
# AMAZON S3
|
||||||
|
AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_KEY_ID')
|
||||||
|
AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_ACCESS_KEY')
|
||||||
|
AWS_STORAGE_BUCKET_NAME = os.getenv('AWS_STORAGE_BUCKET_NAME')
|
||||||
|
AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
|
||||||
|
AWS_S3_OBJECT_PARAMETERS = {'CacheControl': 'max-age=86400'}
|
||||||
|
|
||||||
|
# Static settings
|
||||||
|
# PUBLIC_STATIC_LOCATION = 'static'
|
||||||
|
# STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{PUBLIC_STATIC_LOCATION}/'
|
||||||
|
# STATICFILES_STORAGE = 'project.storage_backends.PublicStaticStorage'
|
||||||
|
|
||||||
|
# Public media settings
|
||||||
|
MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{MEDIA_LOCATION}/'
|
||||||
|
DEFAULT_FILE_STORAGE = 'project.storage_backends.PublicMediaStorage'
|
||||||
|
|
@ -91,6 +91,8 @@ EXTERNAL_APPS = [
|
||||||
'rest_framework_simplejwt.token_blacklist',
|
'rest_framework_simplejwt.token_blacklist',
|
||||||
'solo',
|
'solo',
|
||||||
'phonenumber_field',
|
'phonenumber_field',
|
||||||
|
'storages',
|
||||||
|
'sorl.thumbnail',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -190,19 +192,6 @@ LOCALE_PATHS = (
|
||||||
os.path.abspath(os.path.join(BASE_DIR, 'locale')),
|
os.path.abspath(os.path.join(BASE_DIR, 'locale')),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Static files (CSS, JavaScript, Images)
|
|
||||||
# https://docs.djangoproject.com/en/2.2/howto/static-files/
|
|
||||||
|
|
||||||
STATIC_ROOT = os.path.join(PUBLIC_ROOT, 'static')
|
|
||||||
STATIC_URL = '/static/'
|
|
||||||
|
|
||||||
MEDIA_ROOT = os.path.join(PUBLIC_ROOT, 'media')
|
|
||||||
MEDIA_URL = '/media/'
|
|
||||||
|
|
||||||
STATICFILES_DIRS = (
|
|
||||||
os.path.join(PROJECT_ROOT, 'static'),
|
|
||||||
)
|
|
||||||
|
|
||||||
AVAILABLE_VERSIONS = {
|
AVAILABLE_VERSIONS = {
|
||||||
# 'future': '1.0.1',
|
# 'future': '1.0.1',
|
||||||
'current': '1.0.0',
|
'current': '1.0.0',
|
||||||
|
|
@ -262,6 +251,7 @@ SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS = {
|
||||||
'fields': 'id, name, email',
|
'fields': 'id, name, email',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# SMS Settings
|
# SMS Settings
|
||||||
SMS_EXPIRATION = 5
|
SMS_EXPIRATION = 5
|
||||||
SMS_SEND_DELAY = 30
|
SMS_SEND_DELAY = 30
|
||||||
|
|
@ -272,12 +262,14 @@ SMS_CODE_LENGTH = 6
|
||||||
SEND_SMS = True
|
SEND_SMS = True
|
||||||
SMS_CODE_SHOW = False
|
SMS_CODE_SHOW = False
|
||||||
|
|
||||||
|
|
||||||
# SMSC Settings
|
# SMSC Settings
|
||||||
SMS_SERVICE = 'http://smsc.ru/sys/send.php'
|
SMS_SERVICE = 'http://smsc.ru/sys/send.php'
|
||||||
SMS_LOGIN = 'GM2019'
|
SMS_LOGIN = 'GM2019'
|
||||||
SMS_PASSWORD = '}#6%Qe7CYG7n'
|
SMS_PASSWORD = '}#6%Qe7CYG7n'
|
||||||
SMS_SENDER = 'GM'
|
SMS_SENDER = 'GM'
|
||||||
|
|
||||||
|
|
||||||
# EMAIL
|
# EMAIL
|
||||||
EMAIL_USE_TLS = True
|
EMAIL_USE_TLS = True
|
||||||
EMAIL_HOST = 'smtp.gmail.com'
|
EMAIL_HOST = 'smtp.gmail.com'
|
||||||
|
|
@ -285,6 +277,7 @@ EMAIL_HOST_USER = 'anatolyfeteleu@gmail.com'
|
||||||
EMAIL_HOST_PASSWORD = 'nggrlnbehzksgmbt'
|
EMAIL_HOST_PASSWORD = 'nggrlnbehzksgmbt'
|
||||||
EMAIL_PORT = 587
|
EMAIL_PORT = 587
|
||||||
|
|
||||||
|
|
||||||
# Django Rest Swagger
|
# Django Rest Swagger
|
||||||
SWAGGER_SETTINGS = {
|
SWAGGER_SETTINGS = {
|
||||||
# "DEFAULT_GENERATOR_CLASS": "rest_framework.schemas.generators.BaseSchemaGenerator",
|
# "DEFAULT_GENERATOR_CLASS": "rest_framework.schemas.generators.BaseSchemaGenerator",
|
||||||
|
|
@ -307,6 +300,7 @@ REDOC_SETTINGS = {
|
||||||
'LAZY_RENDERING': False,
|
'LAZY_RENDERING': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# CELERY
|
# CELERY
|
||||||
BROKER_URL = 'amqp://rabbitmq:5672'
|
BROKER_URL = 'amqp://rabbitmq:5672'
|
||||||
CELERY_RESULT_BACKEND = BROKER_URL
|
CELERY_RESULT_BACKEND = BROKER_URL
|
||||||
|
|
@ -316,6 +310,7 @@ CELERY_TASK_SERIALIZER = 'json'
|
||||||
CELERY_RESULT_SERIALIZER = 'json'
|
CELERY_RESULT_SERIALIZER = 'json'
|
||||||
CELERY_TIMEZONE = TIME_ZONE
|
CELERY_TIMEZONE = TIME_ZONE
|
||||||
|
|
||||||
|
|
||||||
# Django FCM (Firebase push notifications)
|
# Django FCM (Firebase push notifications)
|
||||||
FCM_DJANGO_SETTINGS = {
|
FCM_DJANGO_SETTINGS = {
|
||||||
'FCM_SERVER_KEY': (
|
'FCM_SERVER_KEY': (
|
||||||
|
|
@ -325,6 +320,7 @@ FCM_DJANGO_SETTINGS = {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Thumbnail settings
|
# Thumbnail settings
|
||||||
THUMBNAIL_ALIASES = {
|
THUMBNAIL_ALIASES = {
|
||||||
'': {
|
'': {
|
||||||
|
|
@ -345,11 +341,23 @@ THUMBNAIL_DEFAULT_OPTIONS = {
|
||||||
'crop': 'smart',
|
'crop': 'smart',
|
||||||
}
|
}
|
||||||
|
|
||||||
# Password reset
|
|
||||||
RESETTING_TOKEN_EXPIRATION = 24 # hours
|
|
||||||
|
|
||||||
|
# SORL
|
||||||
|
THUMBNAIL_QUALITY = 85
|
||||||
|
THUMBNAIL_DEBUG = False
|
||||||
|
SORL_THUMBNAIL_ALIASES = {
|
||||||
|
'news_preview': {'geometry_string': '100x100', 'crop': 'center'},
|
||||||
|
'news_promo_horizontal_web': {'geometry_string': '1900x600', 'crop': 'center'},
|
||||||
|
'news_promo_horizontal_mobile': {'geometry_string': '375x260', 'crop': 'center'},
|
||||||
|
'news_tile_horizontal_web': {'geometry_string': '300x275', 'crop': 'center'},
|
||||||
|
'news_tile_horizontal_mobile': {'geometry_string': '343x180', 'crop': 'center'},
|
||||||
|
'news_tile_vertical_web': {'geometry_string': '300x380', 'crop': 'center'},
|
||||||
|
'news_highlight_vertical_web': {'geometry_string': '460x630', 'crop': 'center'},
|
||||||
|
'news_editor_web': {'geometry_string': '940x430', 'crop': 'center'},
|
||||||
|
'news_editor_mobile': {'geometry_string': '343x260', 'crop': 'center'}, # при загрузке через контент эдитор
|
||||||
|
'avatar_comments_web': {'geometry_string': '116x116', 'crop': 'center'}, # через контент эдитор в мобильном браузерe
|
||||||
|
}
|
||||||
|
|
||||||
GEOIP_PATH = os.path.join(PROJECT_ROOT, 'geoip_db')
|
|
||||||
|
|
||||||
# JWT
|
# JWT
|
||||||
SIMPLE_JWT = {
|
SIMPLE_JWT = {
|
||||||
|
|
@ -409,17 +417,20 @@ DATA_UPLOAD_MAX_MEMORY_SIZE = 5242880 # 5MB
|
||||||
FILE_UPLOAD_MAX_MEMORY_SIZE = 5242880 # 5MB
|
FILE_UPLOAD_MAX_MEMORY_SIZE = 5242880 # 5MB
|
||||||
FILE_UPLOAD_PERMISSIONS = 0o644
|
FILE_UPLOAD_PERMISSIONS = 0o644
|
||||||
|
|
||||||
|
|
||||||
# SOLO SETTINGS
|
# SOLO SETTINGS
|
||||||
# todo: make a separate service (redis?) and update solo_cache
|
# todo: make a separate service (redis?) and update solo_cache
|
||||||
SOLO_CACHE = 'default'
|
SOLO_CACHE = 'default'
|
||||||
SOLO_CACHE_PREFIX = 'solo'
|
SOLO_CACHE_PREFIX = 'solo'
|
||||||
SOLO_CACHE_TIMEOUT = 300
|
SOLO_CACHE_TIMEOUT = 300
|
||||||
|
|
||||||
|
|
||||||
# REDIRECT URL
|
# REDIRECT URL
|
||||||
SITE_REDIRECT_URL_UNSUBSCRIBE = '/unsubscribe/'
|
SITE_REDIRECT_URL_UNSUBSCRIBE = '/unsubscribe/'
|
||||||
|
|
||||||
SITE_NAME = 'Gault & Millau'
|
SITE_NAME = 'Gault & Millau'
|
||||||
|
|
||||||
|
|
||||||
# Used in annotations for establishments.
|
# Used in annotations for establishments.
|
||||||
DEFAULT_ESTABLISHMENT_PUBLIC_MARK = 10
|
DEFAULT_ESTABLISHMENT_PUBLIC_MARK = 10
|
||||||
# Limit output objects (see in pagination classes).
|
# Limit output objects (see in pagination classes).
|
||||||
|
|
@ -427,6 +438,19 @@ QUERY_OUTPUT_OBJECTS = 12
|
||||||
# Need to restrict objects to sort (3 times more then expected).
|
# Need to restrict objects to sort (3 times more then expected).
|
||||||
LIMITING_QUERY_OBJECTS = QUERY_OUTPUT_OBJECTS * 3
|
LIMITING_QUERY_OBJECTS = QUERY_OUTPUT_OBJECTS * 3
|
||||||
|
|
||||||
|
|
||||||
# GEO
|
# GEO
|
||||||
# A Spatial Reference System Identifier
|
# A Spatial Reference System Identifier
|
||||||
GEO_DEFAULT_SRID = 4326
|
GEO_DEFAULT_SRID = 4326
|
||||||
|
GEOIP_PATH = os.path.join(PROJECT_ROOT, 'geoip_db')
|
||||||
|
|
||||||
|
# Static files (CSS, JavaScript, Images)
|
||||||
|
# https://docs.djangoproject.com/en/2.2/howto/static-files/
|
||||||
|
STATIC_ROOT = os.path.join(PUBLIC_ROOT, 'static')
|
||||||
|
STATIC_URL = '/static/'
|
||||||
|
|
||||||
|
STATICFILES_DIRS = (
|
||||||
|
os.path.join(PROJECT_ROOT, 'static'),
|
||||||
|
)
|
||||||
|
|
||||||
|
MEDIA_LOCATION = 'media'
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
"""Development settings."""
|
"""Development settings."""
|
||||||
from .base import *
|
from .base import *
|
||||||
|
from .amazon_s3 import *
|
||||||
import sentry_sdk
|
import sentry_sdk
|
||||||
from sentry_sdk.integrations.django import DjangoIntegration
|
from sentry_sdk.integrations.django import DjangoIntegration
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['gm.id-east.ru', '95.213.204.126']
|
ALLOWED_HOSTS = ['gm.id-east.ru', '95.213.204.126', '0.0.0.0']
|
||||||
|
|
||||||
SEND_SMS = False
|
SEND_SMS = False
|
||||||
SMS_CODE_SHOW = True
|
SMS_CODE_SHOW = True
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ BROKER_URL = 'amqp://rabbitmq:5672'
|
||||||
CELERY_RESULT_BACKEND = BROKER_URL
|
CELERY_RESULT_BACKEND = BROKER_URL
|
||||||
CELERY_BROKER_URL = BROKER_URL
|
CELERY_BROKER_URL = BROKER_URL
|
||||||
|
|
||||||
|
MEDIA_ROOT = os.path.join(PUBLIC_ROOT, MEDIA_LOCATION)
|
||||||
|
MEDIA_URL = f'{SCHEMA_URI}://{DOMAIN_URI}/{MEDIA_LOCATION}/'
|
||||||
|
|
||||||
# LOGGING
|
# LOGGING
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
|
|
@ -62,8 +64,10 @@ ELASTICSEARCH_DSL = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ELASTICSEARCH_INDEX_NAMES = {
|
ELASTICSEARCH_INDEX_NAMES = {
|
||||||
# 'search_indexes.documents.news': 'local_news',
|
# 'search_indexes.documents.news': 'local_news',
|
||||||
'search_indexes.documents.establishment': 'local_establishment',
|
'search_indexes.documents.establishment': 'local_establishment',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# SORL thumbnails
|
||||||
|
THUMBNAIL_DEBUG = True
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
"""Production settings."""
|
"""Production settings."""
|
||||||
from .base import *
|
from .base import *
|
||||||
|
from .amazon_s3 import *
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
"""Stage settings."""
|
"""Stage settings."""
|
||||||
from .base import *
|
from .base import *
|
||||||
|
from .amazon_s3 import *
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['gm-stage.id-east.ru', '95.213.204.126']
|
ALLOWED_HOSTS = ['gm-stage.id-east.ru', '95.213.204.126']
|
||||||
|
|
||||||
|
|
|
||||||
12
project/storage_backends.py
Normal file
12
project/storage_backends.py
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
"""Extend storage backend for adding custom parameters"""
|
||||||
|
from storages.backends.s3boto3 import S3Boto3Storage
|
||||||
|
|
||||||
|
|
||||||
|
class PublicMediaStorage(S3Boto3Storage):
|
||||||
|
location = 'media'
|
||||||
|
file_overwrite = False
|
||||||
|
|
||||||
|
|
||||||
|
class PublicStaticStorage(S3Boto3Storage):
|
||||||
|
location = 'static'
|
||||||
|
file_overwrite = False
|
||||||
|
|
@ -64,7 +64,7 @@ urlpatterns = [
|
||||||
]
|
]
|
||||||
|
|
||||||
urlpatterns = urlpatterns + \
|
urlpatterns = urlpatterns + \
|
||||||
static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
static(settings.MEDIA_LOCATION, document_root=settings.MEDIA_ROOT)
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
urlpatterns.extend(urlpatterns_doc)
|
urlpatterns.extend(urlpatterns_doc)
|
||||||
|
|
|
||||||
|
|
@ -33,3 +33,9 @@ djangorestframework-simplejwt==4.3.0
|
||||||
django-elasticsearch-dsl>=7.0.0,<8.0.0
|
django-elasticsearch-dsl>=7.0.0,<8.0.0
|
||||||
django-elasticsearch-dsl-drf==0.20.2
|
django-elasticsearch-dsl-drf==0.20.2
|
||||||
sentry-sdk==0.11.2
|
sentry-sdk==0.11.2
|
||||||
|
|
||||||
|
# AMAZON S3
|
||||||
|
boto3==1.9.238
|
||||||
|
django-storages==1.7.2
|
||||||
|
|
||||||
|
sorl-thumbnail==12.5.0
|
||||||
Loading…
Reference in New Issue
Block a user