You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

153 lines
4.5 KiB
Python

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.utils import timezone
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from . import core
assert isinstance(settings.TRIAL_PERIOD, timedelta)
assert isinstance(settings.TRIAL_PERIOD_LIMIT, int)
prng = random.SystemRandom()
def random_gift_code():
charset = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ"
return ''.join([prng.choice(charset) for n in range(10)])
class VPNUser(models.Model):
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)
notify_expiration = models.BooleanField(default=True)
trial_periods_given = models.IntegerField(default=0)
last_vpn_auth = 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)
@property
def is_paid(self):
if not self.expiration:
return False
return self.expiration > timezone.now()
@property
def time_left(self):
return timezone.now() - self.expiration
def add_paid_time(self, time):
now = timezone.now()
if not self.expiration or self.expiration < now:
self.expiration = now
self.expiration += time
# Propagate update to core
if core.VPN_AUTH_STORAGE == 'core':
core.update_user_expiration(self.user)
def give_trial_period(self):
self.add_paid_time(settings.TRIAL_PERIOD)
self.trial_periods_given += 1
@property
def can_have_trial(self):
if self.trial_periods_given >= settings.TRIAL_PERIOD_LIMIT:
return False
if self.user.payment_set.filter(status='confirmed').count() > 0:
return False
return True
@property
def remaining_trial_periods(self):
return settings.TRIAL_PERIOD_LIMIT - 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=14))
self.referrer.vpnuser.save()
self.referrer_used = True
def __str__(self):
return self.user.username
@receiver(post_save, sender=User)
def create_vpnuser(sender, instance, created, **kwargs):
if created:
VPNUser.objects.create(user=instance)
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)
code = models.ForeignKey(GiftCode)
date = models.DateTimeField(auto_now_add=True, null=True, blank=True)
def __str__(self):
return "%s (%s)" % (self.user.username, self.code.code)