diff --git a/apps/news/tasks.py b/apps/news/tasks.py index 7ff4d504..80a2a626 100644 --- a/apps/news/tasks.py +++ b/apps/news/tasks.py @@ -1,43 +1,51 @@ 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 Subscriber @shared_task def send_email_with_news(news_ids): - subscribers = Subscriber.objects.filter(state=Subscriber.USABLE) + subscribers = Subscriber.objects.all() 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 = dict(zip(map(lambda social: social.country.code, socials), socials)) + + for subscriber in subscribers: + socials_for_subscriber = socials.get(subscriber.country_code) 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 diff --git a/apps/notification/migrations/0008_remove_subscribe_state.py b/apps/notification/migrations/0008_remove_subscribe_state.py new file mode 100644 index 00000000..5870e8cf --- /dev/null +++ b/apps/notification/migrations/0008_remove_subscribe_state.py @@ -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', + ), + ] diff --git a/apps/notification/models.py b/apps/notification/models.py index 2c3463a9..4bdabcae 100644 --- a/apps/notification/models.py +++ b/apps/notification/models.py @@ -42,7 +42,6 @@ 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_types = subscription_types obj.save() @@ -64,16 +63,6 @@ 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.""" @@ -102,7 +91,7 @@ class Subscriber(ProjectBaseMixin): subscription_types = models.ManyToManyField(SubscriptionType, through='Subscribe') - objects = SubscriberManager.from_queryset(SubscriberQuerySet)() + objects = SubscriberManager() class Meta: """Meta class.""" @@ -121,9 +110,18 @@ class Subscriber(ProjectBaseMixin): subscription_types = query.get('subscription_types') + old_subscribes = self.subscription_types.objects.all() subscribes = self.subscription_types.objects.filter(pk__in=[subscription_types]) self.subscription_types = subscribes + new_ids = set(existing_answer.answer.id for existing_answer in subscribes) + old_subscribes_types = [sub for sub in old_subscribes if sub.id not in new_ids] + old_subscribes = Subscribe.objects.filter(subscriber=self, subscription_types__in=[old_subscribes_types]) + + for sub in old_subscribes: + sub.unsubscribe_date = now() + sub.save() + self.save() @property @@ -148,17 +146,8 @@ class Subscriber(ProjectBaseMixin): class Subscribe(ProjectBaseMixin): """Subscribe model.""" - UNUSABLE = 0 - USABLE = 1 - - STATE_CHOICES = ( - (UNUSABLE, _('Unusable')), - (USABLE, _('Usable')), - ) - 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) - state = models.PositiveIntegerField(choices=STATE_CHOICES, default=USABLE, verbose_name=_('State')) subscriber = models.ForeignKey(Subscriber, on_delete=models.CASCADE) subscription_type = models.ForeignKey(SubscriptionType, on_delete=models.CASCADE) diff --git a/apps/notification/serializers/common.py b/apps/notification/serializers/common.py index 21b85c2c..3499fd2a 100644 --- a/apps/notification/serializers/common.py +++ b/apps/notification/serializers/common.py @@ -86,7 +86,7 @@ class SubscribeObjectSerializer(serializers.ModelSerializer): model = models.Subscriber fields = () - read_only_fields = ('subscribe_date', 'unsubscribe_date', 'state',) + read_only_fields = ('subscribe_date', 'unsubscribe_date',) class SubscribeSerializer(serializers.ModelSerializer): diff --git a/apps/notification/tests.py b/apps/notification/tests.py index 87264435..e65e049d 100644 --- a/apps/notification/tests.py +++ b/apps/notification/tests.py @@ -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 User, Role, 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) 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,82 @@ 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_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) + + # 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 + ] + } + + 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"]) \ No newline at end of file