Permalink
Browse files

initial domain redirect model and middleware

  • Loading branch information...
0 parents commit d59c06bebead4fc47263f4cc336e55f05e11aaa4 @coffindragger coffindragger committed Jul 12, 2012
Showing with 189 additions and 0 deletions.
  1. +3 −0 .gitignore
  2. +94 −0 setup.py
  3. +3 −0 sky_redirects/__init__.py
  4. +12 −0 sky_redirects/admin.py
  5. +18 −0 sky_redirects/middleware.py
  6. +59 −0 sky_redirects/models.py
@@ -0,0 +1,3 @@
+*.pyc
+.*.sw*
+.DS_Store
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright 2012 Concentric Sky, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from setuptools import setup, find_packages
+import re
+import os
+import sys
+
+name = 'django-sky-redirects'
+package = 'sky_redirects'
+description = 'Robust redirect app for django that supports domain redirects and regex patterns.'
+url = 'http://github.com/concentricsky/django-sky-redirects/'
+author = 'Concentric Sky'
+author_email = 'django@concentricsky.com'
+license = 'Apache 2.0'
+install_requires = []
+classifiers = [
+ 'Operating System :: MacOS :: MacOS X',
+ 'Operating System :: Microsoft :: Windows',
+ 'Operating System :: POSIX :: Linux',
+ 'Programming Language :: Python',
+ 'Framework :: Django',
+ 'License :: OSI Approved :: Apache Software License',
+ 'Topic :: Software Development :: Libraries',
+]
+
+try:
+ longdesc = open('README.rst').read()
+except Exception:
+ longdesc = description
+
+def get_version():
+ """
+ Return package version as listed in `sky_redirects.__version__` in `init.py`.
+ """
+ import sky_redirects
+ return '.'.join([str(i) for i in sky_redirects.__version__])
+
+
+def get_package_data(packages):
+ """
+ Return all files under the root package, that are not in a
+ package themselves.
+ """
+ result = {}
+ for package in packages:
+ walk = [(dirpath.replace(package + os.sep, '', 1), filenames)
+ for dirpath, dirnames, filenames in os.walk(package)
+ if not os.path.exists(os.path.join(dirpath, '__init__.py'))]
+
+ filepaths = []
+ for base, filenames in walk:
+ filepaths.extend([os.path.join(base, filename)
+ for filename in filenames])
+ result[package]=filepaths
+ return result
+
+if sys.argv[-1] == 'publish':
+ os.system("python setup.py sdist upload")
+ args = {'version': get_version(name)}
+ print "You probably want to also tag the version now:"
+ print " git tag -a %(version)s -m 'version %(version)s'" % args
+ print " git push --tags"
+ sys.exit()
+
+setup(
+ name=name,
+ version=get_version(),
+ url=url,
+ license=license,
+ long_description=longdesc,
+ description=description,
+ author=author,
+ author_email=author_email,
+ packages=find_packages(),
+ package_data=get_package_data(['sky_redirects']),
+ install_requires=install_requires,
+)
+
+
+
@@ -0,0 +1,3 @@
+__all__ = ['__version__']
+
+__version__ = (0,8,0)
@@ -0,0 +1,12 @@
+
+from django.contrib import admin
+from sky_redirects.models import DomainRedirect
+
+
+class DomainRedirectAdmin(admin.ModelAdmin):
+ list_display = ('redirect_from','redirect_to', 'redirect_type')
+
+ def redirect_from(self, obj):
+ return obj.fqdn
+
+admin.site.register(DomainRedirect, DomainRedirectAdmin)
@@ -0,0 +1,18 @@
+from sky_redirects.models import DomainRedirect
+from django.utils.http import urlquote
+from django.http import HttpResponseRedirect
+
+
+class DomainRedirectMiddleware(object):
+ def process_request(self, request):
+ host = request.get_host()
+ domain_index = DomainRedirect.objects.cached_index()
+ if host in domain_index:
+ domain_redirect = domain_index[host]
+ new_uri = '%s://%s%s%s' % (
+ 'https' if request.is_secure() else 'http',
+ domain_redirect.redirect_to.domain,
+ urlquote(request.path),
+ (request.method == 'GET' and len(request.GET) > 0) and '?%s' % request.GET.urlencode() or ''
+ )
+ return HttpResponseRedirect(new_uri)
@@ -0,0 +1,59 @@
+from django.db import models
+from django.contrib.sites.models import Site
+
+from django.core.cache import cache
+
+
+
+class DomainRedirectManager(models.Manager):
+ def _index_cache_key(self):
+ return '%s:cached_by_domain' % (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)
+ if index is None:
+ index = self.rebuild_cache(cache_key)
+ return index
+
+ def rebuild_cache(self, cache_key=None):
+ """Publish """
+ 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
+ return index
+
+
+
+class DomainRedirect(models.Model):
+ REDIRECT_TYPE_PERMANENT='301'
+ REDIRECT_TYPE_TEMPORARY='302'
+ REDIRECT_TYPE_CHOICES = (
+ (REDIRECT_TYPE_PERMANENT, 'Permanent'),
+ (REDIRECT_TYPE_TEMPORARY, 'Temporary')
+ )
+ 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()
+
+ def __unicode__(self):
+ return '%s Redirect from:\'%s\' to \'%s\'' % (self.get_redirect_type_display(), self.fqdn, self.redirect_to.domain)
+
+ @property
+ def fqdn(self):
+ if self.domain.endswith('.'):
+ 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

0 comments on commit d59c06b

Please sign in to comment.