import random from datetime import timedelta from django.db import models from django.contrib.auth.models import User from django.utils.translation import ugettext as _ from django.db.models.signals import post_save from django.db import IntegrityError from django.dispatch import receiver from constance import config as site_config from django_lcore.core import LcoreUserProfileMethods, setup_sync_hooks, VPN_AUTH_STORAGE from ccvpn.common import get_trial_period_duration from payments.models import Subscription prng = random.SystemRandom() def random_gift_code(): charset = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ" return ''.join([prng.choice(charset) for n in range(10)]) class VPNUser(models.Model, LcoreUserProfileMethods): class Meta: verbose_name = _("VPN User") verbose_name_plural = _("VPN Users") user = models.OneToOneField(User, on_delete=models.CASCADE) notes = models.TextField(blank=True) expiration = models.DateTimeField(blank=True, null=True) last_expiry_notice = models.DateTimeField(blank=True, null=True) last_vpn_auth_fail_notice = models.DateTimeField(blank=True, null=True) notify_expiration = models.BooleanField(default=True) notify_vpn_auth_fail = models.BooleanField(default=True) trial_periods_given = models.IntegerField(default=0) last_vpn_auth = models.DateTimeField(blank=True, null=True) last_core_sync = models.DateTimeField(blank=True, null=True) referrer = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL, related_name='referrals') referrer_used = models.BooleanField(default=False) campaign = models.CharField(blank=True, null=True, max_length=64) def clear_fields(self): self.expiration = None self.last_expiry_notice = None self.last_vpn_auth = None self.last_core_sync = None self.referrer = None self.referrer_used = False self.campaign = None def give_trial_period(self): self.add_paid_time(get_trial_period_duration()) self.trial_periods_given += 1 @property def can_have_trial(self): if self.trial_periods_given >= site_config.TRIAL_PERIOD_MAX: return False if self.user.payment_set.filter(status='confirmed').count() > 0: return False return True @property def remaining_trial_periods(self): return site_config.TRIAL_PERIOD_MAX - self.trial_periods_given def on_payment_confirmed(self, payment): if self.referrer and not self.referrer_used: self.referrer.vpnuser.add_paid_time(timedelta(days=30)) self.referrer.vpnuser.save() self.referrer_used = True def get_subscription(self, include_unconfirmed=False): """ Tries to get the active (and most recent) Subscription """ s = Subscription.objects.filter(user=self.user, status='active') \ .order_by('-id') \ .first() if s is not None or include_unconfirmed is False: return s s = Subscription.objects.filter(user=self.user, status='unconfirmed') \ .order_by('-id') \ .first() return s def lcore_sync(self): if VPN_AUTH_STORAGE == 'inst': return from lambdainst.tasks import push_user push_user.delay(user_id=self.user.id) def __str__(self): return self.user.username setup_sync_hooks(User, VPNUser) @receiver(post_save, sender=User) def create_vpnuser(sender, instance, created, **kwargs): if created: try: VPNUser.objects.create(user=instance) except IntegrityError: pass class GiftCode(models.Model): class Meta: verbose_name = _("Gift Code") verbose_name_plural = _("Gift Codes") code = models.CharField(max_length=32, default=random_gift_code) time = models.DurationField(default=timedelta(days=30)) created = models.DateTimeField(auto_now_add=True, null=True, blank=True) created_by = models.ForeignKey(User, related_name='created_giftcode_set', on_delete=models.CASCADE, null=True, blank=True) single_use = models.BooleanField(default=True) free_only = models.BooleanField(default=True) available = models.BooleanField(default=True) comment = models.TextField(blank=True) users = models.ManyToManyField(User, through='GiftCodeUser') def use_on(self, user): if not self.available: return False if self.free_only and user.vpnuser.is_paid: return False link = GiftCodeUser(user=user, code=self) link.save() user.vpnuser.add_paid_time(self.time) user.vpnuser.save() if self.single_use: self.available = False self.save() return True @property def comment_head(self): head = self.comment.split('\n', 1)[0] if len(head) > 80: head = head[:80] + "..." return head def __str__(self): return self.code class GiftCodeUser(models.Model): class Meta: verbose_name = _("Gift Code User") verbose_name_plural = _("Gift Code Users") user = models.ForeignKey(User, on_delete=models.CASCADE) code = models.ForeignKey(GiftCode, on_delete=models.CASCADE) date = models.DateTimeField(auto_now_add=True, null=True, blank=True) def __str__(self): return "%s (%s)" % (self.user.username, self.code.code)