You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by jo...@apache.org on 2013/07/08 20:58:35 UTC

git commit: [#4656] More refactor to project shortname validation

Updated Branches:
  refs/heads/cj/4656 dd798ee2a -> 6fc50ebd2


[#4656] More refactor to project shortname validation

Signed-off-by: Cory Johns <cj...@slashdotmedia.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/6fc50ebd
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/6fc50ebd
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/6fc50ebd

Branch: refs/heads/cj/4656
Commit: 6fc50ebd2a121eb0a7814d8b74f3a6756a2a3e97
Parents: dd798ee
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Mon Jul 8 18:57:19 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Mon Jul 8 18:57:19 2013 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/project.py            |  3 +-
 Allura/allura/lib/plugin.py                     | 42 +++++++++++++++-----
 Allura/allura/lib/widgets/forms.py              |  9 ++---
 .../tests/functional/test_neighborhood.py       | 14 +++----
 4 files changed, 44 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6fc50ebd/Allura/allura/controllers/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/project.py b/Allura/allura/controllers/project.py
index 36c4667..3cf4112 100644
--- a/Allura/allura/controllers/project.py
+++ b/Allura/allura/controllers/project.py
@@ -81,7 +81,8 @@ class NeighborhoodController(object):
     def _lookup(self, pname, *remainder):
         pname = unquote(pname)
         provider = plugin.ProjectRegistrationProvider.get()
-        if provider.validate_project_shortname(pname, self.neighborhood):
+        valid, reason = provider.valid_project_shortname(pname, self.neighborhood)
+        if not valid:
             raise exc.HTTPNotFound, pname
         project = M.Project.query.get(shortname=self.prefix + pname, neighborhood_id=self.neighborhood._id)
         if project is None and self.prefix == 'u/':

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6fc50ebd/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 111aa77..76a18ae 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -364,16 +364,14 @@ class ProjectRegistrationProvider(object):
         method = config.get('registration.method', 'local')
         return app_globals.Globals().entry_points['registration'][method]()
 
-    def name_taken(self, project_name, neighborhood):
+    def _name_taken(self, project_name, neighborhood):
         """Return False if ``project_name`` is available in ``neighborhood``.
         If unavailable, return an error message (str) explaining why.
 
         """
         from allura import model as M
         p = M.Project.query.get(shortname=project_name, neighborhood_id=neighborhood._id)
-        if p:
-            return 'This project name is taken.'
-        return False
+        return bool(p)
 
     def suggest_name(self, project_name, neighborhood):
         """Return a suggested project shortname for the full ``project_name``.
@@ -469,21 +467,45 @@ class ProjectRegistrationProvider(object):
             check_shortname = shortname.replace('u/', '', 1)
         else:
             check_shortname = shortname
-        err = self.validate_project_shortname(check_shortname, neighborhood)
-        if err:
+        allowed, err = self.allowed_project_shortname(check_shortname, neighborhood)
+        if not allowed:
             raise ValueError('Invalid project shortname: %s' % shortname)
 
         p = M.Project.query.get(shortname=shortname, neighborhood_id=neighborhood._id)
         if p:
             raise forge_exc.ProjectConflict('%s already exists in nbhd %s' % (shortname, neighborhood._id))
 
-    def validate_project_shortname(self, shortname, neighborhood):
-        """Return an error message if ``shortname`` is invalid for
-        ``neighborhood``, else return None.
+    def valid_project_shortname(self, shortname, neighborhood):
+        """Determine if the project shortname appears to be valid.
+
+        Returns a pair of values, the first being a bool indicating whether
+        the name appears to be valid, and the second being a message indicating
+        the reason, if any, why the name is invalid.
 
+        NB: Even if a project shortname is valid, it might still not be
+        allowed (it could already be taken, for example).  Use the method
+        ``allowed_project_shortname`` instead to check if the shortname can
+        actually be used.
         """
         if not h.re_project_name.match(shortname):
-            return 'Please use only letters, numbers, and dashes 3-15 characters long.'
+            return (False, 'Please use only letters, numbers, and dashes 3-15 characters long.')
+        return (True, None)
+
+    def allowed_project_shortname(self, shortname, neighborhood):
+        """Determine if a project shortname can be used.
+
+        A shortname can be used if it is valid and is not already taken.
+
+        Returns a pair of values, the first being a bool indicating whether
+        the name can be used, and the second being a message indicating the
+        reason, if any, why the name cannot be used.
+        """
+        valid, reason = self.valid_project_shortname(shortname, neighborhood)
+        if not valid:
+            return (False, reason)
+        if self._name_taken(shortname, neighborhood):
+            return (False, 'This project name is taken.')
+        return (True, None)
 
     def _create_project(self, neighborhood, shortname, project_name, user, user_project, private_project, apps):
         '''

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6fc50ebd/Allura/allura/lib/widgets/forms.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/widgets/forms.py b/Allura/allura/lib/widgets/forms.py
index 2312c71..a5ebe15 100644
--- a/Allura/allura/lib/widgets/forms.py
+++ b/Allura/allura/lib/widgets/forms.py
@@ -47,15 +47,12 @@ class _HTMLExplanation(ew.InputField):
 
 class NeighborhoodProjectShortNameValidator(fev.FancyValidator):
 
-    def _to_python(self, value, state):
+    def to_python(self, value, state):
         value = h.really_unicode(value or '').encode('utf-8').lower()
         neighborhood = M.Neighborhood.query.get(name=state.full_dict['neighborhood'])
         provider = plugin.ProjectRegistrationProvider.get()
-        message = provider.validate_project_shortname(value, neighborhood)
-        if message:
-            raise formencode.Invalid(message, value, state)
-        message = provider.name_taken(value, neighborhood)
-        if message:
+        allowed, message = provider.allowed_project_shortname(value, neighborhood)
+        if not allowed:
             raise formencode.Invalid(message, value, state)
         return value
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6fc50ebd/Allura/allura/tests/functional/test_neighborhood.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_neighborhood.py b/Allura/allura/tests/functional/test_neighborhood.py
index fd6c3e4..f63d597 100644
--- a/Allura/allura/tests/functional/test_neighborhood.py
+++ b/Allura/allura/tests/functional/test_neighborhood.py
@@ -449,7 +449,7 @@ class TestNeighborhood(TestController):
                           params=dict(project_unixname='', project_name='Nothing', project_description='', neighborhood='Adobe'),
                           antispam=True,
                           extra_environ=dict(username='root'))
-        assert r.html.find('div', {'class':'error'}).string == 'Please enter a value'
+        assert r.html.find('div', {'class':'error'}).string == 'Please use only letters, numbers, and dashes 3-15 characters long.'
         r = self.app.post('/adobe/register',
                           params=dict(project_unixname='mymoz', project_name='My Moz', project_description='', neighborhood='Adobe'),
                           antispam=True,
@@ -742,12 +742,12 @@ class TestNeighborhood(TestController):
 
     def test_name_check(self):
         for name in ('My+Moz', 'Te%st!', 'ab', 'a' * 16):
-            r = self.app.get('/p/check_names?unix_name=%s' % name)
-            assert r.json['unixname_message'] == 'Please use only letters, numbers, and dashes 3-15 characters long.'
-        r = self.app.get('/p/check_names?unix_name=mymoz')
-        assert_equal(r.json['unixname_message'], False)
-        r = self.app.get('/p/check_names?unix_name=test')
-        assert r.json['unixname_message'] == 'This project name is taken.'
+            r = self.app.get('/p/check_names?neighborhood=Projects&project_unixname=%s' % name)
+            assert_equal(r.json, {'project_unixname': 'Please use only letters, numbers, and dashes 3-15 characters long.'})
+        r = self.app.get('/p/check_names?neighborhood=Projects&project_unixname=mymoz')
+        assert_equal(r.json, {})
+        r = self.app.get('/p/check_names?neighborhood=Projects&project_unixname=test')
+        assert_equal(r.json, {'project_unixname': 'This project name is taken.'})
 
     @td.with_tool('test/sub1', 'Wiki', 'wiki')
     def test_neighborhood_project(self):