Merge branch 'develop' into feature/guides
This commit is contained in:
commit
a59016944c
|
|
@ -8,6 +8,7 @@ from rest_framework import serializers
|
|||
from rest_framework import validators as rest_validators
|
||||
|
||||
from account import models, tasks
|
||||
from notification.models import Subscriber
|
||||
from utils import exceptions as utils_exceptions
|
||||
from utils import methods as utils_methods
|
||||
|
||||
|
|
@ -46,6 +47,12 @@ class UserSerializer(serializers.ModelSerializer):
|
|||
'newsletter',
|
||||
]
|
||||
|
||||
def create(self, validated_data):
|
||||
user = super(UserSerializer, self).create(validated_data)
|
||||
validated_data['user'] = user
|
||||
Subscriber.objects.make_subscriber(**validated_data)
|
||||
return user
|
||||
|
||||
def validate_email(self, value):
|
||||
"""Validate email value"""
|
||||
if value == self.instance.email:
|
||||
|
|
|
|||
|
|
@ -1,43 +1,60 @@
|
|||
from datetime import datetime
|
||||
from smtplib import SMTPException
|
||||
|
||||
from celery import shared_task
|
||||
from django.core.mail import send_mail
|
||||
from notification.models import Subscriber
|
||||
from news import models
|
||||
from django.template.loader import render_to_string, get_template
|
||||
from django.conf import settings
|
||||
from smtplib import SMTPException
|
||||
from django.core.mail import send_mail
|
||||
from django.core.validators import EMPTY_VALUES
|
||||
from django.template.loader import get_template, render_to_string
|
||||
|
||||
from main.models import SiteSettings
|
||||
from news import models
|
||||
from notification.models import Subscribe
|
||||
|
||||
|
||||
@shared_task
|
||||
def send_email_with_news(news_ids):
|
||||
subscribers = Subscriber.objects.filter(state=Subscriber.USABLE)
|
||||
subscribes = Subscribe.objects.all() \
|
||||
.prefetch_related('subscriber') \
|
||||
.prefetch_related('subscription_type')
|
||||
sent_news = models.News.objects.filter(id__in=news_ids)
|
||||
|
||||
htmly = get_template(settings.NEWS_EMAIL_TEMPLATE)
|
||||
year = datetime.now().year
|
||||
socials = list(SiteSettings.objects.with_country())
|
||||
socials = dict(zip(map(lambda s: s.country.code, socials), socials))
|
||||
for s in subscribers:
|
||||
socials_for_subscriber = socials.get(s.country_code)
|
||||
|
||||
socials = list(SiteSettings.objects.with_country().select_related('country'))
|
||||
socials = dict(zip(map(lambda social: social.country.code, socials), socials))
|
||||
|
||||
for subscribe in subscribes.filter(unsubscribe_date=None):
|
||||
country = subscribe.subscription_type.country
|
||||
|
||||
if country is None:
|
||||
continue
|
||||
|
||||
socials_for_subscriber = socials.get(country.code)
|
||||
subscriber = subscribe.subscriber
|
||||
|
||||
try:
|
||||
for n in sent_news:
|
||||
context = {"title": n.title.get(s.locale),
|
||||
"subtitle": n.subtitle.get(s.locale),
|
||||
"description": n.description.get(s.locale),
|
||||
"code": s.update_code,
|
||||
"image_url": n.image_url if n.image_url not in EMPTY_VALUES else None,
|
||||
"domain_uri": settings.DOMAIN_URI,
|
||||
"slug": n.slug,
|
||||
"country_code": s.country_code,
|
||||
"twitter_page_url": socials_for_subscriber.twitter_page_url if socials_for_subscriber else '#',
|
||||
"instagram_page_url": socials_for_subscriber.instagram_page_url if socials_for_subscriber else '#',
|
||||
"facebook_page_url": socials_for_subscriber.facebook_page_url if socials_for_subscriber else '#',
|
||||
"send_to": s.send_to,
|
||||
"year": year}
|
||||
send_mail("G&M News", render_to_string(settings.NEWS_EMAIL_TEMPLATE, context),
|
||||
settings.EMAIL_HOST_USER, [s.send_to], fail_silently=False,
|
||||
html_message=htmly.render(context))
|
||||
for new in sent_news:
|
||||
context = {
|
||||
"title": new.title.get(subscriber.locale),
|
||||
"subtitle": new.subtitle.get(subscriber.locale),
|
||||
"description": new.description.get(subscriber.locale),
|
||||
"code": subscriber.update_code,
|
||||
"image_url": new.image_url if new.image_url not in EMPTY_VALUES else None,
|
||||
"domain_uri": settings.DOMAIN_URI,
|
||||
"slug": new.slug,
|
||||
"country_code": subscriber.country_code,
|
||||
"twitter_page_url": socials_for_subscriber.twitter_page_url if socials_for_subscriber else '#',
|
||||
"instagram_page_url": socials_for_subscriber.instagram_page_url if socials_for_subscriber else '#',
|
||||
"facebook_page_url": socials_for_subscriber.facebook_page_url if socials_for_subscriber else '#',
|
||||
"send_to": subscriber.send_to,
|
||||
"year": year
|
||||
}
|
||||
send_mail(
|
||||
"G&M News", render_to_string(settings.NEWS_EMAIL_TEMPLATE, context),
|
||||
settings.EMAIL_HOST_USER, [subscriber.send_to], fail_silently=False,
|
||||
html_message=htmly.render(context)
|
||||
)
|
||||
except SMTPException:
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ def add_tags():
|
|||
)
|
||||
if created:
|
||||
text_value = ' '.join(new_tag.value.split('_'))
|
||||
translation = SiteInterfaceDictionary(page={'en-GB': text_value}, keywords=f'tag.{new_tag.category}.{new_tag.value}')
|
||||
translation = SiteInterfaceDictionary(text={'en-GB': text_value}, keywords=f'tag.{new_tag.category}.{new_tag.value}')
|
||||
translation.save()
|
||||
new_tag.translation = translation
|
||||
new_tag.save()
|
||||
|
|
|
|||
|
|
@ -2,17 +2,17 @@
|
|||
from django.urls import path
|
||||
|
||||
from news import views
|
||||
from search_indexes.views import NewsDocumentViewSet
|
||||
|
||||
app_name = 'news'
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.NewsBackOfficeLCView.as_view(), name='list-create'),
|
||||
path('<int:pk>/', views.NewsBackOfficeRUDView.as_view(),
|
||||
name='retrieve-update-destroy'),
|
||||
path('<int:pk>/gallery/', views.NewsBackOfficeGalleryListView.as_view(),
|
||||
name='gallery-list'),
|
||||
path('<int:pk>/', views.NewsBackOfficeRUDView.as_view(), name='retrieve-update-destroy'),
|
||||
path('<int:pk>/gallery/', views.NewsBackOfficeGalleryListView.as_view(), name='gallery-list'),
|
||||
path('<int:pk>/gallery/<int:image_id>/', views.NewsBackOfficeGalleryCreateDestroyView.as_view(),
|
||||
name='gallery-create-destroy'),
|
||||
path('<int:pk>/carousels/', views.NewsCarouselCreateDestroyView.as_view(), name='create-destroy-carousels'),
|
||||
path('<int:pk>/clone/<str:country_code>', views.NewsCloneView.as_view(), name='clone-news-item'),
|
||||
path('search/', NewsDocumentViewSet.as_view({'get': 'list'}), name='search-news'),
|
||||
]
|
||||
|
|
|
|||
38
apps/notification/migrations/0005_auto_20191227_1212.py
Normal file
38
apps/notification/migrations/0005_auto_20191227_1212.py
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# Generated by Django 2.2.7 on 2019-12-27 12:12
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('notification', '0004_auto_20191118_1307'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='subscriber',
|
||||
name='subscription_type',
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Subscribe',
|
||||
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')),
|
||||
('subscriber', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='notification.Subscriber')),
|
||||
('subscription_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='notification.SubscriptionType')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Subscribe',
|
||||
'verbose_name_plural': 'Subscribes',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='subscriber',
|
||||
name='subscription_types',
|
||||
field=models.ManyToManyField(through='notification.Subscribe', to='notification.SubscriptionType'),
|
||||
),
|
||||
]
|
||||
24
apps/notification/migrations/0006_auto_20191227_1216.py
Normal file
24
apps/notification/migrations/0006_auto_20191227_1216.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 2.2.7 on 2019-12-27 12:16
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('notification', '0005_auto_20191227_1212'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='subscribe',
|
||||
name='subscribe_date',
|
||||
field=models.DateTimeField(blank=True, default=django.utils.timezone.now, null=True, verbose_name='Last subscribe date'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='subscribe',
|
||||
name='unsubscribe_date',
|
||||
field=models.DateTimeField(blank=True, default=None, null=True, verbose_name='Last unsubscribe date'),
|
||||
),
|
||||
]
|
||||
22
apps/notification/migrations/0007_auto_20191227_1426.py
Normal file
22
apps/notification/migrations/0007_auto_20191227_1426.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# Generated by Django 2.2.7 on 2019-12-27 14:26
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('notification', '0006_auto_20191227_1216'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='subscriber',
|
||||
name='state',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='subscribe',
|
||||
name='state',
|
||||
field=models.PositiveIntegerField(choices=[(0, 'Unusable'), (1, 'Usable')], default=1, verbose_name='State'),
|
||||
),
|
||||
]
|
||||
17
apps/notification/migrations/0008_remove_subscribe_state.py
Normal file
17
apps/notification/migrations/0008_remove_subscribe_state.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# Generated by Django 2.2.7 on 2019-12-30 15:04
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('notification', '0007_auto_20191227_1426'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='subscribe',
|
||||
name='state',
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 2.2.7 on 2019-12-31 01:31
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('location', '0033_merge_20191224_0920'),
|
||||
('notification', '0008_remove_subscribe_state'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='subscriptiontype',
|
||||
name='country',
|
||||
field=models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='location.Country', verbose_name='Country'),
|
||||
),
|
||||
]
|
||||
19
apps/notification/migrations/0010_auto_20191231_0135.py
Normal file
19
apps/notification/migrations/0010_auto_20191231_0135.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 2.2.7 on 2019-12-31 01:35
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('notification', '0009_subscriptiontype_country'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='subscriptiontype',
|
||||
name='country',
|
||||
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.PROTECT, to='location.Country', verbose_name='country'),
|
||||
),
|
||||
]
|
||||
|
|
@ -1,10 +1,14 @@
|
|||
"""Notification app models."""
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from account.models import User
|
||||
from location.models import Country
|
||||
from utils.methods import generate_string_code
|
||||
from utils.models import ProjectBaseMixin, TranslatedFieldsMixin, TJSONField
|
||||
from utils.models import ProjectBaseMixin, TJSONField, TranslatedFieldsMixin
|
||||
|
||||
|
||||
class SubscriptionType(ProjectBaseMixin, TranslatedFieldsMixin):
|
||||
|
|
@ -12,6 +16,9 @@ class SubscriptionType(ProjectBaseMixin, TranslatedFieldsMixin):
|
|||
name = TJSONField(blank=True, null=True, default=None,
|
||||
verbose_name=_('name'),
|
||||
help_text='{"en-GB":"some text"}')
|
||||
country = models.ForeignKey(Country, on_delete=models.PROTECT,
|
||||
blank=True, null=True, default=None,
|
||||
verbose_name=_('country'))
|
||||
|
||||
|
||||
# todo: associate user & subscriber after users registration
|
||||
|
|
@ -19,7 +26,7 @@ class SubscriberManager(models.Manager):
|
|||
"""Extended manager for Subscriber model."""
|
||||
|
||||
def make_subscriber(self, email=None, user=None, ip_address=None, country_code=None,
|
||||
locale=None, subscription_type=None, *args, **kwargs):
|
||||
locale=None, subscription_types=None, *args, **kwargs):
|
||||
"""Make subscriber and update info."""
|
||||
# search existing object
|
||||
if not user:
|
||||
|
|
@ -40,14 +47,15 @@ class SubscriberManager(models.Manager):
|
|||
obj.ip_address = ip_address
|
||||
obj.country_code = country_code
|
||||
obj.locale = locale
|
||||
obj.state = self.model.USABLE
|
||||
obj.update_code = generate_string_code()
|
||||
obj.subscription_type = subscription_type
|
||||
obj.save()
|
||||
obj.subscription_types.set(subscription_types)
|
||||
obj.subscribe_set.update(unsubscribe_date=None)
|
||||
else:
|
||||
obj = self.model.objects.create(user=user, email=email, ip_address=ip_address,
|
||||
country_code=country_code, locale=locale,
|
||||
subscription_type=subscription_type)
|
||||
country_code=country_code, locale=locale)
|
||||
obj.subscription_types.set(subscription_types)
|
||||
obj.subscribe_set.update(unsubscribe_date=None)
|
||||
return obj
|
||||
|
||||
def associate_user(self, user):
|
||||
|
|
@ -62,27 +70,9 @@ class SubscriberManager(models.Manager):
|
|||
return obj
|
||||
|
||||
|
||||
class SubscriberQuerySet(models.QuerySet):
|
||||
"""Extended queryset for Subscriber model."""
|
||||
|
||||
def by_usable(self, switcher=True):
|
||||
if switcher:
|
||||
return self.filter(state=self.model.USABLE)
|
||||
else:
|
||||
return self.filter(state=self.model.UNUSABLE)
|
||||
|
||||
|
||||
class Subscriber(ProjectBaseMixin):
|
||||
"""Subscriber model."""
|
||||
|
||||
UNUSABLE = 0
|
||||
USABLE = 1
|
||||
|
||||
STATE_CHOICES = (
|
||||
(UNUSABLE, _('Unusable')),
|
||||
(USABLE, _('Usable')),
|
||||
)
|
||||
|
||||
user = models.ForeignKey(
|
||||
User,
|
||||
blank=True,
|
||||
|
|
@ -96,7 +86,6 @@ class Subscriber(ProjectBaseMixin):
|
|||
ip_address = models.GenericIPAddressField(blank=True, null=True, default=None, verbose_name=_('IP address'))
|
||||
country_code = models.CharField(max_length=10, blank=True, null=True, default=None, verbose_name=_('Country code'))
|
||||
locale = models.CharField(blank=True, null=True, default=None, max_length=10, verbose_name=_('Locale identifier'))
|
||||
state = models.PositiveIntegerField(choices=STATE_CHOICES, default=USABLE, verbose_name=_('State'))
|
||||
update_code = models.CharField(
|
||||
max_length=254,
|
||||
blank=True,
|
||||
|
|
@ -107,9 +96,9 @@ class Subscriber(ProjectBaseMixin):
|
|||
)
|
||||
old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None)
|
||||
|
||||
subscription_type = models.ForeignKey(SubscriptionType, on_delete=models.CASCADE, null=True, default=None)
|
||||
subscription_types = models.ManyToManyField(SubscriptionType, through='Subscribe')
|
||||
|
||||
objects = SubscriberManager.from_queryset(SubscriberQuerySet)()
|
||||
objects = SubscriberManager()
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
|
@ -123,10 +112,9 @@ class Subscriber(ProjectBaseMixin):
|
|||
self.update_code = generate_string_code()
|
||||
return super(Subscriber, self).save(*args, **kwargs)
|
||||
|
||||
def unsubscribe(self):
|
||||
def unsubscribe(self, query: dict):
|
||||
"""Unsubscribe user."""
|
||||
self.state = self.UNUSABLE
|
||||
self.save()
|
||||
self.subscribe_set.update(unsubscribe_date=now())
|
||||
|
||||
@property
|
||||
def send_to(self):
|
||||
|
|
@ -141,3 +129,19 @@ class Subscriber(ProjectBaseMixin):
|
|||
url = settings.SITE_REDIRECT_URL_UNSUBSCRIBE
|
||||
query = f'?code={self.update_code}'
|
||||
return f'{schema}://{site_domain}{url}{query}'
|
||||
|
||||
|
||||
class Subscribe(ProjectBaseMixin):
|
||||
"""Subscribe model."""
|
||||
|
||||
subscribe_date = models.DateTimeField(_('Last subscribe date'), blank=True, null=True, default=now)
|
||||
unsubscribe_date = models.DateTimeField(_('Last unsubscribe date'), blank=True, null=True, default=None)
|
||||
|
||||
subscriber = models.ForeignKey(Subscriber, on_delete=models.CASCADE)
|
||||
subscription_type = models.ForeignKey(SubscriptionType, on_delete=models.CASCADE)
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
||||
verbose_name = _('Subscribe')
|
||||
verbose_name_plural = _('Subscribes')
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
"""Notification app serializers."""
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from location.serializers import CountrySimpleSerializer
|
||||
from notification import models
|
||||
from utils.methods import get_user_ip
|
||||
from utils.serializers import TranslatedField
|
||||
|
|
@ -10,6 +12,8 @@ class SubscriptionTypeSerializer(serializers.ModelSerializer):
|
|||
"""Subscription type serializer."""
|
||||
|
||||
name_translated = TranslatedField()
|
||||
country = CountrySimpleSerializer()
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
||||
|
|
@ -18,14 +22,15 @@ class SubscriptionTypeSerializer(serializers.ModelSerializer):
|
|||
'id',
|
||||
'index_name',
|
||||
'name_translated',
|
||||
'country',
|
||||
)
|
||||
|
||||
|
||||
class SubscribeSerializer(serializers.ModelSerializer):
|
||||
"""Subscribe serializer."""
|
||||
class CreateSubscribeSerializer(serializers.ModelSerializer):
|
||||
"""Create Subscribe serializer."""
|
||||
|
||||
email = serializers.EmailField(required=False, source='send_to')
|
||||
subscription_type = SubscriptionTypeSerializer(read_only=True)
|
||||
subscription_types = serializers.PrimaryKeyRelatedField(many=True, queryset=models.SubscriptionType.objects.all())
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
|
@ -33,10 +38,9 @@ class SubscribeSerializer(serializers.ModelSerializer):
|
|||
model = models.Subscriber
|
||||
fields = (
|
||||
'email',
|
||||
'subscription_type',
|
||||
'state',
|
||||
'subscription_types',
|
||||
'link_to_unsubscribe',
|
||||
)
|
||||
read_only_fields = ('state',)
|
||||
|
||||
def validate(self, attrs):
|
||||
"""Validate attrs."""
|
||||
|
|
@ -45,6 +49,10 @@ class SubscribeSerializer(serializers.ModelSerializer):
|
|||
|
||||
# validate email
|
||||
email = attrs.get('send_to')
|
||||
|
||||
if attrs.get('email'):
|
||||
email = attrs.get('email')
|
||||
|
||||
if user.is_authenticated:
|
||||
if email is not None and email != user.email:
|
||||
raise serializers.ValidationError(_('Does not match user email'))
|
||||
|
|
@ -57,18 +65,40 @@ class SubscribeSerializer(serializers.ModelSerializer):
|
|||
attrs['country_code'] = request.country_code
|
||||
attrs['locale'] = request.locale
|
||||
attrs['ip_address'] = get_user_ip(request)
|
||||
|
||||
if user.is_authenticated:
|
||||
attrs['user'] = user
|
||||
|
||||
subscription_type_id = self.context.get('request').parser_context.get('kwargs').get("subscription_type_pk")
|
||||
subscription_type_qs = models.SubscriptionType.objects.filter(id=subscription_type_id)
|
||||
if not subscription_type_qs.exists():
|
||||
raise serializers.ValidationError({'detail': _(f'SubscriptionType not found.')})
|
||||
attrs["subscription_type"] = subscription_type_qs.first()
|
||||
|
||||
return attrs
|
||||
|
||||
def create(self, validated_data):
|
||||
"""Create obj."""
|
||||
subscriber = models.Subscriber.objects.make_subscriber(**validated_data)
|
||||
return subscriber
|
||||
return models.Subscriber.objects.make_subscriber(**validated_data)
|
||||
|
||||
|
||||
class SubscribeObjectSerializer(serializers.ModelSerializer):
|
||||
"""Subscribe serializer."""
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
||||
model = models.Subscriber
|
||||
fields = ('subscriber', )
|
||||
read_only_fields = ('subscribe_date', 'unsubscribe_date',)
|
||||
|
||||
|
||||
class SubscribeSerializer(serializers.ModelSerializer):
|
||||
"""Subscribe serializer."""
|
||||
|
||||
email = serializers.EmailField(required=False, source='send_to')
|
||||
subscription_types = SubscriptionTypeSerializer(many=True, read_only=True)
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
||||
model = models.Subscriber
|
||||
fields = (
|
||||
'email',
|
||||
'subscription_types',
|
||||
'link_to_unsubscribe',
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
from datetime import datetime, timedelta
|
||||
from http.cookies import SimpleCookie
|
||||
|
||||
from django.test import TestCase
|
||||
from rest_framework.test import APITestCase
|
||||
from rest_framework import status
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from account.models import User
|
||||
from notification.models import Subscriber
|
||||
from account.models import Role, User, UserRole
|
||||
from location.models import Country
|
||||
from main.models import SiteSettings
|
||||
from news.models import News, NewsType
|
||||
from notification.models import Subscriber, SubscriptionType
|
||||
from translation.models import Language
|
||||
|
||||
|
||||
class BaseTestCase(APITestCase):
|
||||
|
|
@ -17,23 +21,22 @@ class BaseTestCase(APITestCase):
|
|||
self.user = User.objects.create_user(username=self.username, email=self.email, password=self.password)
|
||||
# get tokens
|
||||
tokens = User.create_jwt_tokens(self.user)
|
||||
self.client.cookies = SimpleCookie({'access_token': tokens.get('access_token'),
|
||||
'refresh_token': tokens.get('refresh_token')})
|
||||
self.client.cookies = SimpleCookie({
|
||||
'access_token': tokens.get('access_token'),
|
||||
'refresh_token': tokens.get('refresh_token')
|
||||
})
|
||||
|
||||
|
||||
class NotificationAnonSubscribeTestCase(APITestCase):
|
||||
|
||||
def test_subscribe(self):
|
||||
|
||||
test_data = {
|
||||
"email": "test@email.com",
|
||||
"state": 1
|
||||
"email": "test@email.com"
|
||||
}
|
||||
|
||||
response = self.client.post("/api/web/notifications/subscribe/", data=test_data, format="json")
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.json()["email"], test_data["email"])
|
||||
self.assertEqual(response.json()["state"], test_data["state"])
|
||||
|
||||
|
||||
class NotificationSubscribeTestCase(BaseTestCase):
|
||||
|
|
@ -42,21 +45,17 @@ class NotificationSubscribeTestCase(BaseTestCase):
|
|||
super().setUp()
|
||||
|
||||
self.test_data = {
|
||||
"email": self.email,
|
||||
"state": 1
|
||||
"email": self.email
|
||||
}
|
||||
|
||||
def test_subscribe(self):
|
||||
|
||||
response = self.client.post("/api/web/notifications/subscribe/", data=self.test_data, format="json")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.json()["email"], self.email)
|
||||
self.assertEqual(response.json()["state"], self.test_data["state"])
|
||||
|
||||
def test_subscribe_info_auth_user(self):
|
||||
|
||||
Subscriber.objects.create(user=self.user, email=self.email, state=1)
|
||||
Subscriber.objects.create(user=self.user, email=self.email)
|
||||
|
||||
response = self.client.get("/api/web/notifications/subscribe-info/", data=self.test_data, format="json")
|
||||
|
||||
|
|
@ -66,13 +65,12 @@ class NotificationSubscribeTestCase(BaseTestCase):
|
|||
class NotificationSubscribeInfoTestCase(APITestCase):
|
||||
|
||||
def test_subscribe_info(self):
|
||||
|
||||
self.username = 'sedragurda'
|
||||
self.password = 'sedragurdaredips19'
|
||||
self.email = 'sedragurda@desoz.com'
|
||||
self.user = User.objects.create_user(username=self.username, email=self.email, password=self.password)
|
||||
|
||||
test_subscriber = Subscriber.objects.create(user=self.user, email=self.email, state=1)
|
||||
test_subscriber = Subscriber.objects.create(user=self.user, email=self.email)
|
||||
|
||||
response = self.client.get(f"/api/web/notifications/subscribe-info/{test_subscriber.update_code}/")
|
||||
|
||||
|
|
@ -82,12 +80,10 @@ class NotificationSubscribeInfoTestCase(APITestCase):
|
|||
class NotificationUnsubscribeAuthUserTestCase(BaseTestCase):
|
||||
|
||||
def test_unsubscribe_auth_user(self):
|
||||
|
||||
Subscriber.objects.create(user=self.user, email=self.email, state=1)
|
||||
Subscriber.objects.create(user=self.user, email=self.email)
|
||||
|
||||
self.test_data = {
|
||||
"email": self.email,
|
||||
"state": 1
|
||||
"email": self.email
|
||||
}
|
||||
|
||||
response = self.client.patch("/api/web/notifications/unsubscribe/", data=self.test_data, format="json")
|
||||
|
|
@ -104,13 +100,102 @@ class NotificationUnsubscribeTestCase(APITestCase):
|
|||
self.user = User.objects.create_user(username=self.username, email=self.email, password=self.password)
|
||||
|
||||
self.test_data = {
|
||||
"email": self.email,
|
||||
"state": 1
|
||||
"email": self.email
|
||||
}
|
||||
|
||||
test_subscriber = Subscriber.objects.create(user=self.user, email=self.email, state=1)
|
||||
test_subscriber = Subscriber.objects.create(user=self.user, email=self.email)
|
||||
|
||||
response = self.client.patch(f"/api/web/notifications/unsubscribe/{test_subscriber.update_code}/",
|
||||
data=self.test_data, format="json")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
|
||||
class NotificationManySubscribeTestCase(APITestCase):
|
||||
|
||||
def test_subscribe(self):
|
||||
self.username = 'sedragurda'
|
||||
self.password = 'sedragurdaredips19'
|
||||
self.email = 'sedragurda@desoz.com'
|
||||
self.user = User.objects.create_user(
|
||||
username=self.username, email=self.email, password=self.password)
|
||||
|
||||
# get tokens
|
||||
tokens = User.create_jwt_tokens(self.user)
|
||||
self.client.cookies = SimpleCookie(
|
||||
{
|
||||
'access_token': tokens.get('access_token'),
|
||||
'refresh_token': tokens.get('refresh_token')
|
||||
})
|
||||
self.test_news_type = NewsType.objects.create(name="Test news type")
|
||||
|
||||
self.lang, created = Language.objects.get_or_create(
|
||||
title='Russia',
|
||||
locale='ru-RU'
|
||||
)
|
||||
|
||||
self.country_ru, created = Country.objects.get_or_create(
|
||||
name={"en-GB": "Russian"}
|
||||
)
|
||||
|
||||
self.site_ru, created = SiteSettings.objects.get_or_create(
|
||||
subdomain='ru'
|
||||
)
|
||||
|
||||
role = Role.objects.create(
|
||||
role=Role.CONTENT_PAGE_MANAGER,
|
||||
site_id=self.site_ru.id
|
||||
)
|
||||
role.save()
|
||||
|
||||
user_role = UserRole.objects.create(
|
||||
user=self.user,
|
||||
role=role
|
||||
)
|
||||
user_role.save()
|
||||
|
||||
self.test_news = News.objects.create(
|
||||
created_by=self.user, modified_by=self.user,
|
||||
title={"ru-RU": "Test news"},
|
||||
news_type=self.test_news_type,
|
||||
description={"ru-RU": "Description test news"},
|
||||
end=datetime.now() + timedelta(hours=2),
|
||||
state=News.PUBLISHED,
|
||||
slugs={'en-GB': 'test-news-slug'},
|
||||
country=self.country_ru,
|
||||
site=self.site_ru
|
||||
)
|
||||
|
||||
self.test_subscribe_type = SubscriptionType.objects.create(
|
||||
index_name='test_index_name',
|
||||
name={"ru-RU": "Test subscription type"}
|
||||
)
|
||||
|
||||
test_data = {
|
||||
'email': self.email,
|
||||
'subscription_types_pk': [
|
||||
self.test_subscribe_type.id
|
||||
]
|
||||
}
|
||||
|
||||
response = self.client.post("/api/web/notifications/subscribe/", data=test_data, format="json")
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.json()["email"], test_data["email"])
|
||||
|
||||
def test_unsubscribe(self):
|
||||
self.username = 'sedragurda'
|
||||
self.password = 'sedragurdaredips19'
|
||||
self.email = 'sedragurda@desoz.com'
|
||||
self.user = User.objects.create_user(
|
||||
username=self.username, email=self.email, password=self.password)
|
||||
|
||||
test_data = {
|
||||
"email": self.email
|
||||
}
|
||||
|
||||
test_subscriber = Subscriber.objects.create(user=self.user, email=self.email)
|
||||
|
||||
response = self.client.patch(f"/api/web/notifications/unsubscribe/{test_subscriber.update_code}/",
|
||||
data=test_data, format="json")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
|
|
|||
1
apps/notification/urls/back.py
Normal file
1
apps/notification/urls/back.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
urlpatterns = []
|
||||
|
|
@ -5,7 +5,7 @@ from notification.views import common
|
|||
app_name = "notification"
|
||||
|
||||
urlpatterns = [
|
||||
path('subscribe/<int:subscription_type_pk>', common.SubscribeView.as_view(), name='subscribe'),
|
||||
path('subscribe/', common.CreateSubscribeView.as_view(), name='create-subscribe'),
|
||||
path('subscribe-info/', common.SubscribeInfoAuthUserView.as_view(), name='check-code-auth'),
|
||||
path('subscribe-info/<code>/', common.SubscribeInfoView.as_view(), name='check-code'),
|
||||
path('unsubscribe/', common.UnsubscribeAuthUserView.as_view(), name='unsubscribe-auth'),
|
||||
|
|
|
|||
|
|
@ -2,22 +2,17 @@
|
|||
from django.shortcuts import get_object_or_404
|
||||
from rest_framework import generics, permissions
|
||||
from rest_framework.response import Response
|
||||
|
||||
from notification import models
|
||||
from notification.serializers import common as serializers
|
||||
|
||||
|
||||
class SubscribeView(generics.GenericAPIView):
|
||||
"""Subscribe View."""
|
||||
class CreateSubscribeView(generics.CreateAPIView):
|
||||
"""Create subscribe View."""
|
||||
|
||||
queryset = models.Subscriber.objects.all()
|
||||
permission_classes = (permissions.AllowAny, )
|
||||
serializer_class = serializers.SubscribeSerializer
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
return Response(data=serializer.data)
|
||||
permission_classes = (permissions.AllowAny,)
|
||||
serializer_class = serializers.CreateSubscribeSerializer
|
||||
|
||||
|
||||
class SubscribeInfoView(generics.RetrieveAPIView):
|
||||
|
|
@ -25,7 +20,7 @@ class SubscribeInfoView(generics.RetrieveAPIView):
|
|||
|
||||
lookup_field = 'update_code'
|
||||
lookup_url_kwarg = 'code'
|
||||
permission_classes = (permissions.AllowAny, )
|
||||
permission_classes = (permissions.AllowAny,)
|
||||
queryset = models.Subscriber.objects.all()
|
||||
serializer_class = serializers.SubscribeSerializer
|
||||
|
||||
|
|
@ -33,7 +28,7 @@ class SubscribeInfoView(generics.RetrieveAPIView):
|
|||
class SubscribeInfoAuthUserView(generics.ListAPIView):
|
||||
"""Subscribe info auth user view."""
|
||||
|
||||
permission_classes = (permissions.IsAuthenticated, )
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
serializer_class = serializers.SubscribeSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
|
|
@ -42,18 +37,18 @@ class SubscribeInfoAuthUserView(generics.ListAPIView):
|
|||
return queryset.filter(user=user)
|
||||
|
||||
|
||||
class UnsubscribeView(generics.GenericAPIView):
|
||||
class UnsubscribeView(generics.UpdateAPIView):
|
||||
"""Unsubscribe view."""
|
||||
|
||||
lookup_field = 'update_code'
|
||||
lookup_url_kwarg = 'code'
|
||||
permission_classes = (permissions.AllowAny, )
|
||||
permission_classes = (permissions.AllowAny,)
|
||||
queryset = models.Subscriber.objects.all()
|
||||
serializer_class = serializers.SubscribeSerializer
|
||||
|
||||
def patch(self, request, *args, **kw):
|
||||
obj = self.get_object()
|
||||
obj.unsubscribe()
|
||||
obj.unsubscribe(request.query_params)
|
||||
serializer = self.get_serializer(instance=obj)
|
||||
return Response(data=serializer.data)
|
||||
|
||||
|
|
@ -61,14 +56,14 @@ class UnsubscribeView(generics.GenericAPIView):
|
|||
class UnsubscribeAuthUserView(generics.GenericAPIView):
|
||||
"""Unsubscribe auth user view."""
|
||||
|
||||
permission_classes = (permissions.IsAuthenticated, )
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
queryset = models.Subscriber.objects.all()
|
||||
serializer_class = serializers.SubscribeSerializer
|
||||
|
||||
def patch(self, request, *args, **kw):
|
||||
user = request.user
|
||||
obj = get_object_or_404(models.Subscriber, user=user)
|
||||
obj.unsubscribe()
|
||||
obj.unsubscribe(request.query_params)
|
||||
serializer = self.get_serializer(instance=obj)
|
||||
return Response(data=serializer.data)
|
||||
|
||||
|
|
@ -78,4 +73,3 @@ class SubscriptionTypesView(generics.ListAPIView):
|
|||
permission_classes = (permissions.AllowAny,)
|
||||
queryset = models.SubscriptionType.objects.all()
|
||||
serializer_class = serializers.SubscriptionTypeSerializer
|
||||
|
||||
|
|
|
|||
|
|
@ -10,10 +10,12 @@ class TagsBaseFilterSet(filters.FilterSet):
|
|||
# Object type choices
|
||||
NEWS = 'news'
|
||||
ESTABLISHMENT = 'establishment'
|
||||
RECIPES = 'recipe'
|
||||
|
||||
TYPE_CHOICES = (
|
||||
(NEWS, 'News'),
|
||||
(ESTABLISHMENT, 'Establishment'),
|
||||
(RECIPES, 'Recipe'),
|
||||
)
|
||||
|
||||
type = filters.MultipleChoiceFilter(choices=TYPE_CHOICES,
|
||||
|
|
@ -91,5 +93,7 @@ class TagsFilterSet(TagsBaseFilterSet):
|
|||
if self.ESTABLISHMENT in value:
|
||||
queryset = queryset.for_establishments().filter(category__value_type='list').filter(value__in=settings.ESTABLISHMENT_CHOSEN_TAGS).distinct(
|
||||
'value')
|
||||
if self.RECIPES in value:
|
||||
queryset = queryset.for_news().filter(value__in=settings.RECIPES_CHOSEN_TAGS).distinct('value')
|
||||
return queryset
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ urlpatterns = [
|
|||
path('gallery/', include(('gallery.urls', 'gallery'), namespace='gallery')),
|
||||
path('location/', include('location.urls.back')),
|
||||
path('news/', include('news.urls.back')),
|
||||
path('notifications/', include(('notification.urls.back', 'notification'), namespace='notification')),
|
||||
path('review/', include('review.urls.back')),
|
||||
path('tags/', include(('tag.urls.back', 'tag'), namespace='tag')),
|
||||
path('products/', include(('product.urls.back', 'product'), namespace='product')),
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user