Permalink
Browse files

Merge remote-tracking branch 'upstream/ro/pr/refactor-0.5.0' into jf/…

…refactor-0.5.0
  • Loading branch information...
2 parents 351b8e7 + 3ddceb8 commit a6c5665d40390c38c113051af75e3bd06aee5a07 Josh Finnie committed Nov 27, 2012
Showing with 194 additions and 4 deletions.
  1. +107 −0 lumin/resource.py
  2. +2 −2 lumin/schema.py
  3. +85 −2 lumin/tests/test_schema.py
View
@@ -0,0 +1,107 @@
+from pyramid.security import (
+ Allow,
+ Everyone
+ )
+
+
+class Factory(object):
+ """Pyramid `resource nee context <http://bit.ly/pyramid-latest-resources>`
+ factory base class.
+ """
+
+ _default__acl__ = __acl__ = [
+ [Allow, Everyone, 'view'],
+ ]
+
+ __name__ = __parent__ = None
+
+ def __init__(self, request):
+ self.data = {}
+ self.request = request
+ for ace in self._default__acl__:
+ if ace not in self.__acl__:
+ self.add_ace(ace)
+
+ def get__acl__(self):
+ return self.data.get('__acl__', [])
+
+ def set__acl__(self, acl):
+ self.data['__acl__'] = acl
+
+ def delete__acl__(self):
+ del self.data['__acl__']
+
+ __acl__ = property(get__acl__, set__acl__, delete__acl__)
+
+ def _acl_apply(self, ace, mutator):
+ if not isinstance(ace, list):
+ raise TypeError(
+ "{} is not a list, mongo stores tuples as a list."
+ "Please use lists".format(ace))
+
+ acl = self.__acl__
+
+ if not acl:
+ self.__acl__ = [ace]
+ return
+
+ a, p, perms = ace
+
+ assert not isinstance(perms, tuple)
+ if not isinstance(perms, list):
+ perms = (perms, )
+
+ perms = set(perms)
+
+ for i, (action, principal, permissions) in enumerate(acl):
+ if a == action and p == principal:
+ if not isinstance(permissions, list):
+ permissions = (permissions, )
+
+ permissions = set(permissions)
+
+ # Note that set arguments are updated in place
+ mutator(permissions, perms)
+
+ # Set updated permissions as a sorted list
+ acl[i][-1] = self._acl_sorted(permissions)
+
+ # Stop when we've applied all permissions
+ if not perms:
+ break
+ else:
+ if perms:
+ value = self._acl_sorted(perms)
+ acl.append([a, p, value])
+
+ # Filter out trivial entries
+ #acl[:] = [a_p_permissions for a_p_permissions in acl if a_p_permissions[2] if isinstance(a_p_permissions[2], list) else True]
+ ## PY3: ^ 2to3 suggested to replace lambda below
+ acl[:] = filter(
+ lambda ace: \
+ ace[2] if isinstance(ace[2], list) else True,
+ acl
+ )
+
+ def _acl_add(self, existing, added):
+ existing |= added
+ added.clear()
+
+ def _acl_remove(self, existing, added):
+ intersection = existing & added
+
+ existing -= intersection
+ added -= intersection
+
+ def _acl_sorted(self, permissions):
+ if len(permissions) == 1:
+ for permission in permissions:
+ return permission
+ else:
+ return list(sorted(permissions))
+
+ def add_ace(self, ace):
+ self._acl_apply(ace, self._acl_add)
+
+ def remove_ace(self, ace):
+ self._acl_apply(ace, self._acl_remove)
View
@@ -17,8 +17,8 @@ def validate_username(node, value):
24 lowercase alphanumeric characters")
if not value.replace('_', '').isalnum() or not value.islower():
raise colander.Invalid(node,
- "Only lowercase numbers, letters and \
- underscores are permitted")
+ "Only lowercase numbers, letters and \
+ underscores are permitted")
if not value[0].isalpha():
raise colander.Invalid(node,
"The username must start with a \
@@ -38,9 +38,92 @@ def _call_fut(self, value):
func = deferred_username_validator(node, {"request": self.request})
return func(node, value)
- def test_username_too_short(self):
+ def test_username_too_short_raises(self):
from colander import Invalid
self.assertRaises(
Invalid,
- self._call_fut, 'aname'
+ self._call_fut, 'aaa'
)
+
+ def test_username_too_short_exception(self):
+ from colander import Invalid
+ result = None
+ try:
+ result = self._call_fut('aaa')
+ except Invalid as e:
+ self.assertEquals(e.msg, "Length of user name must be between 4 and \
+ 24 lowercase alphanumeric characters")
+ self.failUnless(result is None)
+
+ def test_username_too_long_exception(self):
+ from colander import Invalid
+ import string
+ result = None
+ try:
+ result = self._call_fut(string.ascii_lowercase)
+ except Invalid as e:
+ self.assertEquals(e.msg, "Length of user name must be between 4 and \
+ 24 lowercase alphanumeric characters")
+ self.failUnless(result is None)
+
+ def test_username_not_lower_exception(self):
+ from colander import Invalid
+ result = None
+ try:
+ result = self._call_fut("AAAA")
+ except Invalid as e:
+ self.assertEquals(e.msg,
+ "Only lowercase numbers, letters and \
+ underscores are permitted")
+ self.failUnless(result is None)
+
+ def test_username_has_special_char_exception(self):
+ from colander import Invalid
+ result = None
+ try:
+ result = self._call_fut("asn$sldkjf")
+ except Invalid as e:
+ self.assertEquals(e.msg,
+ "Only lowercase numbers, letters and \
+ underscores are permitted")
+ self.failUnless(result is None)
+
+ def test_username_has_space_exception(self):
+ from colander import Invalid
+ result = None
+ try:
+ result = self._call_fut(" asnsldkjf")
+ except Invalid as e:
+ self.assertEquals(e.msg,
+ "Only lowercase numbers, letters and \
+ underscores are permitted")
+ self.failUnless(result is None)
+
+ def test_username_not_alpha_start_exception(self):
+ from colander import Invalid
+ result = None
+ try:
+ result = self._call_fut("3asnsldkjf")
+ except Invalid as e:
+ self.assertEquals(e.msg,
+ "The username must start with a \
+ letter")
+ self.failUnless(result is None)
+
+ def test_username_not_available(self):
+ from colander import Invalid
+ result = None
+ try:
+ result = self._call_fut("aname")
+ except Invalid as e:
+ self.assertEquals(e.msg, "Username is not available")
+ self.failUnless(result is None)
+
+ def test_username_available(self):
+ from colander import Invalid
+ result = None
+ try:
+ result = self._call_fut("available_name")
+ except Invalid as e:
+ self.failIf(e)
+ self.assertEquals(result, None)

0 comments on commit a6c5665

Please sign in to comment.