Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

model based regex path redirects

  • Loading branch information...
commit b332adffca5d2ad9609c6d59f675cef6d5baae0c 1 parent d59c06b
@coffindragger coffindragger authored
View
11 sky_redirects/admin.py
@@ -1,6 +1,6 @@
from django.contrib import admin
-from sky_redirects.models import DomainRedirect
+from sky_redirects.models import DomainRedirect, RegexPathRedirect
class DomainRedirectAdmin(admin.ModelAdmin):
@@ -9,4 +9,11 @@ class DomainRedirectAdmin(admin.ModelAdmin):
def redirect_from(self, obj):
return obj.fqdn
-admin.site.register(DomainRedirect, DomainRedirectAdmin)
+admin.site.register(DomainRedirect, DomainRedirectAdmin)
+
+
+class RegexPathRedirectAdmin(admin.ModelAdmin):
+ list_display = ('redirect_from','redirect_to','redirect_type','ordering')
+ ordering = ('ordering',)
+
+admin.site.register(RegexPathRedirect, RegexPathRedirectAdmin)
View
24 sky_redirects/middleware.py
@@ -1,4 +1,4 @@
-from sky_redirects.models import DomainRedirect
+from sky_redirects.models import DomainRedirect, RegexPathRedirect
from django.utils.http import urlquote
from django.http import HttpResponseRedirect
@@ -15,4 +15,24 @@ def process_request(self, request):
urlquote(request.path),
(request.method == 'GET' and len(request.GET) > 0) and '?%s' % request.GET.urlencode() or ''
)
- return HttpResponseRedirect(new_uri)
+ return HttpResponseRedirect(new_uri)
+
+
+class RegexRedirectMiddleware(object):
+ def process_request(self, request):
+ # import pdb; pdb.set_trace()
+ path = request.path
+ domain = request.get_host()
+ redirects = RegexPathRedirect.objects.cached_index()
+ for redir in redirects:
+ regex = redir.compiled_regex
+ matches = regex.match(path)
+ if matches:
+ new_uri = '%s://%s%s%s' % (
+ 'https' if request.is_secure() else 'http',
+ domain,
+ redir.redirect_to % matches.groupdict(),
+ (request.method == 'GET' and len(request.GET) > 0) and '?%s' % request.GET.urlencode() or ''
+ )
+ return HttpResponseRedirect(new_uri)
+
View
118 sky_redirects/models.py
@@ -1,45 +1,84 @@
from django.db import models
from django.contrib.sites.models import Site
-
from django.core.cache import cache
+import re
+
+class RedirectType(object):
+ PERMANENT='301'
+ TEMPORARY='302'
+ CHOICES = (
+ (PERMANENT, 'Permanent'),
+ (TEMPORARY, 'Temporary')
+ )
-class DomainRedirectManager(models.Manager):
- def _index_cache_key(self):
- return '%s:cached_by_domain' % (self.model.__class__.__name__,)
+class IndexedCachedTableManager(models.Manager):
+ def __init__(self, indexed_field, *args, **kwargs):
+ super(IndexedCachedTableManager, self).__init__(*args, **kwargs)
+ self.indexed_field = indexed_field
+
+ def _cache_key(self):
+ return '%s:indexed_cached_table' % (self.model.__class__.__name__,)
def cached_index(self):
- """Index the entire DomainRedirect table into a dictionary of domains to model objects"""
- cache_key = self._index_cache_key()
- index = cache.get(cache_key)
+ """Returned the cached index, generate it if not present."""
+ index = cache.get(self._cache_key())
if index is None:
- index = self.rebuild_cache(cache_key)
+ index = self.rebuild_cache()
return index
- def rebuild_cache(self, cache_key=None):
- """Publish """
+ def rebuild_cache(self):
+ """Generate the indexed dictionary and publish it to the django cache"""
index = {}
- for domain_redirect in self.all().select_related():
- index[domain_redirect.fqdn] = domain_redirect
- if cache_key is None:
- cache_key = self._index_cache_key()
- cache.set(cache_key, index, 365*86400) # cache forever
+ for obj in self.all().select_related():
+ key = getattr(obj, self.indexed_field, None)
+ if key is not None:
+ index[key] = obj
+ cache.set(self._cache_key(), index, 365*86400) # cache forever
return index
+class OrderedCachedTableManager(models.Manager):
+ def __init__(self, ordering_field, *args, **kwargs):
+ super(OrderedCachedTableManager, self).__init__(*args, **kwargs)
+ self.ordering_field = ordering_field
+ def _cache_key(self):
+ return '%s:ordered_cached_table' % (self.model.__class__.__name__,)
-class DomainRedirect(models.Model):
- REDIRECT_TYPE_PERMANENT='301'
- REDIRECT_TYPE_TEMPORARY='302'
- REDIRECT_TYPE_CHOICES = (
- (REDIRECT_TYPE_PERMANENT, 'Permanent'),
- (REDIRECT_TYPE_TEMPORARY, 'Temporary')
- )
+ def cached_index(self):
+ """Returned the cached index, generate it if not present."""
+ index = cache.get(self._cache_key())
+ if index is None:
+ index = self.rebuild_cache()
+ return index
+
+ def rebuild_cache(self):
+ index = []
+ for obj in self.all().order_by(self.ordering_field):
+ index.append(obj)
+ cache.set(self._cache_key(), index, 365*86400) # cache forever
+ return index
+
+
+
+class CachedTable(models.Model):
+ class Meta:
+ abstract = True
+
+ def save(self, *args, **kwargs):
+ ret = super(CachedTable, self).save(*args, **kwargs)
+ #anytime after we change a record, update the cached_index
+ self.__class__.objects.rebuild_cache()
+ return ret
+
+
+
+class DomainRedirect(CachedTable):
domain = models.CharField(max_length=1024, null=False, help_text='The domain to redirect from. You may terminate the domain with a `.` to specify a subdomain e.g.: `www.`')
redirect_to = models.ForeignKey('sites.Site')
- redirect_type = models.CharField(max_length=1024, choices=REDIRECT_TYPE_CHOICES, default=REDIRECT_TYPE_PERMANENT)
- objects = DomainRedirectManager()
+ redirect_type = models.CharField(max_length=1024, choices=RedirectType.CHOICES, default=RedirectType.PERMANENT)
+ objects = IndexedCachedTableManager(indexed_field='fqdn')
def __unicode__(self):
return '%s Redirect from:\'%s\' to \'%s\'' % (self.get_redirect_type_display(), self.fqdn, self.redirect_to.domain)
@@ -50,10 +89,35 @@ def fqdn(self):
return '%s%s' % (self.domain, self.redirect_to.domain)
return self.domain
-
-
def save(self, *args, **kwargs):
ret = super(DomainRedirect, self).save(*args, **kwargs)
#anytime after we change a record, update the cached_index
DomainRedirect.objects.rebuild_cache()
- return ret
+ return ret
+
+class RegexPathRedirect(CachedTable):
+ redirect_from = models.CharField(max_length=1024, help_text='Regular Expression format, remember to include `$` if you want an exact match' )
+ redirect_to = models.CharField(max_length=1024)
+ redirect_type = models.CharField(max_length=1024, choices=RedirectType.CHOICES, default=RedirectType.PERMANENT)
+ ordering = models.IntegerField(default=99, choices=((c,c) for c in range(1,100)))
+ objects = OrderedCachedTableManager(ordering_field='ordering')
+
+ class Meta:
+ ordering = ('ordering',)
+
+ def __unicode__(self):
+ return "Redirect from '%s' to '%s'" % (self.redirect_from, self.redirect_to)
+
+ def save(self, *args, **kwargs):
+ self.redirect_from = self.redirect_from.strip()
+ self.redirect_to = self.redirect_to.strip()
+ return super(RegexPathRedirect, self).save(*args, **kwargs)
+
+ @property
+ def compiled_regex(self):
+ return re.compile(self.redirect_from)
+
+
+
+
+
Please sign in to comment.
Something went wrong with that request. Please try again.