You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
70 lines
1.8 KiB
70 lines
1.8 KiB
from django.db import models |
|
from django.utils.translation import gettext_lazy as _ |
|
from xenua.django.models import RandomSlugPKMixin |
|
|
|
|
|
class Domain(models.Model): |
|
fqdn = models.CharField( |
|
_('FQDN'), |
|
max_length=512, |
|
unique=True, |
|
) |
|
|
|
def __str__(self): |
|
return self.fqdn |
|
|
|
@classmethod |
|
def get_from_request(cls, r): |
|
return cls.objects.get(fqdn__iexact=r.get_host()) |
|
|
|
|
|
class ShortLink(RandomSlugPKMixin, models.Model): |
|
class Meta: |
|
unique_together = ('domain', 'location') |
|
|
|
domain = models.ForeignKey(Domain, related_name='links', on_delete=models.CASCADE) |
|
location = models.CharField(_("short link"), max_length=100) |
|
to = models.URLField(_("redirect to"), max_length=2500) |
|
click_count = models.IntegerField(default=0) |
|
|
|
cache = {} |
|
|
|
def click(self): # todo: further assess performance. initial testing suggests minimal impact |
|
self.click_count += 1 |
|
self.save() |
|
|
|
def link(self): |
|
return f"{self.domain.fqdn}/{self.location}" |
|
|
|
@classmethod |
|
def get_from_request(cls, req): |
|
d = Domain.get_from_request(req) |
|
return cls.objects.filter(domain=d).get(location=req.path[1:]) |
|
|
|
@classmethod |
|
def hit(cls, req, loc): |
|
if r := cls.try_cache(req, loc): |
|
return r |
|
|
|
return cls.miss(req, loc) |
|
|
|
@classmethod |
|
def miss(cls, req, loc): |
|
lnk = cls.get_from_request(req) |
|
cls.cache[req.get_host()][loc] = lnk.to |
|
return lnk.to |
|
|
|
@classmethod |
|
def try_cache(cls, req, loc): |
|
host = req.get_host() |
|
try: |
|
domaincache = cls.cache[host] |
|
try: |
|
return domaincache[loc] |
|
except KeyError: |
|
cls.miss(req, loc) |
|
except KeyError: |
|
cls.cache[host] = {} |
|
|
|
return '' |
|
|
|
|