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/17 23:17:16 UTC

[1/9] git commit: [#6355] Handle dots in repo names

Updated Branches:
  refs/heads/cj/6456 c82d4fac9 -> cec20b962 (forced update)


[#6355] Handle dots in repo names

Signed-off-by: Tim Van Steenburgh <tv...@gmail.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/dbfa5afd
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/dbfa5afd
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/dbfa5afd

Branch: refs/heads/cj/6456
Commit: dbfa5afd2849f9d33901aa4ac170bb5b9d8945f5
Parents: d2a60bb
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Tue Jul 2 14:33:11 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Mon Jul 15 21:03:18 2013 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/auth.py               | 7 ++++---
 ForgeGit/forgegit/tests/functional/test_auth.py | 7 +++++++
 2 files changed, 11 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/dbfa5afd/Allura/allura/controllers/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/auth.py b/Allura/allura/controllers/auth.py
index 5b3acf3..4e197e6 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -309,12 +309,13 @@ class AuthController(BaseController):
                      project_path, repo_path)
             response.status = 404
             return dict(disallow, error='unknown project')
-        mount_point = os.path.splitext(rest[0])[0]
         c.project = project
-        c.app = project.app_instance(mount_point)
+        c.app = project.app_instance(rest[0])
+        if not c.app:
+            c.app = project.app_instance(rest[0])[0]
         if c.app is None:
             log.info("Can't find repo at %s on repo_path %s",
-                     mount_point, repo_path)
+                     rest[0], repo_path)
             return disallow
         return dict(allow_read=has_access(c.app, 'read')(user=user),
                     allow_write=has_access(c.app, 'write')(user=user),

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/dbfa5afd/ForgeGit/forgegit/tests/functional/test_auth.py
----------------------------------------------------------------------
diff --git a/ForgeGit/forgegit/tests/functional/test_auth.py b/ForgeGit/forgegit/tests/functional/test_auth.py
index fcee919..4a16aab 100644
--- a/ForgeGit/forgegit/tests/functional/test_auth.py
+++ b/ForgeGit/forgegit/tests/functional/test_auth.py
@@ -21,8 +21,10 @@ import json
 from datadiff.tools import assert_equal
 
 from allura.tests import TestController
+from allura.tests.decorators import with_tool
 from forgegit.tests import with_git
 
+
 class TestGitUserPermissions(TestController):
     allow = dict(allow_read=True, allow_write=True, allow_create=True)
     read = dict(allow_read=True, allow_write=False, allow_create=False)
@@ -67,6 +69,11 @@ class TestGitUserPermissions(TestController):
             username='test-usera',
             status=404)
 
