Commits

jgsogo committed f8987e5 Draft

link class admits mixins

  • Participants
  • Parent commits f87c5c0

Comments (0)

Files changed (7)

File shortener/baseconv.py

-"""
-Convert numbers from base 10 integers to base X strings and back again.
-
-Original: http://www.djangosnippets.org/snippets/1431/
-
-Sample usage:
-
->>> base20 = BaseConverter('0123456789abcdefghij')
->>> base20.from_decimal(1234)
-'31e'
->>> base20.to_decimal('31e')
-1234
-"""
-
-class BaseConverter(object):
-    decimal_digits = "0123456789"
-
-    def __init__(self, digits):
-        self.digits = digits
-
-    def from_decimal(self, i):
-        return self.convert(i, self.decimal_digits, self.digits)
-
-    def to_decimal(self, s):
-        return int(self.convert(s, self.digits, self.decimal_digits))
-
-    def convert(number, fromdigits, todigits):
-        # Based on http://code.activestate.com/recipes/111286/
-        if str(number)[0] == '-':
-            number = str(number)[1:]
-            neg = 1
-        else:
-            neg = 0
-
-        # make an integer out of the number
-        x = 0
-        for digit in str(number):
-           x = x * len(fromdigits) + fromdigits.index(digit)
-
-        # create the result in base 'len(todigits)'
-        if x == 0:
-            res = todigits[0]
-        else:
-            res = ""
-            while x > 0:
-                digit = x % len(todigits)
-                res = todigits[digit] + res
-                x = int(x / len(todigits))
-            if neg:
-                res = '-' + res
-        return res
-    convert = staticmethod(convert)
-
-bin = BaseConverter('01')
-hexconv = BaseConverter('0123456789ABCDEF')
-base62 = BaseConverter(
-    'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz'
-)
-
-
-if __name__ == '__main__':
-    nums = [-10 ** 10, 10 ** 10] + range(-100, 100)
-    for convertor in [bin, hexconv, base62]:
-        for i in nums:
-            assert i == bin.to_decimal(bin.from_decimal(i)), '%s failed' % i

File shortener/mixins.py

+#!/usr/bin/env python
+# encoding: utf-8
+
+from django.db import models
+from django.contrib.auth.models import User
+
+from shortener.settings import LOGIN_REQUIRED
+
+
+class EnhancedLink(models.Model):
+
+    user = models.ForeignKey(User, blank=not LOGIN_REQUIRED, null= not LOGIN_REQUIRED)
+    created = models.DateTimeField(auto_now=True)
+
+    class Meta:
+        abstract = True
+
+    @classmethod
+    def create(cls, url, user):
+        instance = super(EnhancedLink, cls).create(url, commit=False)
+        instance.user = user
+        instance.save()
+        return instance

File shortener/models.py

 from django.core.validators import URLValidator
 from django.core.exceptions import ValidationError
 
-from shortener.settings import LINK_UNIQUENESS, HASH_SEED_LENGTH, SITE_BASE_URL, HASH_STRATEGY
-from shortener.baseconv import base62
+from shortener.settings import LINK_UNIQUENESS, HASH_SEED_LENGTH, SITE_BASE_URL, HASH_STRATEGY, LINK_MIXIN
+from shortener.utils.baseconv import base62
+from shortener.utils import get_basemodel_mixin
 
 log = logging.getLogger(__name__)
 
-class Link(models.Model):
+class BaseLink(models.Model):
     _hash = models.CharField(max_length=8) # n-char unique random string
     url = models.CharField(max_length=2083) # http://www.boutell.com/newfaq/misc/urllength.html
     created = models.DateTimeField(auto_now=False, auto_now_add=True)
 
+    class Meta:
+        abstract = True
+
     def __unicode__(self):
         return u'%s' % self.url
 
     def get_short_link(self):
         return u'%s/%s' % (SITE_BASE_URL, self._hash)
-
+    """
     @classmethod
     def get_or_create(cls, url):
         try:
-            return Link.objects.get(url=url)
+            return cls.objects.get(url=url)
         except cls.DoesNotExist:
             return cls.create(url)
-
+    """
     @classmethod
     def create(cls, url, commit=True):
         log.debug("Link::create(url='%s')" % url)
 
     @classmethod
     def hash_exists(cls, hash_):
