From: Joseph Spiros Date: Tue, 22 Jun 2010 16:12:12 +0000 (-0400) Subject: Merge branch 'melinath' X-Git-Tag: philo-0.9~76 X-Git-Url: http://git.ithinksw.org/philo.git/commitdiff_plain/d7454a2bc147c702f6ee8036b2818130012a1192?hp=48e24c78145414580099209ae49f6b41d10ec7c9 Merge branch 'melinath' * melinath: Pre-merge cleanup. Switched URLRedirectValidator and URLLinkValidator to subclass directly from RegexValidator. --Avoids having to implement verify_exists for a link on a node that, say, might not even be on a site per se. If that's something I want later, I can look at it then... for now, this will fulfill its function just fine. Explicated DoesNotExist exception for PageAdmin save_model method. Added get_path fallback to slug to increase information flow by reducing the number of ? displayed Revert Redirect unicode. Added Redirect unicode. Added redirect and link validators to allow internal-style absolute and relative links/redirects. Fixed null content reference id bug. --- diff --git a/admin.py b/admin.py index 64893d5..9e991d9 100644 --- a/admin.py +++ b/admin.py @@ -228,7 +228,7 @@ class PageAdmin(NodeAdmin): initial_content = None try: initial_content = page.contentreferences.get(name__exact=container_name, content_type=container_content_type).content.pk - except ContentReference.DoesNotExist: + except (ContentReference.DoesNotExist, AttributeError): pass form.base_fields[('contentreference_container_%s' % container_name)] = forms.ModelChoiceField(label='References', widget=ModelLookupWidget(container_content_type), initial=initial_content, required=False, queryset=container_content_type.model_class().objects.all()) return form @@ -249,10 +249,17 @@ class PageAdmin(NodeAdmin): for container_name, container_content_type in contentreference_containers: if ('contentreference_container_%s' % container_name) in form.cleaned_data: content = form.cleaned_data[('contentreference_container_%s' % container_name)] - contentreference, created = page.contentreferences.get_or_create(name=container_name, defaults={'content': content}) - if not created: - contentreference.content = content - contentreference.save() + try: + contentreference = page.contentreferences.get(name=container_name) + except ContentReference.DoesNotExist: + contentreference = ContentReference(name=container_name, page=page, content_type=container_content_type) + + if content == None: + contentreference.content_id = None + else: + contentreference.content_id = content.id + + contentreference.save() class TemplateAdmin(admin.ModelAdmin): diff --git a/models.py b/models.py index 1c71889..c17cd70 100644 --- a/models.py +++ b/models.py @@ -19,6 +19,7 @@ from django.template.loader import get_template from django.http import Http404, HttpResponse, HttpResponseServerError, HttpResponseRedirect from django.core.servers.basehttp import FileWrapper from django.conf import settings +from philo.validators import RedirectValidator def register_value_model(model): @@ -213,13 +214,16 @@ class InheritableTreeEntity(TreeEntity): @property def instance(self): - return self.instance_type.get_object_for_this_type(id=self.id) + try: + return self.instance_type.get_object_for_this_type(id=self.id) + except: + return None def get_path(self, pathsep='/', field='slug'): - path = getattr(self.instance, field, '?') + path = getattr(self.instance, field, getattr(self.instance, 'slug', '?')) parent = self.parent while parent: - path = getattr(parent.instance, field, '?') + pathsep + path + path = getattr(parent.instance, field, getattr(parent.instance, 'slug', '?')) + pathsep + path parent = parent.parent return path path = property(get_path) @@ -272,7 +276,7 @@ class Redirect(Node): (302, 'Temporary'), (301, 'Permanent'), ) - target = models.URLField(help_text='Must be a valid, absolute URL (i.e. http://)') + target = models.CharField(max_length=200,validators=[RedirectValidator()]) status_code = models.IntegerField(choices=STATUS_CODES, default=302, verbose_name='redirect type') def render_to_response(self, request, path=None, subpath=None): @@ -396,7 +400,7 @@ class ContentReference(models.Model): page = models.ForeignKey(Page, related_name='contentreferences') name = models.CharField(max_length=255) content_type = models.ForeignKey(ContentType, verbose_name='Content type') - content_id = models.PositiveIntegerField(verbose_name='Content ID') + content_id = models.PositiveIntegerField(verbose_name='Content ID', blank=True, null=True) content = generic.GenericForeignKey('content_type', 'content_id') def __unicode__(self): diff --git a/validators.py b/validators.py index bc41d02..0c6fa78 100644 --- a/validators.py +++ b/validators.py @@ -1,5 +1,7 @@ from django.core.exceptions import ValidationError from django.utils.translation import ugettext_lazy as _ +from django.core.validators import RegexValidator +import re class TreeParentValidator(object): @@ -42,7 +44,8 @@ class TreeParentValidator(object): def get_message(self): return self.static_message or _(u"A %s can't be its own parent." % self.instance.__class__.__name__) message = property(get_message) - + + class TreePositionValidator(object): code = 'invalid' @@ -51,7 +54,7 @@ class TreePositionValidator(object): self.slug = slug self.obj_class = obj_class self.static_message = message - + if code is not None: self.code = code @@ -68,10 +71,37 @@ class TreePositionValidator(object): if obj.id != value.id: raise ValidationError(self.message) - + except self.obj_class.DoesNotExist: pass def get_message(self): return self.static_message or _(u"A %s with that path (parent and slug) already exists." % self.obj_class.__name__) message = property(get_message) + + +class RedirectValidator(RegexValidator): + """Based loosely on the URLValidator, but no option to verify_exists""" + regex = re.compile( + r'^(?:https?://' # http:// or https:// + r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' #domain... + r'localhost|' #localhost... + r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip + r'(?::\d+)?' # optional port + r'(?:/?|[/?#]?\S+)|' + r'[^?#\s]\S*)$', + re.IGNORECASE) + message = _(u'Enter a valid absolute or relative redirect target') + + +class URLLinkValidator(RegexValidator): + """Based loosely on the URLValidator, but no option to verify_exists""" + regex = re.compile( + r'^(?:https?://' # http:// or https:// + r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' #domain... + r'localhost|' #localhost... + r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip + r'(?::\d+)?' # optional port + r'|)' # also allow internal links + r'(?:/?|[/?#]?\S+)$', re.IGNORECASE) + message = _(u'Enter a valid absolute or relative redirect target')