Permalink
Browse files

Merge pull request #962 from groovecoder/django-1.4.5-rebase

Django 1.4.5 rebase
  • Loading branch information...
2 parents 9693034 + b7a4d1d commit 5428513b41dac5845d8c9b39ccfb0170675b5c7e @groovecoder groovecoder committed Mar 27, 2013
@@ -1,7 +1,9 @@
from django.contrib.contenttypes.models import ContentType
-from authority import get_check
-from authority.models import Permission
+# HACK: This breaks the things below, but we don't even use them or the
+# authority app. This fixes a missing database error.
+#from authority import get_check
+#from authority.models import Permission
def has_perm_or_owns(user, perm, obj, perm_obj,
@@ -37,7 +37,7 @@ def contribute_to_class(self, cls, name):
t = ActionCounterCreator(self)
setattr(cls, name, t)
- def get_db_prep_save(self, value):
+ def get_db_prep_save(self, value, connection):
pass
@@ -379,7 +379,7 @@ class Submission(models.Model):
_("Hide this demo from others?"), default=False)
censored = models.BooleanField()
censored_url = models.URLField(
- _("Redirect URL for censorship"),
+ _("Redirect URL for censorship."),
verify_exists=False, blank=True, null=True)
navbar_optout = models.BooleanField(
@@ -430,7 +430,7 @@ class Submission(models.Model):
video_url = VideoEmbedURLField(
_("have a video of your demo in action? (optional)"),
- verify_exists=False, blank=True, null=True)
+ blank=True, null=True)
demo_package = ReplacingZipFileField(
_('select a ZIP file containing your demo'),
@@ -442,7 +442,7 @@ class Submission(models.Model):
source_code_url = models.URLField(
_("Is your source code also available somewhere else on the web (e.g., github)? Please share the link."),
- verify_exists=False, blank=True, null=True)
+ blank=True, null=True)
license_name = models.CharField(
_("Select the license that applies to your source code."),
max_length=64, blank=False,
@@ -138,7 +138,7 @@ <h1 class="mod-title">{{_('Update Your Profile')}}</h1>
<p class="note">{{_('JPEG and PNG supported. Minimum size of 480x360.')}}</p>
</li>
{{ li_field(form, 'video_url', note=_('We support YouTube and Vimeo')) }}
- {{ li_field(form, 'navbar_optout', note=_('If your demo has problems when displayed in an <iframe>, try changing this.')) }}
+ {{ li_field(form, 'navbar_optout', note=_('If your demo has problems when displayed in an &lt;iframe&gt;, try changing this.')) }}
</ul>
</fieldset>
@@ -106,7 +106,7 @@ class Meta:
locale = LocaleField(null=True, blank=True, db_index=True,
verbose_name=_(u'Language'))
homepage = models.URLField(max_length=255, blank=True, default='',
- verify_exists=False, error_messages={
+ error_messages={
'invalid': _(u'This URL has an invalid format. '
u'Valid URLs look like '
u'http://example.com/my_page.')})
@@ -649,12 +649,12 @@ class Event(ModelBase):
date = models.DateField()
end_date = models.DateField(blank=True, null=True)
conference = models.CharField(max_length=255)
- conference_link = models.URLField(blank=True, verify_exists=False)
+ conference_link = models.URLField(blank=True)
location = models.CharField(max_length=255)
people = models.TextField()
description = models.TextField()
done = models.BooleanField(default=False)
- materials = models.URLField(blank=True, verify_exists=False)
+ materials = models.URLField(blank=True)
calendar = models.ForeignKey(Calendar)
class Meta:
@@ -57,3 +57,67 @@ def test_new(self, fetch_user_feed):
class SkippedTestCase(test_utils.TestCase):
def setUp(self):
raise SkipTest()
+
+
+class overrider(object):
+ """
+ See http://djangosnippets.org/snippets/2437/
+
+ Acts as either a decorator, or a context manager. If it's a decorator it
+ takes a function and returns a wrapped function. If it's a contextmanager
+ it's used with the ``with`` statement. In either event entering/exiting
+ are called before and after, respectively, the function/block is executed.
+ """
+ def __init__(self, **kwargs):
+ self.options = kwargs
+
+ def __enter__(self):
+ self.enable()
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ self.disable()
+
+ def __call__(self, func):
+ @wraps(func)
+ def inner(*args, **kwargs):
+ with self:
+ return func(*args, **kwargs)
+ return inner
+
+ def enable(self):
+ pass
+
+ def disable(self):
+ pass
+
+
+class override_constance_settings(overrider):
+ """Decorator / context manager to override constance settings and defeat
+ its caching."""
+
+ def enable(self):
+ self.old_cache = constance_database.db_cache
+ constance_database.db_cache = None
+ self.old_settings = dict((k, getattr(constance.config, k))
+ for k in dir(constance.config))
+ for k, v in self.options.items():
+ constance.config._backend.set(k, v)
+
+ def disable(self):
+ for k, v in self.old_settings.items():
+ constance.config._backend.set(k, v)
+ constance_database.db_cache = self.old_cache
+
+
+class override_settings(overrider):
+ """Decorator / context manager to override Django settings"""
+
+ def enable(self):
+ self.old_settings = settings._wrapped
+ override = UserSettingsHolder(settings._wrapped)
+ for key, new_value in self.options.items():
+ setattr(override, key, new_value)
+ settings._wrapped = override
+
+ def disable(self):
+ settings._wrapped = self.old_settings
@@ -111,29 +111,6 @@ def test_devmo_url(self):
req.locale = 'zh-TW'
eq_(devmo_url(context, localized_page), '/zh_tw/HTML')
- def test_devmo_url_mindtouch_disabled(self):
- _old = settings.DEKIWIKI_ENDPOINT
- settings.DEKIWIKI_ENDPOINT = False
-
- localized_page = 'article-title'
- req = test_utils.RequestFactory().get('/')
- context = {'request': req}
-
- req.locale = 'fr'
- eq_(devmo_url(context, localized_page), '/fr/docs/le-title')
-
- settings.DEKIWIKI_ENDPOINT = _old
-
- def test_devmo_url_mindtouch_disabled_redirect(self):
- # Skipping this test for now, redirect model logic is coupled to view
- raise SkipTest()
- _old = settings.DEKIWIKI_ENDPOINT
- settings.DEKIWIKI_ENDPOINT = False
-
- # TODO: add redirect localized pages to fixture and test
-
- settings.DEKIWIKI_ENDPOINT = _old
-
class TestDevMoUrlResolvers(test_utils.TestCase):
def test_prefixer_get_language(self):
@@ -1,11 +1,11 @@
from nose.tools import eq_, ok_
from pyquery import PyQuery as pq
import test_utils
-import constance.config
from sumo.tests import LocalizingClient
from sumo.urlresolvers import reverse
+from devmo.tests import override_constance_settings
def get_promos(client, url, selector):
r = client.get(url, follow=True)
@@ -27,12 +27,12 @@ def test_social_promo(self):
def test_google_analytics(self):
url = reverse('landing.views.home')
- constance.config.GOOGLE_ANALYTICS_ACCOUNT = '0'
- r = self.client.get(url, follow=True)
- eq_(200, r.status_code)
- ok_('var _gaq' not in r.content)
+ with override_constance_settings(GOOGLE_ANALYTICS_ACCOUNT='0'):
+ r = self.client.get(url, follow=True)
+ eq_(200, r.status_code)
+ ok_('var _gaq' not in r.content)
- constance.config.GOOGLE_ANALYTICS_ACCOUNT = 'UA-99999999-9'
- r = self.client.get(url, follow=True)
- eq_(200, r.status_code)
- ok_('var _gaq' in r.content)
+ with override_constance_settings(GOOGLE_ANALYTICS_ACCOUNT='UA-99999999-9'):
+ r = self.client.get(url, follow=True)
+ eq_(200, r.status_code)
+ ok_('var _gaq' in r.content)
@@ -2,6 +2,7 @@
import re
import urllib
+from django.core import urlresolvers
from django.http import HttpResponsePermanentRedirect, HttpResponseForbidden
from django.middleware import common
from django.utils.encoding import iri_to_uri, smart_str, smart_unicode
@@ -128,6 +129,15 @@ def process_exception(self, request, exception):
return jingo.render(request, 'sumo/read-only.html', status=503)
+def is_valid_path(request, path):
+ urlconf = getattr(request, 'urlconf', None)
+ try:
+ urlresolvers.resolve(path, urlconf)
+ return True
+ except urlresolvers.Resolver404:
+ return False
+
+
class RemoveSlashMiddleware(object):
"""
Middleware that tries to remove a trailing slash if there was a 404.
@@ -139,8 +149,8 @@ class RemoveSlashMiddleware(object):
def process_response(self, request, response):
if (response.status_code == 404
and request.path_info.endswith('/')
- and not common._is_valid_path(request.path_info)
- and common._is_valid_path(request.path_info[:-1])):
+ and not is_valid_path(request, request.path_info)
+ and is_valid_path(request, request.path_info[:-1])):
# Use request.path because we munged app/locale in path_info.
newurl = request.path[:-1]
if request.GET:
@@ -37,7 +37,7 @@ def tearDown(self):
models.signals.pre_delete.disconnect(self.db_error)
def db_error(self, *args, **kwargs):
- raise mysql.OperationalError("You can't do this in read-only mode.")
+ raise DatabaseError("You can't do this in read-only mode.")
def test_db_error(self):
assert_raises(DatabaseError, Question.objects.create, id=12)
@@ -41,13 +41,13 @@ def setUp(self):
@raises(KeyError)
def test_no_dir_attribute(self):
"""Make sure dir attr isn't rendered when no dir is specified."""
- html = jingo.render_to_string(self.request, self.template)
+ html = jingo.render_to_string(self.request.get('/'), self.template)
doc = pq(html)
doc('html')[0].attrib['dir']
def test_rtl_dir_attribute(self):
"""Make sure dir attr is set to 'rtl' when specified as so."""
- html = jingo.render_to_string(self.request, self.template,
+ html = jingo.render_to_string(self.request.get('/'), self.template,
{'dir': 'rtl'})
doc = pq(html)
dir_attr = doc('html').attr['dir']
@@ -59,15 +59,15 @@ def test_multi_feeds(self):
feed_urls = (('/feed_one', 'First Feed'),
('/feed_two', 'Second Feed'),)
- doc = pq(jingo.render_to_string(self.request, self.template,
+ doc = pq(jingo.render_to_string(self.request.get('/'), self.template,
{'feeds': feed_urls}))
feeds = doc('link[type="application/atom+xml"]')
eq_(2, len(feeds))
eq_('First Feed', feeds[0].attrib['title'])
eq_('Second Feed', feeds[1].attrib['title'])
def test_readonly_attr(self):
- html = jingo.render_to_string(self.request, self.template)
+ html = jingo.render_to_string(self.request.get('/'), self.template)
doc = pq(html)
eq_('false', doc('body')[0].attrib['data-readonly'])
@@ -89,7 +89,7 @@ def non_field_errors(self):
source = ("""{% from "layout/errorlist.html" import errorlist %}"""
"""{{ errorlist(form) }}""")
- html = jingo.render_to_string(self.request,
+ html = jingo.render_to_string(self.request.get('/'),
jingo.env.from_string(source),
{'form': MockForm()})
assert '<"evil&ness' not in html
@@ -1,7 +1,7 @@
import threading
from django.conf import settings
-from django.core.handlers.wsgi import WSGIRequest
+from django.test.client import RequestFactory
from django.core.urlresolvers import reverse as django_reverse
from django.utils.translation.trans_real import parse_accept_lang_header
@@ -100,7 +100,7 @@ def split_path(path):
class Prefixer(object):
def __init__(self, request=None, locale=None):
"""If request is omitted, fall back to a default locale."""
- self.request = request or WSGIRequest({'REQUEST_METHOD': 'bogus'})
+ self.request = request or RequestFactory(REQUEST_METHOD='bogus').request()
self.locale, self.shortened_path = split_path(self.request.path_info)
if locale:
self.locale = locale
@@ -1,41 +1,36 @@
import hashlib
-import os
-from django.contrib.auth import models as auth_models
-from django.contrib.auth.backends import ModelBackend
+from django.contrib.auth.hashers import BasePasswordHasher
+from django.contrib.auth.hashers import mask_hash
+from django.utils.crypto import constant_time_compare
+from django.utils.datastructures import SortedDict
-# http://fredericiana.com/2010/10/12/adding-support-for-stronger-password-hashes-to-django/
-"""
-from future import django_sha256_support
-
-Monkey-patch SHA-256 support into Django's auth system. If Django ticket #5600
-ever gets fixed, this can be removed.
-"""
-
-
-def get_hexdigest(algorithm, salt, raw_password):
- """Generate SHA-256 hash."""
- if algorithm == 'sha256':
- return hashlib.sha256((salt + raw_password).encode('utf8')).hexdigest()
- else:
- return get_hexdigest_old(algorithm, salt, raw_password)
-get_hexdigest_old = auth_models.get_hexdigest
-auth_models.get_hexdigest = get_hexdigest
-
-
-def set_password(self, raw_password):
- """Set SHA-256 password."""
- algo = 'sha256'
- salt = os.urandom(5).encode('hex') # Random, 10-digit (hex) salt.
- hsh = get_hexdigest(algo, salt, raw_password)
- self.password = '$'.join((algo, salt, hsh))
-auth_models.User.set_password = set_password
-
-
-class Sha256Backend(ModelBackend):
+class Sha256Hasher(BasePasswordHasher):
"""
- Overriding the Django model backend without changes ensures our
- monkeypatching happens by the time we import auth.
+ SHA-256 password hasher.
+
"""
- pass
+ algorithm = 'sha256'
+ digest = hashlib.sha256
+
+ def encode(self, password, salt):
+ assert password
+ assert salt and '$' not in salt
+ hash = self.digest(salt + password).hexdigest()
+ return "%s$%s$%s" % (self.algorithm, salt, hash)
+
+ def verify(self, password, encoded):
+ algorithm, salt, hash = encoded.split('$', 2)
+ assert algorithm == self.algorithm
+ encoded_2 = self.encode(password, salt)
+ return constant_time_compare(encoded, encoded_2)
+
+ def safe_summary(self, encoded):
+ algorithm, salt, hash = encoded.split('$', 2)
+ assert algorithm == self.algorithm
+ return SortedDict([
+ (_('algorithm'), algorithm),
+ (_('salt'), mask_hash(salt, show=2)),
+ (_('hash'), mask_hash(hash)),
+ ])
Oops, something went wrong.

0 comments on commit 5428513

Please sign in to comment.