From f0b7b4d4df245dfcb73e442255f5f81b64897d21 Mon Sep 17 00:00:00 2001 From: Benjamin Bach Date: Wed, 28 Dec 2016 00:57:05 +0100 Subject: [PATCH] Do not allow slugs that consist only of numbers #558 --- docs/release_notes.rst | 1 + wiki/forms.py | 30 +++++++++++++++++++++++++++++- wiki/tests/test_views.py | 17 +++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/docs/release_notes.rst b/docs/release_notes.rst index 0d1183a3..8ef0833e 100644 --- a/docs/release_notes.rst +++ b/docs/release_notes.rst @@ -38,6 +38,7 @@ django-wiki 0.2 (dev) * Added Django 1.10 support #563 * Fix duplicate search results when logged in #582 (duvholt) + * Do not allow slugs only consisting of numbers #558 * Fix memory leak in markdown extensions setting #564 * Updated translations - Languages > 90% completed: Chinese (China), Portuguese (Brazil), Korean (Korea), French, Slovak, Spanish, Dutch, German, Russian, Finnish. * Taiwanese Chinese added (39% completed) diff --git a/wiki/forms.py b/wiki/forms.py index 36bbb982..5e73ff4e 100644 --- a/wiki/forms.py +++ b/wiki/forms.py @@ -9,7 +9,9 @@ from itertools import chain from django import forms from django.apps import apps from django.contrib.auth.forms import UserCreationForm +from django.core import validators from django.core.urlresolvers import Resolver404, resolve +from django.core.validators import RegexValidator from django.forms.widgets import HiddenInput from django.utils import timezone from django.utils.html import conditional_escape, escape @@ -32,6 +34,32 @@ except ImportError: return(x) +validate_slug_numbers = RegexValidator( + r'^\d+$', + _("A 'slug' cannot consist solely of numbers."), + 'invalid', + inverse_match=True +) + + +class WikiSlugField(forms.SlugField): + """ + In future versions of Django, we might be able to define this field as + the default field directly on the model. For now, it's used in CreateForm. + """ + + default_validators = [validators.validate_slug, validate_slug_numbers] + + def __init__(self, *args, **kwargs): + self.allow_unicode = kwargs.pop('allow_unicode', False) + if self.allow_unicode: + self.default_validators = [ + validators.validate_unicode_slug, + validate_slug_numbers + ] + super(forms.SlugField, self).__init__(*args, **kwargs) + + User = get_user_model() Group = apps.get_model(settings.GROUP_MODEL) @@ -313,7 +341,7 @@ class CreateForm(forms.Form, SpamProtectionMixin): self.urlpath_parent = urlpath_parent title = forms.CharField(label=_('Title'),) - slug = forms.SlugField( + slug = WikiSlugField( label=_('Slug'), help_text=_( "This will be the address where your article can be found. Use only alphanumeric characters and - or _. Note that you cannot change the slug after creating the article."), diff --git a/wiki/tests/test_views.py b/wiki/tests/test_views.py index 3b69cc7f..e726aade 100644 --- a/wiki/tests/test_views.py +++ b/wiki/tests/test_views.py @@ -3,7 +3,9 @@ from __future__ import absolute_import, print_function, unicode_literals import pprint from django.contrib.auth import authenticate +from django.utils.html import escape from wiki import models +from wiki.forms import validate_slug_numbers from wiki.models import reverse from .base import ArticleWebTestBase, WebTestBase @@ -154,6 +156,21 @@ class CreateViewTest(ArticleWebTestBase): 'Content' ) # on level 2') + def test_illegal_slug(self): + + c = self.c + + # A slug cannot be '123' because it gets confused with an article ID. + response = c.post( + reverse('wiki:create', kwargs={'path': ''}), + {'title': 'Illegal slug', 'slug': '123', 'content': 'blah'} + ) + self.assertContains( + response, + escape(validate_slug_numbers.message) + ) + + class DeleteViewTest(ArticleWebTestBase): -- 2.45.2