"""Notification app models.""" from django.conf import settings from django.db import models from django.db.models import F 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 notification.tasks import send_unsubscribe_email from utils.methods import generate_string_code from utils.models import ProjectBaseMixin, TJSONField, TranslatedFieldsMixin from notification.tasks import send_unsubscribe_email class SubscriptionType(ProjectBaseMixin, TranslatedFieldsMixin): index_name = models.CharField(max_length=255, verbose_name=_('Index name'), unique=True) 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 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_types=None, *args, **kwargs): """Make subscriber and update info.""" # search existing object if not user: user = User.objects.filter(email=email).first() if user: obj = self.model.objects.filter(user=user).first() if obj is None: obj = self.model.objects.filter(email=user.email).first() self.associate_user(user=user) else: obj = self.model.objects.filter(email=email).first() # update or create if obj: if user: obj.user = user obj.email = None else: obj.email = email obj.ip_address = ip_address obj.country_code = country_code obj.locale = locale obj.update_code = generate_string_code() obj.save() else: obj = self.model.objects.create( user=user, email=email, ip_address=ip_address, country_code=country_code, locale=locale, ) if subscription_types is None: subscription_types = [] obj.subscription_types.set(subscription_types) obj.subscribe_set.update(unsubscribe_date=None) obj.save() return obj def associate_user(self, user): """Associate user.""" obj = self.model.objects.filter(user=user).first() if obj is None: obj = self.model.objects.filter(email=user.email_confirmed, user__isnull=True).first() if obj: obj.user = user obj.email = user.email obj.save() return obj class Subscriber(ProjectBaseMixin): """Subscriber model.""" user = models.ForeignKey( User, blank=True, null=True, default=None, on_delete=models.SET_NULL, related_name='subscriber', verbose_name=_('User'), ) email = models.EmailField(blank=True, null=True, default=None, unique=True, verbose_name=_('Email')) 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')) update_code = models.CharField( max_length=254, blank=True, null=True, default=None, db_index=True, verbose_name=_('Token'), ) old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None) subscription_types = models.ManyToManyField(SubscriptionType, through='Subscribe') objects = SubscriberManager() class Meta: """Meta class.""" verbose_name = _('Subscriber') verbose_name_plural = _('Subscribers') def save(self, *args, **kwargs): """Overrided save method.""" if self.update_code is None: self.update_code = generate_string_code() return super(Subscriber, self).save(*args, **kwargs) def unsubscribe(self): """Unsubscribe user.""" self.subscribe_set.update( unsubscribe_date=now(), old_subscriber_id=F('subscriber_id'), old_subscription_type_id=F('subscription_type_id') ) self.subscribe_set.update( subscriber_id=None, subscription_type_id=None ) if settings.USE_CELERY: send_unsubscribe_email.delay(self.pk) else: send_unsubscribe_email(self.pk) @property def send_to(self): """Actual email.""" return self.user.email if self.user else self.email @property def link_to_unsubscribe(self): """Link to unsubscribe.""" schema = settings.SCHEMA_URI site_domain = settings.DOMAIN_URI url = settings.SITE_REDIRECT_URL_UNSUBSCRIBE query = f'?code={self.update_code}' country_code = '%s.' % self.country_code if self.country_code else '' return f'{schema}://{country_code}{site_domain}{url}{query}' @property def active_subscriptions(self): return self.subscription_types.exclude(subscriber__subscribe__unsubscribe_date__isnull=False) @property def subscription_history(self): return Subscribe.objects.subscription_history(self.pk) class SubscribeQuerySet(models.QuerySet): def active(self, switcher=True): """Fetches active subscriptions.""" return self.exclude(unsubscribe_date__isnull=not switcher) def subscription_history(self, subscriber_id: int): return self.filter(old_subscriber_id=subscriber_id) class Subscribe(ProjectBaseMixin): """Subscribe model.""" unsubscribe_date = models.DateTimeField(_('Last unsubscribe date'), blank=True, null=True, default=None) subscriber = models.ForeignKey(Subscriber, on_delete=models.CASCADE, null=True) subscription_type = models.ForeignKey(SubscriptionType, on_delete=models.CASCADE, null=True) old_subscriber_id = models.PositiveIntegerField(_("Old subscriber id"), null=True) old_subscription_type_id = models.PositiveIntegerField(_("Old subscription type id"), null=True) objects = SubscribeQuerySet.as_manager() @property def subscribe_date(self): return self.created class Meta: """Meta class.""" verbose_name = _('Subscribe') verbose_name_plural = _('Subscribes')