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 2014/02/03 23:43:53 UTC

git commit: [#7124] Added URL availability validation for Trac

Updated Branches:
  refs/heads/cj/7124 [created] 83606c46d


[#7124] Added URL availability validation for Trac

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

Branch: refs/heads/cj/7124
Commit: 83606c46d0ed65659ff81d54678b47082fe98980
Parents: bfee3bc
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Mon Feb 3 22:42:13 2014 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Mon Feb 3 22:43:35 2014 +0000

----------------------------------------------------------------------
 ForgeImporters/forgeimporters/trac/__init__.py  | 28 ++++++++++++
 ForgeImporters/forgeimporters/trac/project.py   |  7 ++-
 .../forgeimporters/trac/tests/test_tickets.py   | 46 +++++++++++++++-----
 ForgeImporters/forgeimporters/trac/tickets.py   | 11 ++---
 requirements-sf.txt                             |  2 +-
 5 files changed, 73 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/83606c46/ForgeImporters/forgeimporters/trac/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/trac/__init__.py b/ForgeImporters/forgeimporters/trac/__init__.py
index 144e298..c861469 100644
--- a/ForgeImporters/forgeimporters/trac/__init__.py
+++ b/ForgeImporters/forgeimporters/trac/__init__.py
@@ -14,3 +14,31 @@
 #       KIND, either express or implied.  See the License for the
 #       specific language governing permissions and limitations
 #       under the License.
+
+from formencode import validators as fev
+import requests
+
+
+class TracURLValidator(fev.URL):
+    not_empty = True
+    messages = {
+        'unavailable': 'This project is unavailable for import'
+    }
+
+    def _to_python(self, value, state=None):
+        value = super(TracURLValidator, self)._to_python(value, state)
+        # remove extraneous /wiki/[PageName] from the end of the URL
+        url_parts = value.split('/')
+        try:
+            wiki_in_url = url_parts.index('wiki')
+        except ValueError:
+            wiki_in_url = -1
+        if wiki_in_url >= len(url_parts) - 2:
+            value = '/'.join(url_parts[:wiki_in_url])
+        # normalize trailing slash
+        value = value.rstrip('/') + '/'
+
+        resp = requests.head(value, allow_redirects=True)
+        if resp.status_code != 200:
+            raise fev.Invalid(self.message('unavailable', state), value, state)
+        return value

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/83606c46/ForgeImporters/forgeimporters/trac/project.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/trac/project.py b/ForgeImporters/forgeimporters/trac/project.py
index 1dba980..0f44259 100644
--- a/ForgeImporters/forgeimporters/trac/project.py
+++ b/ForgeImporters/forgeimporters/trac/project.py
@@ -17,22 +17,21 @@
 
 import logging
 
-from formencode import validators as fev
-
 from tg import expose, validate
 from tg.decorators import with_trailing_slash
 
 from allura.lib.decorators import require_post
 from allura.lib.validators import UserMapJsonFile
 
-from .. import base
+from forgeimporters import base
+from forgeimporters.trac import TracURLValidator
 
 
 log = logging.getLogger(__name__)
 
 
 class TracProjectForm(base.ProjectImportForm):
-    trac_url = fev.URL(not_empty=True)
+    trac_url = TracURLValidator()
     user_map = UserMapJsonFile(as_string=True)
 
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/83606c46/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/trac/tests/test_tickets.py b/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
index e9366f2..ce2eccd 100644
--- a/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
+++ b/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
@@ -26,7 +26,7 @@ from IPython.testing.decorators import module_not_available, skipif
 
 from allura.tests import TestController
 from allura.tests.decorators import with_tracker
-from alluratest.controller import TestRestApiBase
+from alluratest.controller import TestRestApiBase, setup_unit_test
 
 from allura import model as M
 from forgetracker import model as TM
@@ -40,6 +40,9 @@ from forgeimporters.trac.tickets import (
 
 class TestTracTicketImporter(TestCase):
 
+    def setUp(self):
+        setup_unit_test()
+
     @patch('forgeimporters.trac.tickets.session')
     @patch('forgeimporters.trac.tickets.g')
     @patch('forgeimporters.trac.tickets.AuditLog')
@@ -69,9 +72,9 @@ class TestTracTicketImporter(TestCase):
             closed_status_names='closed',
             import_id={
                 'source': 'Trac',
-                'trac_url': 'http://example.com/trac/url/',
+                'trac_url': 'http://example.com/trac/url',
             })
-        export.assert_called_once_with('http://example.com/trac/url/')
+        export.assert_called_once_with('http://example.com/trac/url')
         ImportSupport.return_value.perform_import.assert_called_once_with(
             json.dumps(export.return_value),
             json.dumps({
@@ -80,7 +83,7 @@ class TestTracTicketImporter(TestCase):
             }),
         )
         AuditLog.log.assert_called_once_with(
-            'import tool bugs from http://example.com/trac/url/',
+            'import tool bugs from http://example.com/trac/url',
             project=project, user=user, url='foo')
         g.post_event.assert_called_once_with('project_updated')
 
@@ -122,15 +125,18 @@ class TestTracTicketImportController(TestController, TestCase):
         self.assertIsNotNone(r.html.find(attrs=dict(name="mount_point")))
 
     @with_tracker
+    @patch('forgeimporters.trac.requests.head')
     @patch('forgeimporters.base.import_tool')
-    def test_create(self, import_tool):
+    def test_create(self, import_tool, head):
+        head.return_value.status_code = 200
         params = dict(trac_url='http://example.com/trac/url',
                       mount_label='mylabel',
                       mount_point='mymount',
                       )
         r = self.app.post('/p/test/admin/bugs/_importer/create', params,
-                          upload_files=[
-                              ('user_map', 'myfile', '{"orig_user": "new_user"}')],
+                          upload_files=[(
+                              'user_map', 'myfile', '{"orig_user": "new_user"}'
+                          )],
                           status=302)
         self.assertEqual(r.location, 'http://localhost/p/test/admin/')
         self.assertEqual(
@@ -139,12 +145,14 @@ class TestTracTicketImportController(TestController, TestCase):
             u'mylabel', import_tool.post.call_args[1]['mount_label'])
         self.assertEqual('{"orig_user": "new_user"}',
                          import_tool.post.call_args[1]['user_map'])
-        self.assertEqual(u'http://example.com/trac/url',
+        self.assertEqual(u'http://example.com/trac/url/',
                          import_tool.post.call_args[1]['trac_url'])
 
     @with_tracker
+    @patch('forgeimporters.trac.requests.head')
     @patch('forgeimporters.base.import_tool')
-    def test_create_limit(self, import_tool):
+    def test_create_limit(self, import_tool, head):
+        head.return_value.status_code = 200
         project = M.Project.query.get(shortname='test')
         project.set_tool_data('TracTicketImporter', pending=1)
         ThreadLocalORMSession.flush_all()
@@ -153,12 +161,28 @@ class TestTracTicketImportController(TestController, TestCase):
                       mount_point='mymount',
                       )
         r = self.app.post('/p/test/admin/bugs/_importer/create', params,
-                          upload_files=[
-                              ('user_map', 'myfile', '{"orig_user": "new_user"}')],
+                          upload_files=[(
+                              'user_map', 'myfile', '{"orig_user": "new_user"}'
+                          )],
                           status=302).follow()
         self.assertIn('Please wait and try again', r)
         self.assertEqual(import_tool.post.call_count, 0)
 
+    @with_tracker
+    @patch('forgeimporters.trac.requests.head')
+    @patch('forgeimporters.base.import_tool')
+    def test_create_not_found(self, import_tool, head):
+        head.return_value.status_code = 404
+        params = dict(trac_url='http://example.com/trac/url',
+                      mount_label='mylabel',
+                      mount_point='mymount',
+                      )
+        r = self.app.post('/p/test/admin/bugs/_importer/create', params,
+                          upload_files=[(
+                              'user_map', 'myfile', '{"orig_user": "new_user"}'
+                          )])
+        self.assertEqual(import_tool.post.call_count, 0)
+
 
 class TestTracImportSupport(TestCase):
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/83606c46/ForgeImporters/forgeimporters/trac/tickets.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/trac/tickets.py b/ForgeImporters/forgeimporters/trac/tickets.py
index c2c28c1..a8372ed 100644
--- a/ForgeImporters/forgeimporters/trac/tickets.py
+++ b/ForgeImporters/forgeimporters/trac/tickets.py
@@ -48,13 +48,14 @@ from forgeimporters.base import (
     ToolImporter,
     ToolImportForm,
 )
+from forgeimporters.trac import TracURLValidator
 from forgetracker.tracker_main import ForgeTrackerApp
 from forgetracker.import_support import ImportSupport
 from forgetracker import model as TM
 
 
 class TracTicketImportForm(ToolImportForm):
-    trac_url = fev.URL(not_empty=True)
+    trac_url = TracURLValidator()
     user_map = v.UserMapJsonFile(as_string=True)
 
 
@@ -85,11 +86,12 @@ class TracTicketImportController(BaseController):
                 mount_label=mount_label,
                 trac_url=trac_url,
                 user_map=user_map)
-            flash('Ticket import has begun. Your new tracker will be available '
-                  'when the import is complete.')
+            flash('Ticket import has begun. Your new tracker will be '
+                  'available when the import is complete.')
         else:
             flash(
-                'There are too many imports pending at this time.  Please wait and try again.', 'error')
+                'There are too many imports pending at this time.  Please '
+                'wait and try again.', 'error')
         redirect(c.project.url() + 'admin/')
 
 
@@ -105,7 +107,6 @@ class TracTicketImporter(ToolImporter):
         """ Import Trac tickets into a new Allura Tracker tool.
 
         """
-        trac_url = trac_url.rstrip('/') + '/'
         mount_point = mount_point or 'tickets'
         app = project.install_app(
             'Tickets',

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/83606c46/requirements-sf.txt
----------------------------------------------------------------------
diff --git a/requirements-sf.txt b/requirements-sf.txt
index b54c0c0..61c12ac 100644
--- a/requirements-sf.txt
+++ b/requirements-sf.txt
@@ -20,7 +20,7 @@ wsgipreload==1.2
 pyzmq==2.1.7
 html2text==3.200.3dev-20121112
 PyMollom==0.1
-TracWikiImporter==0.3.6
+TracWikiImporter==0.3.7
 MediawikiImporter==0.0.2
 Unidecode==0.04.14