summaryrefslogtreecommitdiff
path: root/django/core
diff options
context:
space:
mode:
authorJoseph Kocherhans <joseph@jkocherhans.com>2006-05-16 20:39:14 +0000
committerJoseph Kocherhans <joseph@jkocherhans.com>2006-05-16 20:39:14 +0000
commite1184016a29b90694e3624d646b35b9d4aa4756e (patch)
treef15b0c5f1ccd0f22b132b97403304263da579fb9 /django/core
parent93937ed38a828e0f252fb25614516593ec7b9ab0 (diff)
multi-auth: Merged to [2919]
git-svn-id: http://code.djangoproject.com/svn/django/branches/multi-auth@2921 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/core')
-rw-r--r--django/core/mail.py5
-rw-r--r--django/core/urlresolvers.py78
2 files changed, 82 insertions, 1 deletions
diff --git a/django/core/mail.py b/django/core/mail.py
index 3baf191b5c..415cb6e8fc 100644
--- a/django/core/mail.py
+++ b/django/core/mail.py
@@ -2,6 +2,7 @@
from django.conf import settings
from email.MIMEText import MIMEText
+from email.Header import Header
import smtplib
class BadHeaderError(ValueError):
@@ -12,6 +13,8 @@ class SafeMIMEText(MIMEText):
"Forbids multi-line headers, to prevent header injection."
if '\n' in val or '\r' in val:
raise BadHeaderError, "Header values can't contain newlines (got %r for header %r)" % (val, name)
+ if name == "Subject":
+ val = Header(val, settings.DEFAULT_CHARSET)
MIMEText.__setitem__(self, name, val)
def send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=settings.EMAIL_HOST_USER, auth_password=settings.EMAIL_HOST_PASSWORD):
@@ -42,7 +45,7 @@ def send_mass_mail(datatuple, fail_silently=False, auth_user=settings.EMAIL_HOST
if not recipient_list:
continue
from_email = from_email or settings.DEFAULT_FROM_EMAIL
- msg = SafeMIMEText(message)
+ msg = SafeMIMEText(message, 'plain', settings.DEFAULT_CHARSET)
msg['Subject'] = subject
msg['From'] = from_email
msg['To'] = ', '.join(recipient_list)
diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py
index e11b63e977..db4967e1c5 100644
--- a/django/core/urlresolvers.py
+++ b/django/core/urlresolvers.py
@@ -14,12 +14,56 @@ import re
class Resolver404(Http404):
pass
+class NoReverseMatch(Exception):
+ pass
+
def get_mod_func(callback):
# Converts 'django.views.news.stories.story_detail' to
# ['django.views.news.stories', 'story_detail']
dot = callback.rindex('.')
return callback[:dot], callback[dot+1:]
+class MatchChecker(object):
+ "Class used in reverse RegexURLPattern lookup."
+ def __init__(self, args, kwargs):
+ self.args, self.kwargs = args, kwargs
+ self.current_arg = 0
+
+ def __call__(self, match_obj):
+ # match_obj.group(1) is the contents of the parenthesis.
+ # First we need to figure out whether it's a named or unnamed group.
+ #
+ grouped = match_obj.group(1)
+ m = re.search(r'^\?P<(\w+)>(.*?)$', grouped)
+ if m: # If this was a named group...
+ # m.group(1) is the name of the group
+ # m.group(2) is the regex.
+ try:
+ value = self.kwargs[m.group(1)]
+ except KeyError:
+ # It was a named group, but the arg was passed in as a
+ # positional arg or not at all.
+ try:
+ value = self.args[self.current_arg]
+ self.current_arg += 1
+ except IndexError:
+ # The arg wasn't passed in.
+ raise NoReverseMatch('Not enough positional arguments passed in')
+ test_regex = m.group(2)
+ else: # Otherwise, this was a positional (unnamed) group.
+ try:
+ value = self.args[self.current_arg]
+ self.current_arg += 1
+ except IndexError:
+ # The arg wasn't passed in.
+ raise NoReverseMatch('Not enough positional arguments passed in')
+ test_regex = grouped
+ # Note we're using re.match here on purpose because the start of
+ # to string needs to match.
+ if not re.match(test_regex + '$', str(value)): # TODO: Unicode?
+ raise NoReverseMatch("Value %r didn't match regular expression %r" % (value, test_regex))
+ return str(value) # TODO: Unicode?
+
class RegexURLPattern:
def __init__(self, regex, callback, default_args=None):
# regex is a string representing a regular expression.
@@ -58,12 +102,37 @@ class RegexURLPattern:
except AttributeError, e:
raise ViewDoesNotExist, "Tried %s in module %s. Error was: %s" % (func_name, mod_name, str(e))
+ def reverse(self, viewname, *args, **kwargs):
+ if viewname != self.callback:
+ raise NoReverseMatch
+ return self.reverse_helper(*args, **kwargs)
+
+ def reverse_helper(self, *args, **kwargs):
+ """
+ Does a "reverse" lookup -- returns the URL for the given args/kwargs.
+ The args/kwargs are applied to the regular expression in this
+ RegexURLPattern. For example:
+
+ >>> RegexURLPattern('^places/(\d+)/$').reverse_helper(3)
+ 'places/3/'
+ >>> RegexURLPattern('^places/(?P<id>\d+)/$').reverse_helper(id=3)
+ 'places/3/'
+ >>> RegexURLPattern('^people/(?P<state>\w\w)/(\w+)/$').reverse_helper('adrian', state='il')
+ 'people/il/adrian/'
+
+ Raises NoReverseMatch if the args/kwargs aren't valid for the RegexURLPattern.
+ """
+ # TODO: Handle nested parenthesis in the following regex.
+ result = re.sub(r'\(([^)]+)\)', MatchChecker(args, kwargs), self.regex.pattern)
+ return result.replace('^', '').replace('$', '')
+
class RegexURLResolver(object):
def __init__(self, regex, urlconf_name):
# regex is a string representing a regular expression.
# urlconf_name is a string representing the module containing urlconfs.
self.regex = re.compile(regex)
self.urlconf_name = urlconf_name
+ self.callback = None
def resolve(self, path):
tried = []
@@ -110,3 +179,12 @@ class RegexURLResolver(object):
def resolve500(self):
return self._resolve_special('500')
+
+ def reverse(self, viewname, *args, **kwargs):
+ for pattern in self.urlconf_module.urlpatterns:
+ if pattern.callback == viewname:
+ try:
+ return pattern.reverse_helper(*args, **kwargs)
+ except NoReverseMatch:
+ continue
+ raise NoReverseMatch