+    @with_tool('test', 'Git', 'src.c++.git', 'Git', type='git')
+    def test_dot_and_plus(self):
+        r = self._check_repo('/git/test.p/src.c++.git')
+        assert r == self.allow, r
+
     def _check_repo(self, path, username='test-admin', **kw):
         url = '/auth/repo_permissions'
         r = self.app.get(url, params=dict(


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

Posted by jo...@apache.org.
[#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/c78912c4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/c78912c4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/c78912c4

Branch: refs/heads/cj/6456
Commit: c78912c4692def26a65263e762f33a61b0173c2a
Parents: 7efec56
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Mon Jul 8 18:57:19 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Tue Jul 16 20:15:14 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 +++----
 Allura/allura/tests/test_plugin.py              | 30 ++++++++++++--
 5 files changed, 70 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c78912c4/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/c78912c4/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/c78912c4/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/c78912c4/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):

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c78912c4/Allura/allura/tests/test_plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_plugin.py b/Allura/allura/tests/test_plugin.py
index aa2aaeb..712fe52 100644
--- a/Allura/allura/tests/test_plugin.py
+++ b/Allura/allura/tests/test_plugin.py
@@ -46,10 +46,32 @@ class TestProjectRegistrationProvider(object):
         assert_equals(f('A More Than Fifteen Character Name', Mock()),
                 'amorethanfifteencharactername')
 
-    def test_validate_project_shortname(self):
-        f = self.provider.validate_project_shortname
+    def test_valid_project_shortname(self):
+        f = self.provider.valid_project_shortname
         p = Mock()
-        assert_equals(f('thisislegit', p), None)
-        assert_equals(f('this is invalid and too long', p),
+        valid = (True, None)
+        invalid = (False,
                 'Please use only letters, numbers, and dashes '
                 '3-15 characters long.')
+        assert_equals(f('thisislegit', p), valid)
+        assert_equals(f('not valid', p), invalid)
+        assert_equals(f('this-is-valid-but-too-long', p), invalid)
+        assert_equals(f('this is invalid and too long', p), invalid)
+
+    def test_allowed_project_shortname(self):
+        allowed = valid = (True, None)
+        invalid = (False, 'invalid')
+        taken = (False, 'This project name is taken.')
+        cases = [
+                (valid, False, allowed),
+                (invalid, False, invalid),
+                (valid, True, taken),
+            ]
+        p = Mock()
+        vps = self.provider.valid_project_shortname = Mock()
+        nt = self.provider._name_taken = Mock()
+        f = self.provider.allowed_project_shortname
+        for vps_v, nt_v, result in cases:
+            vps.return_value = vps_v
+            nt.return_value = nt_v
+            assert_equals(f('project', p), result)


[3/9] git commit: [#6290] Ensure last_updated is properly set for trove updates

Posted by jo...@apache.org.
[#6290] Ensure last_updated is properly set for trove updates


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

Branch: refs/heads/cj/6456
Commit: 8067670843bc36cb25a11673e07684b2c51074d9
Parents: 6d18b9f
Author: Wayne Witzel III <ww...@slashdotmedia.com>
Authored: Tue Jul 16 01:33:29 2013 +0000
Committer: Wayne Witzel III <ww...@slashdotmedia.com>
Committed: Tue Jul 16 01:35:56 2013 +0000

----------------------------------------------------------------------
 Allura/allura/ext/admin/admin_main.py | 2 ++
 1 file changed, 2 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/80676708/Allura/allura/ext/admin/admin_main.py
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/admin/admin_main.py b/Allura/allura/ext/admin/admin_main.py
index 7b188c9..1083d86 100644
--- a/Allura/allura/ext/admin/admin_main.py
+++ b/Allura/allura/ext/admin/admin_main.py
@@ -408,6 +408,7 @@ class ProjectAdminController(BaseController):
                 current_troves.append(trove_obj._id)
                 M.AuditLog.log('add trove %s: %s', type, trove_obj.fullpath)
                 ThreadLocalORMSession.flush_all()  # just in case the event handling is super fast
+                c.project.last_updated = datetime.utcnow()
                 g.post_event('project_updated')
             else:
                 error_msg = 'This category has already been assigned to the project.'
@@ -439,6 +440,7 @@ class ProjectAdminController(BaseController):
             M.AuditLog.log('remove trove %s: %s', type, trove_obj.fullpath)
             current_troves.remove(trove_obj._id)
             ThreadLocalORMSession.flush_all()  # just in case the event handling is super fast
+            c.project.last_updated = datetime.utcnow()
             g.post_event('project_updated')
         redirect('trove')
 


[2/9] git commit: [#6355] Try repo path with extension stripped off

Posted by jo...@apache.org.
[#6355] Try repo path with extension stripped off

Signed-off-by: Tim Van Steenburgh <tv...@gmail.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/6d18b9ff
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/6d18b9ff
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/6d18b9ff

Branch: refs/heads/cj/6456
Commit: 6d18b9ffe788b2feaddd7e1dee79c6903a03807b
Parents: dbfa5af
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Mon Jul 15 21:55:24 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Mon Jul 15 21:55:24 2013 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/auth.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6d18b9ff/Allura/allura/controllers/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/auth.py b/Allura/allura/controllers/auth.py
index 4e197e6..4c1ee37 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -312,7 +312,7 @@ class AuthController(BaseController):
         c.project = project
         c.app = project.app_instance(rest[0])
         if not c.app:
-            c.app = project.app_instance(rest[0])[0]
+            c.app = project.app_instance(os.path.splitext(rest[0])[0])
         if c.app is None:
             log.info("Can't find repo at %s on repo_path %s",
                      rest[0], repo_path)


[5/9] git commit: [#4656] Refactor project name validation

Posted by jo...@apache.org.
[#4656] Refactor project name validation

Signed-off-by: Tim Van Steenburgh <tv...@gmail.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/c3b47b75
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/c3b47b75
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/c3b47b75

Branch: refs/heads/cj/6456
Commit: c3b47b75d1588c6c6f6b4ee2a22f3ceee469fbc6
Parents: 8067670
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Tue Jul 2 19:56:40 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Tue Jul 16 20:15:14 2013 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/project.py | 16 ++++++------
 Allura/allura/lib/plugin.py          | 41 ++++++++++++++++++++++++-------
 2 files changed, 41 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c3b47b75/Allura/allura/controllers/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/project.py b/Allura/allura/controllers/project.py
index bff0399..e5edd80 100644
--- a/Allura/allura/controllers/project.py
+++ b/Allura/allura/controllers/project.py
@@ -175,21 +175,23 @@ class NeighborhoodController(object):
 
     @expose('json:')
     def suggest_name(self, project_name=''):
-        result = dict()
-        result['suggested_name'] = re.sub("[^A-Za-z0-9]", "", project_name).lower()[:15]
-        return result
+        provider = plugin.ProjectRegistrationProvider.get()
+        return dict(suggested_name=provider.suggest_name(project_name,
+            self.neighborhood))
 
     @expose('json:')
     def check_names(self, project_name='', unix_name=''):
+        provider = plugin.ProjectRegistrationProvider.get()
         result = dict()
         try:
             W.add_project.fields['project_name'].validate(project_name, '')
         except Invalid as e:
             result['name_message'] = str(e)
-        if not h.re_project_name.match(unix_name) or not (3 <= len(unix_name) <= 15):
-            result['unixname_message'] = 'Please use only letters, numbers, and dashes 3-15 characters long.'
-        else:
-            result['unixname_message'] = plugin.ProjectRegistrationProvider.get().name_taken(unix_name, self.neighborhood)
+
+        unixname_invalid_err = provider.validate_project_shortname(unix_name,
+                self.neighborhood)
+        result['unixname_message'] = (unixname_invalid_err or
+                provider.name_taken(unix_name, self.neighborhood))
         return result
 
     @h.vardec

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c3b47b75/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 855e71c..c0319f7 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -365,6 +365,10 @@ class ProjectRegistrationProvider(object):
         return app_globals.Globals().entry_points['registration'][method]()
 
     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:
@@ -375,18 +379,28 @@ class ProjectRegistrationProvider(object):
         return False
 
     def extra_name_checks(self):
-        '''This should be a list or iterator containing tuples.
-        The first tiem in the tuple should be an error message and the
-        second should be a regex. If the user attempts to register a
-        project with a name that matches the regex, the field will
-        be marked invalid with the message displayed to the user.
-        '''
+        """Return an iterable of ``(error_message, regex)`` tuples.
+
+        If user attempts to register a project with a name that matches
+        ``regex``, the field will be marked invalid, and ``error_message``
+        displayed to the user.
+
+        """
         return []
 
+    def suggest_name(self, project_name, neighborhood):
+        """Return a suggested project shortname for the full ``project_name``.
+
+        Example: "My Great Project" -> "mygreatproject"
+
+        """
+        return re.sub("[^A-Za-z0-9]", "", project_name).lower()
+
     def rate_limit(self, user, neighborhood):
-        '''Check the various config-defined project registration rate
+        """Check the various config-defined project registration rate
         limits, and if any are exceeded, raise ProjectRatelimitError.
-        '''
+
+        """
         if security.has_access(neighborhood, 'admin', user=user)():
             return
         # have to have the replace because, despite being UTC,
@@ -468,13 +482,22 @@ class ProjectRegistrationProvider(object):
             check_shortname = shortname.replace('u/', '', 1)
         else:
             check_shortname = shortname
-        if not h.re_project_name.match(check_shortname):
+        err = self.validate_project_shortname(check_shortname, neighborhood)
+        if err:
             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.
+
+        """
+        if not h.re_project_name.match(shortname):
+            return 'Please use only letters, numbers, and dashes 3-15 characters long.'
+
     def _create_project(self, neighborhood, shortname, project_name, user, user_project, private_project, apps):
         '''
         Actually create the project, no validation.  This should not be called directly


[9/9] git commit: [#6456] Added importer framework base

Posted by jo...@apache.org.
[#6456] Added importer framework base

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/cec20b96
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/cec20b96
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/cec20b96

Branch: refs/heads/cj/6456
Commit: cec20b9620775b03faca5feb9adf2488ae2bb295
Parents: 099c565
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Tue Jul 16 19:23:08 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Wed Jul 17 21:16:41 2013 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/project.py            |  4 +-
 Allura/allura/nf/allura/css/site_style.css      | 66 +++++++++++++++
 ForgeImporters/forgeimporters/__init__.py       |  0
 ForgeImporters/forgeimporters/base.py           | 85 ++++++++++++++++++++
 .../forgeimporters/templates/project_base.html  | 50 ++++++++++++
 ForgeImporters/forgeimporters/tests/__init__.py |  0
 .../forgeimporters/tests/test_base.py           | 65 +++++++++++++++
 ForgeImporters/setup.py                         | 39 +++++++++
 ForgeImporters/test.ini                         | 70 ++++++++++++++++
 9 files changed, 378 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec20b96/Allura/allura/controllers/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/project.py b/Allura/allura/controllers/project.py
index 3cf4112..24bba79 100644
--- a/Allura/allura/controllers/project.py
+++ b/Allura/allura/controllers/project.py
@@ -23,7 +23,7 @@ from itertools import chain, islice
 
 from bson import ObjectId
 from tg import expose, flash, redirect, validate, request, response, config
-from tg.decorators import with_trailing_slash, without_trailing_slash
+from tg.decorators import with_trailing_slash, without_trailing_slash, override_template
 from pylons import tmpl_context as c, app_globals as g
 from paste.deploy.converters import asbool
 from webob import exc
@@ -47,6 +47,7 @@ from allura.lib.widgets import forms as ff
 from allura.lib.widgets import form_fields as ffw
 from allura.lib.widgets import project_list as plw
 from allura.lib import plugin, exceptions
+from forgeimporters.base import ProjectImporterDispatcher
 from .auth import AuthController
 from .search import SearchController, ProjectBrowseController
 from .static import NewForgeController
@@ -73,6 +74,7 @@ class NeighborhoodController(object):
         self.browse = NeighborhoodProjectBrowseController(neighborhood=self.neighborhood)
         self._admin = NeighborhoodAdminController(self.neighborhood)
         self._moderate = NeighborhoodModerateController(self.neighborhood)
+        self.import_project = ProjectImporterDispatcher()
 
     def _check_security(self):
         require_access(self.neighborhood, 'read')

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec20b96/Allura/allura/nf/allura/css/site_style.css
----------------------------------------------------------------------
diff --git a/Allura/allura/nf/allura/css/site_style.css b/Allura/allura/nf/allura/css/site_style.css
index 1322fee..0b4eb92 100644
--- a/Allura/allura/nf/allura/css/site_style.css
+++ b/Allura/allura/nf/allura/css/site_style.css
@@ -3041,3 +3041,69 @@ ul.dropdown ul li a:hover {
     text-align: left;
     margin-right: 0;
 }
+#project-import-form {
+    margin-left: 5px;
+}
+#project-import-form fieldset {
+    margin-top: 10px;
+}
+#project-import-form label {
+    display: block;
+}
+#project-import-form #project-fields label {
+    text-align: right;
+    font-size: 18px;
+    font-weight: 300;
+    line-height: 28px;
+}
+#project-import-form .error {
+    background: transparent;
+    color: red;
+    border: 0;
+}
+#project-import-form .tool {
+    float: left;
+    position: relative;
+    padding: 10px 20px 10px 70px;
+    -moz-border-radius: 4px;
+    -webkit-border-radius: 4px;
+    -o-border-radius: 4px;
+    -ms-border-radius: 4px;
+    -khtml-border-radius: 4px;
+    border-radius: 4px;
+    border: 1px solid #aaa;
+    width: 360px;
+    margin: 5px;
+    background-color: whiteSmoke;
+    height: 74px;
+}
+#project-import-form .tool img {
+    left: 10px;
+    position: absolute;
+    top: 26px;
+}
+#project-import-form .tool label {
+    line-height: 24px;
+    font-size: 18px;
+    font-weight: 600;
+}
+#project-import-form input[type="submit"] {
+    margin-top: 30px;
+    margin-left: 5px;
+    float: none;
+    display: inline-block;
+    position: relative;
+    top: -1em;
+    font-size: 18px;
+    font-weight: 600;
+    text-shadow: none;
+    color: white !important;
+    padding: 1em 2em 1em 2em;
+    text-decoration: none;
+    -webkit-border-radius: 5px;
+    -moz-border-radius: 5px;
+    background: rgb(0,0,0);
+    background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, to(rgb(0,0,0)), from(rgb(90,90,90)));
+    background-image: -moz-linear-gradient(100% 100% 90deg, rgb(0,0,0), rgb(90,90,90) 100%);
+    border: 1px solid black;
+}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec20b96/ForgeImporters/forgeimporters/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/__init__.py b/ForgeImporters/forgeimporters/__init__.py
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec20b96/ForgeImporters/forgeimporters/base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/base.py b/ForgeImporters/forgeimporters/base.py
new file mode 100644
index 0000000..9c5a195
--- /dev/null
+++ b/ForgeImporters/forgeimporters/base.py
@@ -0,0 +1,85 @@
+#       Licensed to the Apache Software Foundation (ASF) under one
+#       or more contributor license agreements.  See the NOTICE file
+#       distributed with this work for additional information
+#       regarding copyright ownership.  The ASF licenses this file
+#       to you under the Apache License, Version 2.0 (the
+#       "License"); you may not use this file except in compliance
+#       with the License.  You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#       Unless required by applicable law or agreed to in writing,
+#       software distributed under the License is distributed on an
+#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#       KIND, either express or implied.  See the License for the
+#       specific language governing permissions and limitations
+#       under the License.
+
+from pkg_resources import iter_entry_points
+
+from tg import expose
+
+from ming.utils import LazyProperty
+from allura.controllers import BaseController
+
+
+class ProjectImporterDispatcher(BaseController):
+    @expose()
+    def _lookup(self, source, *rest):
+        for ep in iter_entry_points('allura.project_importers', source):
+            return ep.load()(), rest
+
+class ProjectImporter(BaseController):
+    source = None
+
+    @LazyProperty
+    def tool_importers(self):
+        tools = []
+        for ep in iter_entry_points('allura.importers'):
+            ep = ep.load()
+            if ep.source == self.source:
+                tools.append(ep())
+        return tools
+
+    def index(self, **kw):
+        """
+        Override and expose this view to present the project import form.
+
+        The template used by this view should extend the base template in:
+
+            jinja:forgeimporters:templates/project_base.html
+
+        This will list the available tool importers.  Other project fields
+        (e.g., project_name) should go in the project_fields block.
+        """
+        raise NotImplemented
+
+    def process(self, tools=None, **kw):
+        """
+        Override and expose this to handle a project import.
+
+        This should at a minimum create the stub project with the appropriate
+        tools installed and redirect to the new project, presumably with a
+        message indicating that some data will not be available immediately.
+        """
+        raise NotImplemented
+
+class ToolImporter(object):
+    target_app = None
+    source = None
+    controller = None
+
+    def import_tool(self, project, mount_point):
+        """
+        Override this method to perform the tool import.
+        """
+        raise NotImplementedError
+
+    @property
+    def tool_label(self):
+        return getattr(self.target_app, 'tool_label', None)
+
+    @property
+    def tool_description(self):
+        return getattr(self.target_app, 'tool_description', None)
+

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec20b96/ForgeImporters/forgeimporters/templates/project_base.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/templates/project_base.html b/ForgeImporters/forgeimporters/templates/project_base.html
new file mode 100644
index 0000000..4413b48
--- /dev/null
+++ b/ForgeImporters/forgeimporters/templates/project_base.html
@@ -0,0 +1,50 @@
+{#-
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+-#}
+{% set hide_left_bar = True %}
+{% extends g.theme.master %}
+{% block title %}{{importer.source}} Project Importer{% endblock %}
+
+{% block header %}{{importer.source}} Project Importer{% endblock %}
+
+{% block content %}
+
+<form id="project-import-form" method="POST" action="process">
+    <input type="hidden" name="source" value="{{request.params.source}}" />
+
+    <fieldset id="project-fields">
+        {% block project_fields %}{% endblock %}
+    </fieldset>
+
+    <fieldset id="tool-fields">
+        {% for tool_importer in importer.tool_importers %}
+        <div class="tool">
+            <img src="{{ g.theme.app_icon_url(tool_importer.target_app, 48) }}" alt="{{ tool_importer.tool_label }} icon">
+            <label>
+                <input name="tools" value="{{tool_importer.tool_label}}" type="checkbox" checked="checked"/>
+                {{tool_importer.tool_label}}
+            </label>
+            {{tool_importer.tool_description}}
+        </div>
+        {% endfor %}
+    </fieldset>
+
+    <input type="submit" value="Import"/>
+</form>
+
+{% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec20b96/ForgeImporters/forgeimporters/tests/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/__init__.py b/ForgeImporters/forgeimporters/tests/__init__.py
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec20b96/ForgeImporters/forgeimporters/tests/test_base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/test_base.py b/ForgeImporters/forgeimporters/tests/test_base.py
new file mode 100644
index 0000000..3a7df56
--- /dev/null
+++ b/ForgeImporters/forgeimporters/tests/test_base.py
@@ -0,0 +1,65 @@
+#       Licensed to the Apache Software Foundation (ASF) under one
+#       or more contributor license agreements.  See the NOTICE file
+#       distributed with this work for additional information
+#       regarding copyright ownership.  The ASF licenses this file
+#       to you under the Apache License, Version 2.0 (the
+#       "License"); you may not use this file except in compliance
+#       with the License.  You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#       Unless required by applicable law or agreed to in writing,
+#       software distributed under the License is distributed on an
+#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#       KIND, either express or implied.  See the License for the
+#       specific language governing permissions and limitations
+#       under the License.
+
+from unittest import TestCase
+
+import mock
+
+from .. import base
+
+
+def ep(ep_res):
+    mep = mock.Mock(name='mock_ep')
+    mep.load.return_value.source = ep_res
+    mep.lv = mep.load.return_value.return_value
+    return mep
+
+class TestProjectImporterDispatcher(TestCase):
+    @mock.patch('forgeimporters.base.iter_entry_points')
+    def test_lookup(self, iep):
+        eps = iep.return_value = [ep('first'), ep('second')]
+        result = base.ProjectImporterDispatcher()._lookup('source', 'rest1', 'rest2')
+        self.assertEqual(result, (eps[0].lv, ('rest1', 'rest2')))
+        iep.assert_called_once_with('allura.project_importers', 'source')
+
+
+class TestProjectImporter(TestCase):
+    @mock.patch('forgeimporters.base.iter_entry_points')
+    def test_tool_importers(self, iep):
+        eps = iep.return_value = [ep('foo'), ep('bar'), ep('foo')]
+        pi = base.ProjectImporter()
+        pi.source = 'foo'
+        self.assertEqual(pi.tool_importers, [eps[0].lv, eps[2].lv])
+        iep.assert_called_once_with('allura.importers')
+
+
+class TestImporter(TestCase):
+    class TI1(base.ToolImporter):
+        target_app = mock.Mock(tool_label='foo', tool_description='foo_desc')
+
+    class TI2(base.ToolImporter):
+        target_app = mock.Mock(tool_label='foo', tool_description='foo_desc')
+        tool_label = 'bar'
+        tool_description = 'bar_desc'
+
+    def test_tool_label(self):
+        self.assertEqual(self.TI1().tool_label, 'foo')
+        self.assertEqual(self.TI2().tool_label, 'bar')
+
+    def test_tool_description(self):
+        self.assertEqual(self.TI1().tool_description, 'foo_desc')
+        self.assertEqual(self.TI2().tool_description, 'bar_desc')

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec20b96/ForgeImporters/setup.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/setup.py b/ForgeImporters/setup.py
new file mode 100644
index 0000000..5e45638
--- /dev/null
+++ b/ForgeImporters/setup.py
@@ -0,0 +1,39 @@
+#       Licensed to the Apache Software Foundation (ASF) under one
+#       or more contributor license agreements.  See the NOTICE file
+#       distributed with this work for additional information
+#       regarding copyright ownership.  The ASF licenses this file
+#       to you under the Apache License, Version 2.0 (the
+#       "License"); you may not use this file except in compliance
+#       with the License.  You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#       Unless required by applicable law or agreed to in writing,
+#       software distributed under the License is distributed on an
+#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#       KIND, either express or implied.  See the License for the
+#       specific language governing permissions and limitations
+#       under the License.
+
+from setuptools import setup, find_packages
+
+
+setup(name='ForgeImporters',
+      description="",
+      long_description="",
+      classifiers=[],
+      keywords='',
+      author='',
+      author_email='',
+      url='',
+      license='',
+      packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
+      include_package_data=True,
+      zip_safe=False,
+      install_requires=['Allura', ],
+      entry_points="""
+      # -*- Entry points: -*-
+      [allura.project_importers]
+
+      [allura.importers]
+      """,)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cec20b96/ForgeImporters/test.ini
----------------------------------------------------------------------
diff --git a/ForgeImporters/test.ini b/ForgeImporters/test.ini
new file mode 100644
index 0000000..019c262
--- /dev/null
+++ b/ForgeImporters/test.ini
@@ -0,0 +1,70 @@
+#       Licensed to the Apache Software Foundation (ASF) under one
+#       or more contributor license agreements.  See the NOTICE file
+#       distributed with this work for additional information
+#       regarding copyright ownership.  The ASF licenses this file
+#       to you under the Apache License, Version 2.0 (the
+#       "License"); you may not use this file except in compliance
+#       with the License.  You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#       Unless required by applicable law or agreed to in writing,
+#       software distributed under the License is distributed on an
+#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#       KIND, either express or implied.  See the License for the
+#       specific language governing permissions and limitations
+#       under the License.
+#
+# allura - TurboGears 2 testing environment configuration
+#
+# The %(here)s variable will be replaced with the parent directory of this file
+#
+[DEFAULT]
+debug = true
+
+[server:main]
+use = egg:Paste#http
+host = 0.0.0.0
+port = 5000
+
+[app:main]
+use = config:../Allura/test.ini
+
+[app:main_without_authn]
+use = config:../Allura/test.ini#main_without_authn
+
+[app:main_with_amqp]
+use = config:../Allura/test.ini#main_with_amqp
+
+[loggers]
+keys = root, allura, tool
+
+[handlers]
+keys = test
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = test
+
+[logger_allura]
+level = DEBUG
+handlers =
+qualname = allura
+
+[logger_tool]
+level = DEBUG
+handlers =
+qualname = forgeshorturl
+
+[handler_test]
+class = FileHandler
+args = ('test.log',)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
+datefmt = %H:%M:%S


[6/9] git commit: [#4656] Add tests for new provider methods

Posted by jo...@apache.org.
[#4656] Add tests for new provider methods

Signed-off-by: Tim Van Steenburgh <tv...@gmail.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/dce4fe8c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/dce4fe8c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/dce4fe8c

Branch: refs/heads/cj/6456
Commit: dce4fe8c3c05109f9d9e8de7e2495ebf13b673ac
Parents: c3b47b7
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Tue Jul 2 21:36:57 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Tue Jul 16 20:15:14 2013 +0000

----------------------------------------------------------------------
 Allura/allura/tests/test_plugin.py | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/dce4fe8c/Allura/allura/tests/test_plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_plugin.py b/Allura/allura/tests/test_plugin.py
index 6e1a07a..aa2aaeb 100644
--- a/Allura/allura/tests/test_plugin.py
+++ b/Allura/allura/tests/test_plugin.py
@@ -16,7 +16,7 @@
 #       under the License.
 
 from nose.tools import assert_equals
-from mock import MagicMock, patch
+from mock import Mock, MagicMock, patch
 
 from allura import model as M
 from allura.lib.utils import TruthyCallable
@@ -25,16 +25,31 @@ from allura.lib.plugin import ProjectRegistrationProvider
 
 class TestProjectRegistrationProvider(object):
 
+    def setUp(self):
+        self.provider = ProjectRegistrationProvider()
+
     @patch('allura.lib.security.has_access')
     def test_validate_project_15char_user(self, has_access):
         has_access.return_value = TruthyCallable(lambda: True)
-        provider = ProjectRegistrationProvider()
         nbhd = M.Neighborhood()
-        provider.validate_project(
+        self.provider.validate_project(
             neighborhood=nbhd,
             shortname='u/' + ('a' * 15),
             project_name='15 char username',
             user=MagicMock(),
             user_project=True,
             private_project=False,
-        )
\ No newline at end of file
+        )
+
+    def test_suggest_name(self):
+        f = self.provider.suggest_name
+        assert_equals(f('A More Than Fifteen Character Name', Mock()),
+                'amorethanfifteencharactername')
+
+    def test_validate_project_shortname(self):
+        f = self.provider.validate_project_shortname
+        p = Mock()
+        assert_equals(f('thisislegit', p), None)
+        assert_equals(f('this is invalid and too long', p),
+                'Please use only letters, numbers, and dashes '
+                '3-15 characters long.')


[8/9] git commit: [#6469] Bump EW for security fix: escaped textarea content

Posted by jo...@apache.org.
[#6469] Bump EW for security fix: escaped textarea content

Signed-off-by: Tim Van Steenburgh <tv...@gmail.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/099c5659
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/099c5659
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/099c5659

Branch: refs/heads/cj/6456
Commit: 099c5659d3a17ef84da5ca088ea1cebc7de37001
Parents: c78912c
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Tue Jul 16 22:07:12 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Tue Jul 16 22:07:12 2013 +0000

----------------------------------------------------------------------
 requirements-common.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/099c5659/requirements-common.txt
----------------------------------------------------------------------
diff --git a/requirements-common.txt b/requirements-common.txt
index d496708..81a470b 100644
--- a/requirements-common.txt
+++ b/requirements-common.txt
@@ -10,7 +10,7 @@ Creoleparser==0.7.3
 decorator==3.3.2
 # dep of pypeline
 docutils==0.8.1
-EasyWidgets==0.2dev-20130603
+EasyWidgets==0.2dev-20130716
 faulthandler==2.1
 feedparser==5.0.1
 FormEncode==1.2.4


[7/9] git commit: [#4656] Refactored project name validation

Posted by jo...@apache.org.
[#4656] Refactored project name validation

AJAX validation and validation on submit were not using the same
validation checks.  Refactored the validation code so that both use
the same checks and consolidated redundant API methods related to those
checks.

The "extra_name_checks" method is no longer used, and those checks
should be folded into the new, more general "validate_project_shortname"
method.

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/7efec56e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/7efec56e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/7efec56e

Branch: refs/heads/cj/6456
Commit: 7efec56ef005433e79fdb377ef6c0a8da5f28ecd
Parents: dce4fe8
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Wed Jul 3 20:05:19 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Tue Jul 16 20:15:14 2013 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/project.py | 19 +++++--------------
 Allura/allura/lib/plugin.py          | 13 -------------
 Allura/allura/lib/widgets/forms.py   | 30 +++++++++++++++---------------
 3 files changed, 20 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7efec56e/Allura/allura/controllers/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/project.py b/Allura/allura/controllers/project.py
index e5edd80..36c4667 100644
--- a/Allura/allura/controllers/project.py
+++ b/Allura/allura/controllers/project.py
@@ -80,7 +80,8 @@ class NeighborhoodController(object):
     @expose()
     def _lookup(self, pname, *remainder):
         pname = unquote(pname)
-        if not h.re_project_name.match(pname):
+        provider = plugin.ProjectRegistrationProvider.get()
+        if provider.validate_project_shortname(pname, self.neighborhood):
             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/':
@@ -180,19 +181,9 @@ class NeighborhoodController(object):
             self.neighborhood))
 
     @expose('json:')
-    def check_names(self, project_name='', unix_name=''):
-        provider = plugin.ProjectRegistrationProvider.get()
-        result = dict()
-        try:
-            W.add_project.fields['project_name'].validate(project_name, '')
-        except Invalid as e:
-            result['name_message'] = str(e)
-
-        unixname_invalid_err = provider.validate_project_shortname(unix_name,
-                self.neighborhood)
-        result['unixname_message'] = (unixname_invalid_err or
-                provider.name_taken(unix_name, self.neighborhood))
-        return result
+    @validate(W.add_project)
+    def check_names(self, **raw_data):
+        return c.form_errors
 
     @h.vardec
     @expose()

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7efec56e/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index c0319f7..111aa77 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -373,21 +373,8 @@ class ProjectRegistrationProvider(object):
         p = M.Project.query.get(shortname=project_name, neighborhood_id=neighborhood._id)
         if p:
             return 'This project name is taken.'
-        for check in self.extra_name_checks():
-            if re.match(str(check[1]),project_name) is not None:
-                return check[0]
         return False
 
-    def extra_name_checks(self):
-        """Return an iterable of ``(error_message, regex)`` tuples.
-
-        If user attempts to register a project with a name that matches
-        ``regex``, the field will be marked invalid, and ``error_message``
-        displayed to the user.
-
-        """
-        return []
-
     def suggest_name(self, project_name, neighborhood):
         """Return a suggested project shortname for the full ``project_name``.
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7efec56e/Allura/allura/lib/widgets/forms.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/widgets/forms.py b/Allura/allura/lib/widgets/forms.py
index 9501b70..2312c71 100644
--- a/Allura/allura/lib/widgets/forms.py
+++ b/Allura/allura/lib/widgets/forms.py
@@ -45,12 +45,16 @@ class _HTMLExplanation(ew.InputField):
         ''',
         'jinja2')
 
-class NeighborhoodProjectTakenValidator(fev.FancyValidator):
+class NeighborhoodProjectShortNameValidator(fev.FancyValidator):
 
     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'])
-        message = plugin.ProjectRegistrationProvider.get().name_taken(value, 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:
             raise formencode.Invalid(message, value, state)
         return value
@@ -779,14 +783,7 @@ class NeighborhoodAddProjectForm(ForgeForm):
                 V.MaxBytesValidator(max=40)))
         project_unixname = ew.InputField(
             label='Short Name', field_type='text',
-            validator=formencode.All(
-                fev.String(not_empty=True),
-                fev.MinLength(3),
-                fev.MaxLength(15),
-                fev.Regex(
-                    r'^[A-z][-A-z0-9]{2,}$',
-                    messages={'invalid':'Please use only letters, numbers, and dashes 3-15 characters long.'}),
-                NeighborhoodProjectTakenValidator()))
+            validator=NeighborhoodProjectShortNameValidator())
         tools = ew.CheckboxSet(name='tools', options=[
             ## Required for Neighborhood functional tests to pass
             ew.Option(label='Wiki', html_value='wiki', selected=True)
@@ -805,12 +802,14 @@ class NeighborhoodAddProjectForm(ForgeForm):
     def resources(self):
         for r in super(NeighborhoodAddProjectForm, self).resources(): yield r
         yield ew.CSSLink('css/add_project.css')
+        neighborhood = g.antispam.enc('neighborhood')
         project_name = g.antispam.enc('project_name')
         project_unixname = g.antispam.enc('project_unixname')
 
         yield ew.JSScript('''
             $(function(){
                 var $scms = $('input[type=checkbox].scm');
+                var $nbhd_input = $('input[name="%(neighborhood)s"]');
                 var $name_input = $('input[name="%(project_name)s"]');
                 var $unixname_input = $('input[name="%(project_unixname)s"]');
                 var $url_fragment = $('#url_fragment');
@@ -864,12 +863,13 @@ class NeighborhoodAddProjectForm(ForgeForm):
                 });
                 var check_names = function() {
                     var data = {
-                        'project_name':$name_input.val(),
-                        'unix_name': $unixname_input.val()
+                        'neighborhood': $nbhd_input.val(),
+                        'project_name': $name_input.val(),
+                        'project_unixname': $unixname_input.val()
                     };
                     $.getJSON('check_names', data, function(result){
-                        handle_error($name_input, result.name_message);
-                        handle_error($unixname_input, result.unixname_message);
+                        handle_error($name_input, result.project_name);
+                        handle_error($unixname_input, result.project_unixname);
                     });
                 };
                 var manual = false;
@@ -897,7 +897,7 @@ class NeighborhoodAddProjectForm(ForgeForm):
                     delay(check_names, 500);
                 });
             });
-        ''' % dict(project_name=project_name, project_unixname=project_unixname))
+        ''' % dict(neighborhood=neighborhood, project_name=project_name, project_unixname=project_unixname))
 
 
 class MoveTicketForm(ForgeForm):