-        return Link.objects.filter(_hash=hash_).exists()
+        return cls.objects.filter(_hash=hash_).exists()
 
     @classmethod
     def link_exists(cls, url):
-        return Link.objects.filter(url=url).exists()
+        return cls.objects.filter(url=url).exists()
 
     @classmethod
     def url_is_valid(cls, url):
             return True
         except ValidationError:
             return False
+
+
+if LINK_MIXIN:
+    Mixin = get_basemodel_mixin(LINK_MIXIN)
+    class Link(Mixin, BaseLink):
+        class Meta(Mixin.Meta):
+            abstract = False
+
+else:
+    class Link(BaseLink):
+        class Meta:
+            abstract = False

File shortener/settings.py

 
 from django.conf import settings
 
+LINK_MIXIN = getattr(settings, 'SHORTENER_LINK_MIXIN', None)
+LOGIN_REQUIRED = getattr(settings, 'SHORTENER_LOGIN_REQUIRED', False)
+
 LINK_UNIQUENESS = getattr(settings, 'SHORTENER_LINK_UNIQUENESS', False)
 
 HASH_STRATEGY = getattr(settings, 'SHORTENER_HASH_STRATEGY', None)

File shortener/utils/__init__.py

+#!/usr/bin/env python
+# encoding: utf-8
+
+from importer import load_class, get_basemodel_mixin

File shortener/utils/baseconv.py

+"""
+Convert numbers from base 10 integers to base X strings and back again.
+
+Original: http://www.djangosnippets.org/snippets/1431/
+
+Sample usage:
+
+>>> base20 = BaseConverter('0123456789abcdefghij')
+>>> base20.from_decimal(1234)
+'31e'
+>>> base20.to_decimal('31e')
+1234
+"""
+
+class BaseConverter(object):
+    decimal_digits = "0123456789"
+
+    def __init__(self, digits):
+        self.digits = digits
+
+    def from_decimal(self, i):
+        return self.convert(i, self.decimal_digits, self.digits)
+
+    def to_decimal(self, s):
+        return int(self.convert(s, self.digits, self.decimal_digits))
+
+    def convert(number, fromdigits, todigits):
+        # Based on http://code.activestate.com/recipes/111286/
+        if str(number)[0] == '-':
+            number = str(number)[1:]
+            neg = 1
+        else:
+            neg = 0
+
+        # make an integer out of the number
+        x = 0
+        for digit in str(number):
+           x = x * len(fromdigits) + fromdigits.index(digit)
+
+        # create the result in base 'len(todigits)'
+        if x == 0:
+            res = todigits[0]
+        else:
+            res = ""
+            while x > 0:
+                digit = x % len(todigits)
+                res = todigits[digit] + res
+                x = int(x / len(todigits))
+            if neg:
+                res = '-' + res
+        return res
+    convert = staticmethod(convert)
+
+bin = BaseConverter('01')
+hexconv = BaseConverter('0123456789ABCDEF')
+base62 = BaseConverter(
+    'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz'
+)
+
+
+if __name__ == '__main__':
+    nums = [-10 ** 10, 10 ** 10] + range(-100, 100)
+    for convertor in [bin, hexconv, base62]:
+        for i in nums:
+            assert i == bin.to_decimal(bin.from_decimal(i)), '%s failed' % i

File shortener/utils/importer.py

+#!/usr/bin/env python
+# encoding: utf-8
+
+from django.db import models
+from django.core.exceptions import  ImproperlyConfigured
+
+def load_class(class_str):
+    if isinstance(class_str, basestring):
+        components = class_str.split('.')
+        mod = __import__('.'.join(components[:-1]), fromlist=components[-1:])
+        as_class = getattr(mod, components[-1:][0])
+        return as_class
+    else:
+        raise ValueError("Argument must be a string")
+
+def get_basemodel_mixin(basemodel_mixin):
+    if isinstance(basemodel_mixin, basestring):
+        as_model = load_class(basemodel_mixin)
+        return get_basemodel_mixin(as_model)
+
+    if issubclass(basemodel_mixin, models.Model) and basemodel_mixin._meta.abstract:
+        return basemodel_mixin
+    else:
+        raise ImproperlyConfigured("'%s' must be an abstract django model." % basemodel_mixin)