Permalink
Browse files

Merge remote-tracking branch 'upstream/master'

  • Loading branch information...
2 parents 8b5f6b5 + 79a82f8 commit afc1a7e335373384bddc2f9961fa5edc3be558e1 @ericrasmussen committed Apr 26, 2012
@@ -14,7 +14,7 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000&blobstorage_d
substanced.secret = seekri1
substanced.initial_login = admin
substanced.initial_password = admin
-substanced.form.tempdir = %(here)s/tmp
+substanced.uploads_tempdir = %(here)s/tmp
mail.default_sender = substanced_demo@pylonsproject.org
@@ -137,7 +137,7 @@ class FileUploadTempStore(object):
upload data in the Pyramid session and on disk. The request passed to
its constructor must be a fully-initialized Pyramid request (it have a
``registry`` attribute, which must have a ``settings`` attribute, which
- must be a dictionary). The ``substanced.form.tempdir`` variable in the
+ must be a dictionary). The ``substanced.uploads_tempdir`` variable in the
``settings`` dictionary must be set to the path of an existing directory
on disk. This directory will temporarily store file upload data on
behalf of Deform and Substance D when a form containing a file upload
@@ -148,11 +148,11 @@ class FileUploadTempStore(object):
"""
def __init__(self, request):
try:
- self.tempdir = request.registry.settings['substanced.form.tempdir']
+ self.tempdir=request.registry.settings['substanced.uploads_tempdir']
except KeyError:
raise ConfigurationError(
'To use FileUploadTempStore, you must set a '
- '"substanced.form.tempdir" key in your .ini settings. It '
+ '"substanced.uploads_tempdir" key in your .ini settings. It '
'points to a directory which will temporarily '
'hold uploaded files when form validation fails.')
self.request = request
@@ -101,7 +101,7 @@ def _makeOne(self, request):
def _makeRequest(self):
request = testing.DummyRequest()
request.registry.settings = {}
- request.registry.settings['substanced.form.tempdir'] = self.tempdir
+ request.registry.settings['substanced.uploads_tempdir'] = self.tempdir
request.session = DummySession()
return request
@@ -166,6 +166,12 @@ def test_get_with_randid(self):
self.assertEqual(inst.get('a')['fp'].read(),
open(fn, 'rb').read())
+ def test_get_with_randid_file_doesntexist(self):
+ request = self._makeRequest()
+ inst = self._makeOne(request)
+ inst.tempstore['a'] = {'randid':'1234'}
+ self.assertFalse('fp' in inst.get('a'))
+
def test___getitem___notfound(self):
request = self._makeRequest()
inst = self._makeOne(request)
@@ -47,8 +47,9 @@ class UserToGroup(Interface):
class Principals(Folder):
""" Object representing a collection of principals. Inherits from
:class:`substanced.folder.Folder`. Contains ``users``, an instance of
- :class:`substanced.principal.Users`, and ``groups``, an instance of
- :class:`substanced.principal.Groups`."""
+ :class:`substanced.principal.Users`, ``groups``, an instance of
+ :class:`substanced.principal.Groups`, and ``resets`` an instance of
+ :class:`substanced.principal.PasswordResets`"""
def __init__(self):
Folder.__init__(self)
self['users'] = Users()
@@ -358,7 +359,7 @@ def disconnect(self, *groups):
class UserToPasswordReset(object):
pass
-@content(IPasswordResets, icon='icon-star')
+@content(IPasswordResets, icon='icon-tags')
class PasswordResets(Folder):
""" Object representing the current set of password reset requests """
def _gen_random_token(self):
@@ -375,19 +376,17 @@ def add_reset(self, user):
break
reset = PasswordReset()
self[token] = reset
- reset.__acl__ = [(Allow, Everyone, 'sdi.view')]
+ reset.__acl__ = [(Allow, Everyone, ('sdi.view',))]
objectmap = self.find_service('objectmap')
objectmap.connect(user, reset, UserToPasswordReset)
return reset
-@content(IPasswordReset, icon='icon-question-mark')
+@content(IPasswordReset, icon='icon-tag')
class PasswordReset(Persistent):
""" Object representing the a single password reset request """
def reset_password(self, password):
objectmap = find_service(self, 'objectmap')
sources = list(objectmap.sources(self, UserToPasswordReset))
- if not sources:
- raise ValueError('No user associated with this password reset')
user = sources[0]
user.set_password(password)
self.commit_suicide()
@@ -399,7 +398,7 @@ def commit_suicide(self):
def user_will_be_removed(user, event):
""" Remove all password reset objects associated with a user when the user
is removed """
- objectmap = find_service(event.object, 'objectmap')
+ objectmap = find_service(user, 'objectmap')
if objectmap is not None:
resets = objectmap.targets(user, UserToPasswordReset)
for reset in resets:
@@ -249,6 +249,12 @@ def test_it(self):
self.assertEqual(result.values, [('1', 'group')])
class TestUser(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
def _makeOne(self, password, email=''):
from .. import User
return User(password, email)
@@ -263,6 +269,24 @@ def test_set_password(self):
inst.set_password('abcdef')
self.assertTrue(inst.pwd_manager.check(inst.password, 'abcdef'))
+ def test_email_password_reset(self):
+ from ...testing import make_site
+ from pyramid_mailer import get_mailer
+ site = make_site()
+ principals = site['__services__']['principals']
+ resets = principals['resets'] = testing.DummyResource()
+ def add_reset(user):
+ self.assertEqual(user, inst)
+ resets.add_reset = add_reset
+ request = testing.DummyRequest()
+ request.mgmt_path = lambda *arg: '/mgmt'
+ request.root = site
+ self.config.include('pyramid_mailer.testing')
+ inst = self._makeOne('password')
+ principals['users']['user'] = inst
+ inst.email_password_reset(request)
+ self.assertTrue(get_mailer(request).outbox)
+
def test_get_properties(self):
inst = self._makeOne('abc', 'email')
inst.__name__ = 'fred'
@@ -450,6 +474,69 @@ def test_garden_path(self):
request.context = context
result = self._callFUT(1, request)
self.assertEqual(result, (1,2))
+
+class TestPasswordResets(unittest.TestCase):
+ def _makeOne(self):
+ from .. import PasswordResets
+ return PasswordResets()
+
+ def test_add_reset(self):
+ from .. import UserToPasswordReset
+ inst = self._makeOne()
+ objectmap = DummyObjectMap()
+ services = testing.DummyResource()
+ inst.add('__services__', services, allow_services=True)
+ services['objectmap'] = objectmap
+ user = testing.DummyResource()
+ reset = inst.add_reset(user)
+ self.assertEqual(
+ objectmap.connections,
+ [(user, reset, UserToPasswordReset)])
+ self.assertTrue(reset.__acl__)
+ self.assertEqual(len(inst), 2)
+
+class TestPasswordReset(unittest.TestCase):
+ def _makeOne(self):
+ from .. import PasswordReset
+ return PasswordReset()
+
+ def test_reset_password(self):
+ from ...interfaces import IFolder
+ parent = testing.DummyResource(__provides__=IFolder)
+ user = testing.DummyResource()
+ def set_password(password):
+ user.password = password
+ user.set_password = set_password
+ objectmap = DummyObjectMap((user,))
+ inst = self._makeOne()
+ parent['reset'] = inst
+ services = testing.DummyResource()
+ parent['__services__'] = services
+ services['objectmap'] = objectmap
+ inst.reset_password('password')
+ self.assertEqual(user.password, 'password')
+ self.assertFalse('reset' in parent)
+
+class Test_user_will_be_removed(unittest.TestCase):
+ def _callFUT(self, user, event):
+ from .. import user_will_be_removed
+ return user_will_be_removed(user, event)
+
+ def test_it(self):
+ from ...interfaces import IFolder
+ parent = testing.DummyResource(__provides__=IFolder)
+ user = testing.DummyResource()
+ reset = testing.DummyResource()
+ def commit_suicide():
+ reset.committed = True
+ reset.commit_suicide = commit_suicide
+ objectmap = DummyObjectMap((reset,))
+ services = testing.DummyResource()
+ parent['__services__'] = services
+ parent['user'] = user
+ services['objectmap'] = objectmap
+ self._callFUT(user, None)
+ self.assertTrue(reset.committed)
from ...interfaces import IFolder
@@ -111,6 +111,61 @@ def test_send_success(self):
self.assertEqual(resp.location, 'http://example.com')
self.assertTrue(user.emailed_password_reset)
+class TestResetView(unittest.TestCase):
+ def _makeOne(self, request):
+ from ..views import ResetView
+ return ResetView(request)
+
+ def _makeRequest(self):
+ request = testing.DummyRequest()
+ request.mgmt_path = lambda *arg : 'http://example.com'
+ return request
+
+ def test_reset_success(self):
+ context = testing.DummyResource()
+ def reset_password(password):
+ self.assertEqual(password, 'thepassword')
+ context.reset_password = reset_password
+ request = self._makeRequest()
+ request.context = context
+ inst = self._makeOne(request)
+ resp = inst.reset_success({'new_password':'thepassword'})
+ self.assertEqual(resp.location, 'http://example.com')
+
+
+class Test_login_validator(unittest.TestCase):
+ def _makeOne(self, node, kw):
+ from ..views import login_validator
+ return login_validator(node, kw)
+
+ def _makeSite(self):
+ from ...interfaces import IFolder
+ site = testing.DummyResource(__provides__=IFolder)
+ services = testing.DummyResource()
+ principals = testing.DummyResource()
+ users = testing.DummyResource()
+ site['__services__'] = services
+ services['principals'] = principals
+ principals['users'] = users
+ return site
+
+ def test_no_such_user(self):
+ import colander
+ request = testing.DummyRequest()
+ site = self._makeSite()
+ request.context = site
+ inst = self._makeOne(None, dict(request=request))
+ self.assertRaises(colander.Invalid, inst, None, 'fred')
+
+ def test_user_exists(self):
+ request = testing.DummyRequest()
+ site = self._makeSite()
+ request.context = site
+ fred = testing.DummyResource()
+ site['__services__']['principals']['users']['fred'] = fred
+ inst = self._makeOne(None, dict(request=request))
+ self.assertEqual(inst(None, 'fred'), None)
+
class DummyPrincipal(object):
def connect(self, *args):
self.connected = args
@@ -105,7 +105,7 @@ def login_validator(node, kw):
def _login_validator(node, value):
principals = find_service(context, 'principals')
users = principals['users']
- if users.get(value) is None:
+ if not value in users:
raise colander.Invalid(node, 'No such user %s' % value)
return _login_validator
@@ -131,7 +131,7 @@ def send_success(self, appstruct):
users = principals['users']
user = users[login]
user.email_password_reset(request)
- request.session.flash('Emailed reset instructions', 'success')
+ request.session.flash('Emailed password reset instructions', 'success')
home = request.mgmt_path(request.root)
return HTTPFound(location=home)
@@ -154,6 +154,6 @@ def reset_success(self, appstruct):
request = self.request
context = self.request.context
context.reset_password(appstruct['new_password'])
- request.session.flash('Password reset, now please log in', 'success')
+ request.session.flash('Password reset, you may now log in', 'success')
home = request.mgmt_path(request.root)
return HTTPFound(location=home)

0 comments on commit afc1a7e

Please sign in to comment.