You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by br...@apache.org on 2013/07/23 04:52:44 UTC

[1/9] git commit: [#6456] Changed target_app to allow list and added by_app to ToolImporter

Updated Branches:
  refs/heads/master b2a00e822 -> 5f68604db


[#6456] Changed target_app to allow list and added by_app to ToolImporter

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

Branch: refs/heads/master
Commit: 138f4318526e5d3c6e2387e905793c48eef8b120
Parents: f690652
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Mon Jul 22 21:43:49 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Jul 23 02:45:41 2013 +0000

----------------------------------------------------------------------
 ForgeImporters/forgeimporters/base.py           | 14 +++++-
 .../forgeimporters/tests/test_base.py           | 48 ++++++++++++++++----
 2 files changed, 50 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/138f4318/ForgeImporters/forgeimporters/base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/base.py b/ForgeImporters/forgeimporters/base.py
index 01e614a..6632f37 100644
--- a/ForgeImporters/forgeimporters/base.py
+++ b/ForgeImporters/forgeimporters/base.py
@@ -18,6 +18,7 @@
 from pkg_resources import iter_entry_points
 
 from tg import expose
+from paste.deploy.converters import aslist
 from formencode import validators as fev
 
 from ming.utils import LazyProperty
@@ -77,6 +78,15 @@ class ToolImporter(object):
         for ep in iter_entry_points('allura.importers', name):
             return ep.load()()
 
+    @classmethod
+    def by_app(self, app):
+        importers = {}
+        for ep in iter_entry_points('allura.importers'):
+            importer = ep.load()
+            if app in aslist(importer.target_app):
+                importers[ep.name] = importer()
+        return importers
+
     def import_tool(self, project=None, mount_point=None):
         """
         Override this method to perform the tool import.
@@ -85,11 +95,11 @@ class ToolImporter(object):
 
     @property
     def tool_label(self):
-        return getattr(self.target_app, 'tool_label', None)
+        return getattr(aslist(self.target_app)[0], 'tool_label', None)
 
     @property
     def tool_description(self):
-        return getattr(self.target_app, 'tool_description', None)
+        return getattr(aslist(self.target_app)[0], 'tool_description', None)
 
 
 class ToolsValidator(fev.Set):

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/138f4318/ForgeImporters/forgeimporters/tests/test_base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/test_base.py b/ForgeImporters/forgeimporters/tests/test_base.py
index a6a4d18..64096fd 100644
--- a/ForgeImporters/forgeimporters/tests/test_base.py
+++ b/ForgeImporters/forgeimporters/tests/test_base.py
@@ -23,17 +23,20 @@ import mock
 from .. import base
 
 
-def ep(name, source=None):
-    mep = mock.Mock(name='mock_ep')
+def ep(name, source=None, importer=None, **kw):
+    mep = mock.Mock(name='mock_ep', **kw)
     mep.name = name
-    mep.load.return_value.source = source
-    mep.lv = mep.load.return_value.return_value
-    mep.lv.source = source
+    if importer is not None:
+        mep.load.return_value = importer
+    else:
+        mep.load.return_value.source = source
+        mep.lv = mep.load.return_value.return_value
+        mep.lv.source = source
     return mep
 
 
 class TestProjectImporterDispatcher(TestCase):
-    @mock.patch('forgeimporters.base.iter_entry_points')
+    @mock.patch.object(base, 'iter_entry_points')
     def test_lookup(self, iep):
         eps = iep.return_value = [ep('ep1', 'first'), ep('ep2', 'second')]
         result = base.ProjectImporterDispatcher()._lookup('source', 'rest1', 'rest2')
@@ -42,7 +45,7 @@ class TestProjectImporterDispatcher(TestCase):
 
 
 class TestProjectImporter(TestCase):
-    @mock.patch('forgeimporters.base.iter_entry_points')
+    @mock.patch.object(base, 'iter_entry_points')
     def test_tool_importers(self, iep):
         eps = iep.return_value = [ep('ep1', 'foo'), ep('ep2', 'bar'), ep('ep3', 'foo')]
         pi = base.ProjectImporter()
@@ -51,16 +54,24 @@ class TestProjectImporter(TestCase):
         iep.assert_called_once_with('allura.importers')
 
 
+
+TA1 = mock.Mock(tool_label='foo', tool_description='foo_desc')
+TA2 = mock.Mock(tool_label='qux', tool_description='qux_desc')
+TA3 = mock.Mock(tool_label='baz', tool_description='baz_desc')
+
 class TestToolImporter(TestCase):
     class TI1(base.ToolImporter):
-        target_app = mock.Mock(tool_label='foo', tool_description='foo_desc')
+        target_app = TA1
 
     class TI2(base.ToolImporter):
-        target_app = mock.Mock(tool_label='foo', tool_description='foo_desc')
+        target_app = TA2
         tool_label = 'bar'
         tool_description = 'bar_desc'
 
-    @mock.patch('forgeimporters.base.iter_entry_points')
+    class TI3(base.ToolImporter):
+        target_app = [TA2, TA2]
+
+    @mock.patch.object(base, 'iter_entry_points')
     def test_by_name(self, iep):
         eps = iep.return_value = [ep('my-name', 'my-source')]
         importer = base.ToolImporter.by_name('my-name')
@@ -73,13 +84,30 @@ class TestToolImporter(TestCase):
         iep.assert_called_once_with('allura.importers', 'other-name')
         self.assertEqual(importer, None)
 
+    @mock.patch.object(base, 'iter_entry_points')
+    def test_by_app(self, iep):
+        eps = iep.return_value = [
+                ep('importer1', importer=self.TI1),
+                ep('importer2', importer=self.TI2),
+                ep('importer3', importer=self.TI3),
+            ]
+        importers = base.ToolImporter.by_app(TA2)
+        self.assertEqual(set(importers.keys()), set([
+                'importer2',
+                'importer3',
+            ]))
+        self.assertIsInstance(importers['importer2'], self.TI2)
+        self.assertIsInstance(importers['importer3'], self.TI3)
+
     def test_tool_label(self):
         self.assertEqual(self.TI1().tool_label, 'foo')
         self.assertEqual(self.TI2().tool_label, 'bar')
+        self.assertEqual(self.TI3().tool_label, 'qux')
 
     def test_tool_description(self):
         self.assertEqual(self.TI1().tool_description, 'foo_desc')
         self.assertEqual(self.TI2().tool_description, 'bar_desc')
+        self.assertEqual(self.TI3().tool_description, 'qux_desc')
 
 
 class TestToolsValidator(TestCase):


[4/9] git commit: [#6456] Changed field names for GC project import

Posted by br...@apache.org.
[#6456] Changed field names for GC project import

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

Branch: refs/heads/master
Commit: a5371df3be09ff8bf017057e86570d6ab3a3c1fc
Parents: 7af8206
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Mon Jul 22 18:57:20 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Jul 23 02:45:41 2013 +0000

----------------------------------------------------------------------
 .../forgeimporters/google/__init__.py           |  4 +--
 ForgeImporters/forgeimporters/google/project.py | 19 +++++++------
 .../google/templates/project.html               | 30 ++++++++++----------
 3 files changed, 27 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a5371df3/ForgeImporters/forgeimporters/google/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/__init__.py b/ForgeImporters/forgeimporters/google/__init__.py
index e01dcfb..235791f 100644
--- a/ForgeImporters/forgeimporters/google/__init__.py
+++ b/ForgeImporters/forgeimporters/google/__init__.py
@@ -48,8 +48,8 @@ class GoogleCodeProjectExtractor(object):
         })
 
     def __init__(self, project, page='project_info'):
-        gc_project_name = project.get_tool_data('google-code', 'project_name')
-        page = urllib2.urlopen(self.PAGE_MAP[page] % urllib.quote(gc_project_name))
+        project_name = project.get_tool_data('google-code', 'project_name')
+        page = urllib2.urlopen(self.PAGE_MAP[page] % urllib.quote(project_name))
         self.project = project
         self.page = BeautifulSoup(page)
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a5371df3/ForgeImporters/forgeimporters/google/project.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/project.py b/ForgeImporters/forgeimporters/google/project.py
index fdd3c97..ec8de53 100644
--- a/ForgeImporters/forgeimporters/google/project.py
+++ b/ForgeImporters/forgeimporters/google/project.py
@@ -24,6 +24,7 @@ from allura import model as M
 from allura.lib.decorators import require_post
 from allura.lib.widgets.forms import NeighborhoodProjectShortNameValidator
 from allura.lib import helpers as h
+from allura.lib import exceptions
 
 from .. import base
 from . import tasks
@@ -32,8 +33,8 @@ from . import tasks
 
 class GoogleCodeProjectForm(schema.Schema):
     neighborhood = fev.PlainText(not_empty=True)
-    gc_project_name = fev.Regex(r'^[a-z0-9][a-z0-9-]{,61}$', not_empty=True)
-    project_unixname = NeighborhoodProjectShortNameValidator()
+    project_name = fev.Regex(r'^[a-z0-9][a-z0-9-]{,61}$', not_empty=True)
+    project_shortname = NeighborhoodProjectShortNameValidator()
     tools = base.ToolsValidator('Google Code')
 
 
@@ -49,13 +50,13 @@ class GoogleCodeProjectImporter(base.ProjectImporter):
     @require_post()
     @expose()
     @validate(GoogleCodeProjectForm(), error_handler=index)
-    def process(self, gc_project_name=None, project_unixname=None, tools=None, **kw):
+    def process(self, project_name=None, project_shortname=None, tools=None, **kw):
         neighborhood = M.Neighborhood.query.get(url_prefix='/p/')
-        project_name = h.really_unicode(gc_project_name).encode('utf-8')
-        project_unixname = h.really_unicode(project_unixname).encode('utf-8').lower()
+        project_name = h.really_unicode(project_name).encode('utf-8')
+        project_shortname = h.really_unicode(project_shortname).encode('utf-8').lower()
 
         try:
-            c.project = neighborhood.register_project(project_unixname,
+            c.project = neighborhood.register_project(project_shortname,
                     project_name=project_name)
         except exceptions.ProjectOverlimitError:
             flash("You have exceeded the maximum number of projects you are allowed to create", 'error')
@@ -64,11 +65,11 @@ class GoogleCodeProjectImporter(base.ProjectImporter):
             flash("Project creation rate limit exceeded.  Please try again later.", 'error')
             redirect('.')
         except Exception as e:
-            log.error('error registering project: %s', project_unixname, exc_info=True)
+            log.error('error registering project: %s', project_shortname, exc_info=True)
             flash('Internal Error. Please try again later.', 'error')
             redirect('.')
 
-        c.project.set_tool_data('google-code', project_name=gc_project_name)
+        c.project.set_tool_data('google-code', project_name=project_name)
         tasks.import_project_info.post()
         for tool in tools:
             tool.import_tool(c.project)
@@ -79,5 +80,5 @@ class GoogleCodeProjectImporter(base.ProjectImporter):
 
     @expose('json:')
     @validate(GoogleCodeProjectForm())
-    def check_names(self, gc_project_name=None, project_unixname=None, tools=None, **kw):
+    def check_names(self, project_name=None, project_shortname=None, tools=None, **kw):
         return c.form_errors

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a5371df3/ForgeImporters/forgeimporters/google/templates/project.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/templates/project.html b/ForgeImporters/forgeimporters/google/templates/project.html
index ae9362a..a98d5ef 100644
--- a/ForgeImporters/forgeimporters/google/templates/project.html
+++ b/ForgeImporters/forgeimporters/google/templates/project.html
@@ -41,19 +41,19 @@
         var manual = false;
         function suggest_name() {
             if (!manual) {
-                $('#project_unixname').val($('#gc_project_name').val()).trigger('change');
+                $('#project_shortname').val($('#project_name').val()).trigger('change');
             }
         }
 
         function check_names() {
             var data = {
                 'neighborhood': $('#neighborhood').val(),
-                'gc_project_name': $('#gc_project_name').val(),
-                'project_unixname': $('#project_unixname').val()
+                'project_name': $('#project_name').val(),
+                'project_shortname': $('#project_shortname').val()
             };
             $.getJSON('check_names', data, function(result) {
-                $('#gc_project_name_error').addClass('hidden');
-                $('#project_unixname_error').addClass('hidden');
+                $('#project_name_error').addClass('hidden');
+                $('#project_shortname_error').addClass('hidden');
                 for(var field in result) {
                     $('#'+field+'_error').text(result[field]).removeClass('hidden');
                 }
@@ -61,13 +61,13 @@
         }
 
         function update_url() {
-            $('#url-fragment').text($('#project_unixname').val());
+            $('#url-fragment').text($('#project_shortname').val());
         }
 
         $(function() {
-            $('#gc_project_name').focus().bind('change keyup', suggest_name);
+            $('#project_name').focus().bind('change keyup', suggest_name);
 
-            $('#project_unixname').bind('change keyup', function(event) {
+            $('#project_shortname').bind('change keyup', function(event) {
                 if (event.type == 'keyup') {
                     manual = true;
                 }
@@ -83,9 +83,9 @@
         <label>Google Project Name</label>
     </div>
     <div class="grid-10">
-        <input id="gc_project_name" name="gc_project_name" value="{{c.form_values['gc_project_name']}}"/>
-        <div id="gc_project_name_error" class="error{% if not c.form_errors['gc_project_name'] %} hidden{% endif %}">
-            {{c.form_errors['gc_project_name']}}
+        <input id="project_name" name="project_name" value="{{c.form_values['project_name']}}"/>
+        <div id="project_name_error" class="error{% if not c.form_errors['project_name'] %} hidden{% endif %}">
+            {{c.form_errors['project_name']}}
         </div>
     </div>
 
@@ -93,12 +93,12 @@
         <label>URL Name</label>
     </div>
     <div class="grid-10">
-        <input id="project_unixname" name="project_unixname" value="{{c.form_values['project_unixname']}}"/>
-        <div id="project_unixname_error" class="error{% if not c.form_errors['project_unixname'] %} hidden{% endif %}">
-            {{c.form_errors['project_unixname']}}
+        <input id="project_shortname" name="project_shortname" value="{{c.form_values['project_shortname']}}"/>
+        <div id="project_shortname_error" class="error{% if not c.form_errors['project_shortname'] %} hidden{% endif %}">
+            {{c.form_errors['project_shortname']}}
         </div>
         <div id="project-url">
-            http://{{request.environ['HTTP_HOST']}}{{neighborhood.url()}}<span id="url-fragment">{{c.form_values['project_unixname']}}</span>
+            http://{{request.environ['HTTP_HOST']}}{{neighborhood.url()}}<span id="url-fragment">{{c.form_values['project_shortname']}}</span>
         </div>
     </div>
 {% endblock %}


[3/9] git commit: [#6456] Added missing license header

Posted by br...@apache.org.
[#6456] Added missing license header

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

Branch: refs/heads/master
Commit: 519f7470faced7405e2775ebfdcf7894babd94d1
Parents: a5371df
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Mon Jul 22 18:57:41 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Jul 23 02:45:41 2013 +0000

----------------------------------------------------------------------
 .../forgeimporters/tests/google/__init__.py        | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/519f7470/ForgeImporters/forgeimporters/tests/google/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/__init__.py b/ForgeImporters/forgeimporters/tests/google/__init__.py
index e69de29..77505f1 100644
--- a/ForgeImporters/forgeimporters/tests/google/__init__.py
+++ b/ForgeImporters/forgeimporters/tests/google/__init__.py
@@ -0,0 +1,17 @@
+#       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.
+


[6/9] git commit: [#6456] Fixed validation of GC import form

Posted by br...@apache.org.
[#6456] Fixed validation of GC import form

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

Branch: refs/heads/master
Commit: 5f68604dbc07864302a5c42ae9d71b8b25a52658
Parents: f70ea75
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Mon Jul 22 22:53:25 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Jul 23 02:45:42 2013 +0000

----------------------------------------------------------------------
 ForgeImporters/forgeimporters/google/project.py             | 6 +++++-
 ForgeImporters/forgeimporters/google/templates/project.html | 4 +++-
 ForgeImporters/forgeimporters/tests/test_base.py            | 4 +++-
 3 files changed, 11 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/5f68604d/ForgeImporters/forgeimporters/google/project.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/project.py b/ForgeImporters/forgeimporters/google/project.py
index 678f16d..c3e4d17 100644
--- a/ForgeImporters/forgeimporters/google/project.py
+++ b/ForgeImporters/forgeimporters/google/project.py
@@ -34,7 +34,11 @@ from . import tasks
 
 class GoogleCodeProjectForm(schema.Schema):
     neighborhood = fev.PlainText(not_empty=True)
-    project_name = fev.Regex(r'^[a-z0-9][a-z0-9-]{,61}$', not_empty=True)
+    project_name = fev.Regex(r'^[a-z0-9][a-z0-9-]{,61}$',
+            not_empty=True,
+            messages={
+                'invalid': 'Please use only letters, numbers, and dashes.',
+            })
     project_shortname = NeighborhoodProjectShortNameValidator()
     tools = base.ToolsValidator('Google Code')
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/5f68604d/ForgeImporters/forgeimporters/google/templates/project.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/templates/project.html b/ForgeImporters/forgeimporters/google/templates/project.html
index 614e1cb..2cda0d0 100644
--- a/ForgeImporters/forgeimporters/google/templates/project.html
+++ b/ForgeImporters/forgeimporters/google/templates/project.html
@@ -40,9 +40,11 @@
 
         var manual = false;
         function suggest_name() {
+            var $project_shortname = $('#project_shortname');
             if (!manual) {
-                $('#project_shortname').val($('#project_name').val()).trigger('change');
+                $project_shortname.val($('#project_name').val());
             }
+            $project_shortname.trigger('change');
         }
 
         function check_names() {

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/5f68604d/ForgeImporters/forgeimporters/tests/test_base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/test_base.py b/ForgeImporters/forgeimporters/tests/test_base.py
index 64096fd..303570d 100644
--- a/ForgeImporters/forgeimporters/tests/test_base.py
+++ b/ForgeImporters/forgeimporters/tests/test_base.py
@@ -39,9 +39,11 @@ class TestProjectImporterDispatcher(TestCase):
     @mock.patch.object(base, 'iter_entry_points')
     def test_lookup(self, iep):
         eps = iep.return_value = [ep('ep1', 'first'), ep('ep2', 'second')]
-        result = base.ProjectImporterDispatcher()._lookup('source', 'rest1', 'rest2')
+        nbhd = mock.Mock(name='neighborhood')
+        result = base.ProjectImporterDispatcher(nbhd)._lookup('source', 'rest1', 'rest2')
         self.assertEqual(result, (eps[0].lv, ('rest1', 'rest2')))
         iep.assert_called_once_with('allura.project_importers', 'source')
+        eps[0].load.return_value.assert_called_once_with(nbhd)
 
 
 class TestProjectImporter(TestCase):


[8/9] git commit: [#6456] Removed unnecessary !important

Posted by br...@apache.org.
[#6456] Removed unnecessary !important

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

Branch: refs/heads/master
Commit: f70ea755870d647a4791adc64f325d192547281a
Parents: 22c7f70
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Mon Jul 22 22:35:15 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Jul 23 02:45:42 2013 +0000

----------------------------------------------------------------------
 Allura/allura/nf/allura/css/site_style.css | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/f70ea755/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 94db371..662b4f6 100644
--- a/Allura/allura/nf/allura/css/site_style.css
+++ b/Allura/allura/nf/allura/css/site_style.css
@@ -3106,7 +3106,7 @@ ul.dropdown ul li a:hover {
     font-size: 18px;
     font-weight: 600;
     text-shadow: none;
-    color: white !important;
+    color: white;
     padding: 1em 2em 1em 2em;
     text-decoration: none;
     -webkit-border-radius: 5px;


[7/9] git commit: [#6456] Fixed GC project importer being tied to Projects nbhd and added security check

Posted by br...@apache.org.
[#6456] Fixed GC project importer being tied to Projects nbhd and added security check

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

Branch: refs/heads/master
Commit: 22c7f7012fadca27b1ffce67428bfa254b180a3a
Parents: 788e9e4
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Mon Jul 22 22:32:02 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Jul 23 02:45:42 2013 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/project.py                  |  2 +-
 ForgeImporters/forgeimporters/base.py                 |  6 +++++-
 ForgeImporters/forgeimporters/google/project.py       | 14 ++++++++++----
 .../forgeimporters/google/templates/project.html      |  2 +-
 .../forgeimporters/templates/project_base.html        |  2 +-
 5 files changed, 18 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/22c7f701/Allura/allura/controllers/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/project.py b/Allura/allura/controllers/project.py
index a407bba..91d5a4f 100644
--- a/Allura/allura/controllers/project.py
+++ b/Allura/allura/controllers/project.py
@@ -74,7 +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()
+        self.import_project = ProjectImporterDispatcher(self.neighborhood)
 
     def _check_security(self):
         require_access(self.neighborhood, 'read')

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/22c7f701/ForgeImporters/forgeimporters/base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/base.py b/ForgeImporters/forgeimporters/base.py
index 6632f37..334b89a 100644
--- a/ForgeImporters/forgeimporters/base.py
+++ b/ForgeImporters/forgeimporters/base.py
@@ -26,10 +26,14 @@ from allura.controllers import BaseController
 
 
 class ProjectImporterDispatcher(BaseController):
+    def __init__(self, neighborhood, *a, **kw):
+        super(ProjectImporterDispatcher, self).__init__(*a, **kw)
+        self.neighborhood = neighborhood
+
     @expose()
     def _lookup(self, source, *rest):
         for ep in iter_entry_points('allura.project_importers', source):
-            return ep.load()(), rest
+            return ep.load()(self.neighborhood), rest
 
 
 class ProjectImporter(BaseController):

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/22c7f701/ForgeImporters/forgeimporters/google/project.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/project.py b/ForgeImporters/forgeimporters/google/project.py
index 057115f..678f16d 100644
--- a/ForgeImporters/forgeimporters/google/project.py
+++ b/ForgeImporters/forgeimporters/google/project.py
@@ -23,6 +23,7 @@ from formencode import validators as fev, schema
 from allura import model as M
 from allura.lib.decorators import require_post
 from allura.lib.widgets.forms import NeighborhoodProjectShortNameValidator
+from allura.lib.security import require_access
 from allura.lib import helpers as h
 from allura.lib import exceptions
 
@@ -41,22 +42,27 @@ class GoogleCodeProjectForm(schema.Schema):
 class GoogleCodeProjectImporter(base.ProjectImporter):
     source = 'Google Code'
 
+    def __init__(self, neighborhood, *a, **kw):
+        super(GoogleCodeProjectImporter, self).__init__(*a, **kw)
+        self.neighborhood = neighborhood
+
+    def _check_security(self):
+        require_access(self.neighborhood, 'register')
+
     @with_trailing_slash
     @expose('jinja:forgeimporters.google:templates/project.html')
     def index(self, **kw):
-        neighborhood = M.Neighborhood.query.get(url_prefix='/p/')
-        return {'importer': self, 'neighborhood': neighborhood}
+        return {'importer': self}
 
     @require_post()
     @expose()
     @validate(GoogleCodeProjectForm(), error_handler=index)
     def process(self, project_name=None, project_shortname=None, tools=None, **kw):
-        neighborhood = M.Neighborhood.query.get(url_prefix='/p/')
         project_name = h.really_unicode(project_name).encode('utf-8')
         project_shortname = h.really_unicode(project_shortname).encode('utf-8').lower()
 
         try:
-            c.project = neighborhood.register_project(project_shortname,
+            c.project = self.neighborhood.register_project(project_shortname,
                     project_name=project_name)
         except exceptions.ProjectOverlimitError:
             flash("You have exceeded the maximum number of projects you are allowed to create", 'error')

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/22c7f701/ForgeImporters/forgeimporters/google/templates/project.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/templates/project.html b/ForgeImporters/forgeimporters/google/templates/project.html
index a98d5ef..614e1cb 100644
--- a/ForgeImporters/forgeimporters/google/templates/project.html
+++ b/ForgeImporters/forgeimporters/google/templates/project.html
@@ -98,7 +98,7 @@
             {{c.form_errors['project_shortname']}}
         </div>
         <div id="project-url">
-            http://{{request.environ['HTTP_HOST']}}{{neighborhood.url()}}<span id="url-fragment">{{c.form_values['project_shortname']}}</span>
+            http://{{request.environ['HTTP_HOST']}}{{importer.neighborhood.url()}}<span id="url-fragment">{{c.form_values['project_shortname']}}</span>
         </div>
     </div>
 {% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/22c7f701/ForgeImporters/forgeimporters/templates/project_base.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/templates/project_base.html b/ForgeImporters/forgeimporters/templates/project_base.html
index d42954f..bd37665 100644
--- a/ForgeImporters/forgeimporters/templates/project_base.html
+++ b/ForgeImporters/forgeimporters/templates/project_base.html
@@ -26,7 +26,7 @@
 {% block content %}
 
 <form id="project-import-form" method="POST" action="process">
-    <input type="hidden" id="neighborhood" name="neighborhood" value="Projects"/>
+    <input type="hidden" id="neighborhood" name="neighborhood" value="{{importer.neighborhood.name}}"/>
 
     <fieldset id="project-fields">
         {% block project_fields %}{% endblock %}


[2/9] git commit: [#6456] Changed import_tool call to task in GC project importer

Posted by br...@apache.org.
[#6456] Changed import_tool call to task in GC project importer

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

Branch: refs/heads/master
Commit: f690652203ff7666a4633116b7a44d715936ec44
Parents: 519f747
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Mon Jul 22 20:33:44 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Jul 23 02:45:41 2013 +0000

----------------------------------------------------------------------
 ForgeImporters/forgeimporters/base.py           | 22 ++++---
 ForgeImporters/forgeimporters/google/project.py |  4 +-
 ForgeImporters/forgeimporters/google/tasks.py   |  6 ++
 .../forgeimporters/tests/google/test_tasks.py   |  9 +++
 .../forgeimporters/tests/test_base.py           | 66 ++++++++++++--------
 5 files changed, 69 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/f6906522/ForgeImporters/forgeimporters/base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/base.py b/ForgeImporters/forgeimporters/base.py
index c3b6946..01e614a 100644
--- a/ForgeImporters/forgeimporters/base.py
+++ b/ForgeImporters/forgeimporters/base.py
@@ -68,10 +68,15 @@ class ProjectImporter(BaseController):
 
 
 class ToolImporter(object):
-    target_app = None
-    source = None
+    target_app = None  # app or list of apps
+    source = None  # string description of source, must match project importer
     controller = None
 
+    @classmethod
+    def by_name(self, name):
+        for ep in iter_entry_points('allura.importers', name):
+            return ep.load()()
+
     def import_tool(self, project=None, mount_point=None):
         """
         Override this method to perform the tool import.
@@ -96,15 +101,12 @@ class ToolsValidator(fev.Set):
         value = super(ToolsValidator, self).to_python(value, state)
         valid = []
         invalid = []
-        for i, v in enumerate(value):
-            try:
-                ep = iter_entry_points('allura.importers', v).next().load()
-            except StopIteration:
-                ep = None
-            if getattr(ep, 'source', None) != self.source:
-                invalid.append(v)
+        for name in value:
+            importer = ToolImporter.by_name(name)
+            if importer is not None and importer.source == self.source:
+                valid.append(name)
             else:
-                valid.append(ep())
+                invalid.append(name)
         if invalid:
             pl = 's' if len(invalid) > 1 else ''
             raise fev.Invalid('Invalid tool%s selected: %s' % (pl, ', '.join(invalid)), value, state)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/f6906522/ForgeImporters/forgeimporters/google/project.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/project.py b/ForgeImporters/forgeimporters/google/project.py
index ec8de53..caf1346 100644
--- a/ForgeImporters/forgeimporters/google/project.py
+++ b/ForgeImporters/forgeimporters/google/project.py
@@ -71,8 +71,8 @@ class GoogleCodeProjectImporter(base.ProjectImporter):
 
         c.project.set_tool_data('google-code', project_name=project_name)
         tasks.import_project_info.post()
-        for tool in tools:
-            tool.import_tool(c.project)
+        for importer_name in tools:
+            tasks.import_tool.post(importer_name)
 
         flash('Welcome to the SourceForge Project System! '
               'Your project data will be imported and should show up here shortly.')

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/f6906522/ForgeImporters/forgeimporters/google/tasks.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tasks.py b/ForgeImporters/forgeimporters/google/tasks.py
index 79851c3..834dc9d 100644
--- a/ForgeImporters/forgeimporters/google/tasks.py
+++ b/ForgeImporters/forgeimporters/google/tasks.py
@@ -22,6 +22,7 @@ from ming.orm import ThreadLocalORMSession
 from allura.lib.decorators import task
 
 from . import GoogleCodeProjectExtractor
+from ..base import ToolImporter
 
 
 @task
@@ -31,3 +32,8 @@ def import_project_info():
     extractor.get_icon()
     extractor.get_license()
     ThreadLocalORMSession.flush_all()
+
+@task
+def import_tool(importer_name, mount_point=None, mount_label=None):
+    importer = ToolImporter.by_name(importer_name)
+    importer.import_tool(c.project, mount_point, mount_label)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/f6906522/ForgeImporters/forgeimporters/tests/google/test_tasks.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_tasks.py b/ForgeImporters/forgeimporters/tests/google/test_tasks.py
index a21d083..bb9319d 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_tasks.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_tasks.py
@@ -31,3 +31,12 @@ def test_import_project_info(c, session, gpe):
     gpe.return_value.get_icon.assert_called_once_with()
     gpe.return_value.get_license.assert_called_once_with()
     session.flush_all.assert_called_once_with()
+
+
+@mock.patch.object(tasks.ToolImporter, 'by_name')
+@mock.patch.object(tasks, 'c')
+def test_import_tool(c, by_name):
+    c.project = mock.Mock(name='project')
+    tasks.import_tool('importer_name', 'mount_point', 'mount_label')
+    by_name.assert_called_once_with('importer_name')
+    by_name.return_value.import_tool.assert_called_once_with(c.project, 'mount_point', 'mount_label')

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/f6906522/ForgeImporters/forgeimporters/tests/test_base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/test_base.py b/ForgeImporters/forgeimporters/tests/test_base.py
index 394723d..a6a4d18 100644
--- a/ForgeImporters/forgeimporters/tests/test_base.py
+++ b/ForgeImporters/forgeimporters/tests/test_base.py
@@ -28,6 +28,7 @@ def ep(name, source=None):
     mep.name = name
     mep.load.return_value.source = source
     mep.lv = mep.load.return_value.return_value
+    mep.lv.source = source
     return mep
 
 
@@ -50,7 +51,7 @@ class TestProjectImporter(TestCase):
         iep.assert_called_once_with('allura.importers')
 
 
-class TestImporter(TestCase):
+class TestToolImporter(TestCase):
     class TI1(base.ToolImporter):
         target_app = mock.Mock(tool_label='foo', tool_description='foo_desc')
 
@@ -59,6 +60,19 @@ class TestImporter(TestCase):
         tool_label = 'bar'
         tool_description = 'bar_desc'
 
+    @mock.patch('forgeimporters.base.iter_entry_points')
+    def test_by_name(self, iep):
+        eps = iep.return_value = [ep('my-name', 'my-source')]
+        importer = base.ToolImporter.by_name('my-name')
+        iep.assert_called_once_with('allura.importers', 'my-name')
+        self.assertEqual(importer, eps[0].lv)
+
+        iep.reset_mock()
+        iep.return_value = []
+        importer = base.ToolImporter.by_name('other-name')
+        iep.assert_called_once_with('allura.importers', 'other-name')
+        self.assertEqual(importer, None)
+
     def test_tool_label(self):
         self.assertEqual(self.TI1().tool_label, 'foo')
         self.assertEqual(self.TI2().tool_label, 'bar')
@@ -72,44 +86,44 @@ class TestToolsValidator(TestCase):
     def setUp(self):
         self.tv = base.ToolsValidator('good-source')
 
-    @mock.patch('forgeimporters.base.iter_entry_points')
-    def test_empty(self, iep):
+    @mock.patch.object(base.ToolImporter, 'by_name')
+    def test_empty(self, by_name):
         self.assertEqual(self.tv.to_python(''), [])
-        self.assertEqual(iep.call_count, 0)
+        self.assertEqual(by_name.call_count, 0)
 
-    @mock.patch('forgeimporters.base.iter_entry_points')
-    def test_no_ep(self, iep):
-        eps = iep.return_value.next.side_effect = StopIteration
+    @mock.patch.object(base.ToolImporter, 'by_name')
+    def test_no_ep(self, by_name):
+        eps = by_name.return_value = None
         with self.assertRaises(Invalid) as cm:
             self.tv.to_python('my-value')
         self.assertEqual(cm.exception.msg, 'Invalid tool selected: my-value')
-        iep.assert_called_once_with('allura.importers', 'my-value')
+        by_name.assert_called_once_with('my-value')
 
-    @mock.patch('forgeimporters.base.iter_entry_points')
-    def test_bad_source(self, iep):
-        eps = iep.return_value.next.side_effect = [ep('ep1', 'bad-source'), ep('ep2', 'good-source')]
+    @mock.patch.object(base.ToolImporter, 'by_name')
+    def test_bad_source(self, by_name):
+        eps = by_name.return_value = ep('ep1', 'bad-source').lv
         with self.assertRaises(Invalid) as cm:
             self.tv.to_python('my-value')
         self.assertEqual(cm.exception.msg, 'Invalid tool selected: my-value')
-        iep.assert_called_once_with('allura.importers', 'my-value')
+        by_name.assert_called_once_with('my-value')
 
-    @mock.patch('forgeimporters.base.iter_entry_points')
-    def test_multiple(self, iep):
-        eps = iep.return_value.next.side_effect = [ep('ep1', 'bad-source'), ep('ep2', 'good-source'), ep('ep3', 'bad-source')]
+    @mock.patch.object(base.ToolImporter, 'by_name')
+    def test_multiple(self, by_name):
+        eps = by_name.side_effect = [ep('ep1', 'bad-source').lv, ep('ep2', 'good-source').lv, ep('ep3', 'bad-source').lv]
         with self.assertRaises(Invalid) as cm:
             self.tv.to_python(['value1', 'value2', 'value3'])
         self.assertEqual(cm.exception.msg, 'Invalid tools selected: value1, value3')
-        self.assertEqual(iep.call_args_list, [
-                mock.call('allura.importers', 'value1'),
-                mock.call('allura.importers', 'value2'),
-                mock.call('allura.importers', 'value3'),
+        self.assertEqual(by_name.call_args_list, [
+                mock.call('value1'),
+                mock.call('value2'),
+                mock.call('value3'),
             ])
 
-    @mock.patch('forgeimporters.base.iter_entry_points')
-    def test_valid(self, iep):
-        eps = iep.return_value.next.side_effect = [ep('ep1', 'good-source'), ep('ep2', 'good-source'), ep('ep3', 'bad-source')]
-        self.assertEqual(self.tv.to_python(['value1', 'value2']), [eps[0].lv, eps[1].lv])
-        self.assertEqual(iep.call_args_list, [
-                mock.call('allura.importers', 'value1'),
-                mock.call('allura.importers', 'value2'),
+    @mock.patch.object(base.ToolImporter, 'by_name')
+    def test_valid(self, by_name):
+        eps = by_name.side_effect = [ep('ep1', 'good-source').lv, ep('ep2', 'good-source').lv, ep('ep3', 'bad-source').lv]
+        self.assertEqual(self.tv.to_python(['value1', 'value2']), ['value1', 'value2'])
+        self.assertEqual(by_name.call_args_list, [
+                mock.call('value1'),
+                mock.call('value2'),
             ])


[5/9] git commit: [#6456] Added Google Code project importer

Posted by br...@apache.org.
[#6456] Added Google Code project importer

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

Branch: refs/heads/master
Commit: 7af82067e7802e2f3a27041f4cc85d67e6d4c291
Parents: b2a00e8
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Fri Jul 19 19:21:05 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Jul 23 02:45:41 2013 +0000

----------------------------------------------------------------------
 .../forgeimporters/google/__init__.py           |  17 +--
 ForgeImporters/forgeimporters/google/project.py |  83 +++++++++++++++
 ForgeImporters/forgeimporters/google/tasks.py   |  33 ++++++
 .../google/templates/project.html               | 104 +++++++++++++++++++
 .../forgeimporters/tests/google/__init__.py     |   0
 .../tests/google/test_extractor.py              |  93 +++++++++++++++++
 .../forgeimporters/tests/google/test_tasks.py   |  33 ++++++
 ForgeImporters/setup.py                         |   1 +
 8 files changed, 358 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7af82067/ForgeImporters/forgeimporters/google/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/__init__.py b/ForgeImporters/forgeimporters/google/__init__.py
index 0feb64a..e01dcfb 100644
--- a/ForgeImporters/forgeimporters/google/__init__.py
+++ b/ForgeImporters/forgeimporters/google/__init__.py
@@ -19,6 +19,10 @@ import urllib
 import urllib2
 from urlparse import urlparse
 from collections import defaultdict
+try:
+    from cStringIO import StringIO
+except ImportError:
+    from StringIO import StringIO
 
 from BeautifulSoup import BeautifulSoup
 
@@ -50,19 +54,20 @@ class GoogleCodeProjectExtractor(object):
         self.page = BeautifulSoup(page)
 
     def get_short_description(self):
-        self.project.short_description = str(self.page.find(itemprop='description')).strip()
+        self.project.short_description = self.page.find(itemprop='description').string.strip()
 
     def get_icon(self):
-        icon_url = self.page.find(itemprop='image').src
+        icon_url = self.page.find(itemprop='image').attrMap['src']
         icon_name = urllib.unquote(urlparse(icon_url).path).split('/')[-1]
-        fp = urllib2.urlopen(icon_url)
+        fp_ish = urllib2.urlopen(icon_url)
+        fp = StringIO(fp_ish.read())
         M.ProjectFile.save_image(
-            icon_name, fp, fp.info()['content-type'], square=True,
+            icon_name, fp, fp_ish.info()['content-type'], square=True,
             thumbnail_size=(48,48),
-            thumbnail_meta=dict(project_id=self.project._id, category='icon'))
+            thumbnail_meta={'project_id': self.project._id, 'category': 'icon'})
 
     def get_license(self):
-        license = str(self.page.find(text='Code license:').findNext('td')).strip()
+        license = self.page.find(text='Code license').findNext().find('a').string.strip()
         trove = M.TroveCategory.query.get(fullname=self.LICENSE_MAP[license])
         self.project.trove_license.append(trove._id)
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7af82067/ForgeImporters/forgeimporters/google/project.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/project.py b/ForgeImporters/forgeimporters/google/project.py
new file mode 100644
index 0000000..fdd3c97
--- /dev/null
+++ b/ForgeImporters/forgeimporters/google/project.py
@@ -0,0 +1,83 @@
+#       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 tg import expose, validate, flash, redirect
+from tg.decorators import with_trailing_slash
+from pylons import tmpl_context as c
+from formencode import validators as fev, schema
+
+from allura import model as M
+from allura.lib.decorators import require_post
+from allura.lib.widgets.forms import NeighborhoodProjectShortNameValidator
+from allura.lib import helpers as h
+
+from .. import base
+from . import tasks
+
+
+
+class GoogleCodeProjectForm(schema.Schema):
+    neighborhood = fev.PlainText(not_empty=True)
+    gc_project_name = fev.Regex(r'^[a-z0-9][a-z0-9-]{,61}$', not_empty=True)
+    project_unixname = NeighborhoodProjectShortNameValidator()
+    tools = base.ToolsValidator('Google Code')
+
+
+class GoogleCodeProjectImporter(base.ProjectImporter):
+    source = 'Google Code'
+
+    @with_trailing_slash
+    @expose('jinja:forgeimporters.google:templates/project.html')
+    def index(self, **kw):
+        neighborhood = M.Neighborhood.query.get(url_prefix='/p/')
+        return {'importer': self, 'neighborhood': neighborhood}
+
+    @require_post()
+    @expose()
+    @validate(GoogleCodeProjectForm(), error_handler=index)
+    def process(self, gc_project_name=None, project_unixname=None, tools=None, **kw):
+        neighborhood = M.Neighborhood.query.get(url_prefix='/p/')
+        project_name = h.really_unicode(gc_project_name).encode('utf-8')
+        project_unixname = h.really_unicode(project_unixname).encode('utf-8').lower()
+
+        try:
+            c.project = neighborhood.register_project(project_unixname,
+                    project_name=project_name)
+        except exceptions.ProjectOverlimitError:
+            flash("You have exceeded the maximum number of projects you are allowed to create", 'error')
+            redirect('.')
+        except exceptions.ProjectRatelimitError:
+            flash("Project creation rate limit exceeded.  Please try again later.", 'error')
+            redirect('.')
+        except Exception as e:
+            log.error('error registering project: %s', project_unixname, exc_info=True)
+            flash('Internal Error. Please try again later.', 'error')
+            redirect('.')
+
+        c.project.set_tool_data('google-code', project_name=gc_project_name)
+        tasks.import_project_info.post()
+        for tool in tools:
+            tool.import_tool(c.project)
+
+        flash('Welcome to the SourceForge Project System! '
+              'Your project data will be imported and should show up here shortly.')
+        redirect(c.project.script_name + 'admin/overview')
+
+    @expose('json:')
+    @validate(GoogleCodeProjectForm())
+    def check_names(self, gc_project_name=None, project_unixname=None, tools=None, **kw):
+        return c.form_errors

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7af82067/ForgeImporters/forgeimporters/google/tasks.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tasks.py b/ForgeImporters/forgeimporters/google/tasks.py
new file mode 100644
index 0000000..79851c3
--- /dev/null
+++ b/ForgeImporters/forgeimporters/google/tasks.py
@@ -0,0 +1,33 @@
+#       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 pylons import tmpl_context as c
+
+from ming.orm import ThreadLocalORMSession
+
+from allura.lib.decorators import task
+
+from . import GoogleCodeProjectExtractor
+
+
+@task
+def import_project_info():
+    extractor = GoogleCodeProjectExtractor(c.project, 'project_info')
+    extractor.get_short_description()
+    extractor.get_icon()
+    extractor.get_license()
+    ThreadLocalORMSession.flush_all()

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7af82067/ForgeImporters/forgeimporters/google/templates/project.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/templates/project.html b/ForgeImporters/forgeimporters/google/templates/project.html
new file mode 100644
index 0000000..ae9362a
--- /dev/null
+++ b/ForgeImporters/forgeimporters/google/templates/project.html
@@ -0,0 +1,104 @@
+{#-
+       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.
+-#}
+{% extends 'forgeimporters:templates/project_base.html' %}
+
+{% block extra_css %}
+    {{ super() }}
+    <style type="text/css">
+        #project-import-form #project-fields input {
+            width: 88%;
+        }
+
+        .hidden { display: none; }
+    </style>
+{% endblock %}
+
+{% block extra_js %}
+    {{ super() }}
+    <script type="text/javascript">
+        var timers = {};
+        function delay(callback, ms) {
+            clearTimeout(timers[callback]);
+            timers[callback] = setTimeout(callback, ms);
+        }
+
+        var manual = false;
+        function suggest_name() {
+            if (!manual) {
+                $('#project_unixname').val($('#gc_project_name').val()).trigger('change');
+            }
+        }
+
+        function check_names() {
+            var data = {
+                'neighborhood': $('#neighborhood').val(),
+                'gc_project_name': $('#gc_project_name').val(),
+                'project_unixname': $('#project_unixname').val()
+            };
+            $.getJSON('check_names', data, function(result) {
+                $('#gc_project_name_error').addClass('hidden');
+                $('#project_unixname_error').addClass('hidden');
+                for(var field in result) {
+                    $('#'+field+'_error').text(result[field]).removeClass('hidden');
+                }
+            });
+        }
+
+        function update_url() {
+            $('#url-fragment').text($('#project_unixname').val());
+        }
+
+        $(function() {
+            $('#gc_project_name').focus().bind('change keyup', suggest_name);
+
+            $('#project_unixname').bind('change keyup', function(event) {
+                if (event.type == 'keyup') {
+                    manual = true;
+                }
+                update_url();
+                delay(check_names, 500);
+            });
+        });
+    </script>
+{% endblock %}
+
+{% block project_fields %}
+    <div class="grid-6">
+        <label>Google Project Name</label>
+    </div>
+    <div class="grid-10">
+        <input id="gc_project_name" name="gc_project_name" value="{{c.form_values['gc_project_name']}}"/>
+        <div id="gc_project_name_error" class="error{% if not c.form_errors['gc_project_name'] %} hidden{% endif %}">
+            {{c.form_errors['gc_project_name']}}
+        </div>
+    </div>
+
+    <div class="grid-6" style="clear:left">
+        <label>URL Name</label>
+    </div>
+    <div class="grid-10">
+        <input id="project_unixname" name="project_unixname" value="{{c.form_values['project_unixname']}}"/>
+        <div id="project_unixname_error" class="error{% if not c.form_errors['project_unixname'] %} hidden{% endif %}">
+            {{c.form_errors['project_unixname']}}
+        </div>
+        <div id="project-url">
+            http://{{request.environ['HTTP_HOST']}}{{neighborhood.url()}}<span id="url-fragment">{{c.form_values['project_unixname']}}</span>
+        </div>
+    </div>
+{% endblock %}

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

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7af82067/ForgeImporters/forgeimporters/tests/google/test_extractor.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_extractor.py b/ForgeImporters/forgeimporters/tests/google/test_extractor.py
new file mode 100644
index 0000000..f03c82c
--- /dev/null
+++ b/ForgeImporters/forgeimporters/tests/google/test_extractor.py
@@ -0,0 +1,93 @@
+#       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 google
+
+
+class TestGoogleCodeProjectExtractor(TestCase):
+    def setUp(self):
+        self._p_urlopen = mock.patch.object(google.urllib2, 'urlopen')
+        self._p_soup = mock.patch.object(google, 'BeautifulSoup')
+        self.urlopen = self._p_urlopen.start()
+        self.soup = self._p_soup.start()
+        self.project = mock.Mock(name='project')
+        self.project.get_tool_data.return_value = 'my-project'
+
+    def tearDown(self):
+        self._p_urlopen.stop()
+        self._p_soup.stop()
+
+    def test_init(self):
+        extractor = google.GoogleCodeProjectExtractor(self.project, 'project_info')
+
+        self.project.get_tool_data.assert_called_once_with('google-code', 'project_name')
+        self.urlopen.assert_called_once_with('http://code.google.com/p/my-project/')
+        self.assertEqual(extractor.project, self.project)
+        self.soup.assert_called_once_with(self.urlopen.return_value)
+        self.assertEqual(extractor.page, self.soup.return_value)
+
+    def test_get_short_description(self):
+        extractor = google.GoogleCodeProjectExtractor(self.project, 'project_info')
+        extractor.page.find.return_value.string = 'My Super Project'
+
+        extractor.get_short_description()
+
+        extractor.page.find.assert_called_once_with(itemprop='description')
+        self.assertEqual(self.project.short_description, 'My Super Project')
+
+    @mock.patch.object(google, 'StringIO')
+    @mock.patch.object(google, 'M')
+    def test_get_icon(self, M, StringIO):
+        self.urlopen.return_value.info.return_value = {'content-type': 'image/png'}
+        extractor = google.GoogleCodeProjectExtractor(self.project, 'project_info')
+        extractor.page.find.return_value.attrMap = {'src': 'http://example.com/foo/bar/my-logo.png'}
+        self.urlopen.reset_mock()
+
+        extractor.get_icon()
+
+        extractor.page.find.assert_called_once_with(itemprop='image')
+        self.urlopen.assert_called_once_with('http://example.com/foo/bar/my-logo.png')
+        self.urlopen.return_value.info.assert_called_once_with()
+        StringIO.assert_called_once_with(self.urlopen.return_value.read.return_value)
+        M.ProjectFile.save_image.assert_called_once_with(
+            'my-logo.png', StringIO.return_value, 'image/png', square=True,
+            thumbnail_size=(48,48), thumbnail_meta={
+                'project_id': self.project._id, 'category': 'icon'})
+
+    @mock.patch.object(google, 'M')
+    def test_get_license(self, M):
+        self.project.trove_license = []
+        extractor = google.GoogleCodeProjectExtractor(self.project, 'project_info')
+        extractor.page.find.return_value.findNext.return_value.find.return_value.string = '  New BSD License  '
+        trove = M.TroveCategory.query.get.return_value
+
+        extractor.get_license()
+
+        extractor.page.find.assert_called_once_with(text='Code license')
+        extractor.page.find.return_value.findNext.assert_called_once_with()
+        extractor.page.find.return_value.findNext.return_value.find.assert_called_once_with('a')
+        self.assertEqual(self.project.trove_license, [trove._id])
+        M.TroveCategory.query.get.assert_called_once_with(fullname='BSD License')
+
+        M.TroveCategory.query.get.reset_mock()
+        extractor.page.find.return_value.findNext.return_value.find.return_value.string = 'non-existant license'
+        extractor.get_license()
+        M.TroveCategory.query.get.assert_called_once_with(fullname='Other/Proprietary License')

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7af82067/ForgeImporters/forgeimporters/tests/google/test_tasks.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_tasks.py b/ForgeImporters/forgeimporters/tests/google/test_tasks.py
new file mode 100644
index 0000000..a21d083
--- /dev/null
+++ b/ForgeImporters/forgeimporters/tests/google/test_tasks.py
@@ -0,0 +1,33 @@
+#       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.
+
+import mock
+
+from ...google import tasks
+
+
+@mock.patch.object(tasks, 'GoogleCodeProjectExtractor')
+@mock.patch.object(tasks, 'ThreadLocalORMSession')
+@mock.patch.object(tasks, 'c')
+def test_import_project_info(c, session, gpe):
+    c.project = mock.Mock(name='project')
+    tasks.import_project_info()
+    gpe.assert_called_once_with(c.project, 'project_info')
+    gpe.return_value.get_short_description.assert_called_once_with()
+    gpe.return_value.get_icon.assert_called_once_with()
+    gpe.return_value.get_license.assert_called_once_with()
+    session.flush_all.assert_called_once_with()

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7af82067/ForgeImporters/setup.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/setup.py b/ForgeImporters/setup.py
index 5e45638..a928504 100644
--- a/ForgeImporters/setup.py
+++ b/ForgeImporters/setup.py
@@ -34,6 +34,7 @@ setup(name='ForgeImporters',
       entry_points="""
       # -*- Entry points: -*-
       [allura.project_importers]
+      google-code = forgeimporters.google.project:GoogleCodeProjectImporter
 
       [allura.importers]
       """,)


[9/9] git commit: [#6456] Removed hard-coded reference to SourceForge

Posted by br...@apache.org.
[#6456] Removed hard-coded reference to SourceForge

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

Branch: refs/heads/master
Commit: 788e9e41bdcffa9f9bdd2e64a252b33a835b202d
Parents: 138f431
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Mon Jul 22 21:58:50 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Jul 23 02:45:42 2013 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/project.py            | 4 ++--
 Allura/development.ini                          | 1 +
 Allura/test.ini                                 | 1 +
 ForgeImporters/forgeimporters/google/project.py | 6 +++---
 4 files changed, 7 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/788e9e41/Allura/allura/controllers/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/project.py b/Allura/allura/controllers/project.py
index 24bba79..a407bba 100644
--- a/Allura/allura/controllers/project.py
+++ b/Allura/allura/controllers/project.py
@@ -225,8 +225,8 @@ class NeighborhoodController(object):
             for i, tool in enumerate(tools):
                 if (tool.lower() not in anchored_tools.keys()) and (c.project.app_instance(tool) is None):
                     c.project.install_app(tool, ordinal=i + offset)
-        flash('Welcome to the SourceForge Project System! '
-              'To get started, fill out some information about your project.')
+        flash('Welcome to the %s Project System! '
+              'To get started, fill out some information about your project.' % config['site_name'])
         redirect(c.project.script_name + 'admin/overview')
 
     @expose()

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/788e9e41/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index ab0877c..338b8ee 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -46,6 +46,7 @@ next=main
 use = egg:Allura
 full_stack = true
 use_queue = true
+site_name = Allura
 
 base_url = http://localhost:8080
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/788e9e41/Allura/test.ini
----------------------------------------------------------------------
diff --git a/Allura/test.ini b/Allura/test.ini
index f1bd5f2..7394359 100644
--- a/Allura/test.ini
+++ b/Allura/test.ini
@@ -37,6 +37,7 @@ port = 5000
 use = config:development.ini#tool_test
 db_prefix = test_
 
+site_name = Allura
 base_url = http://localhost
 
 # Use test MongoDB DB server

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/788e9e41/ForgeImporters/forgeimporters/google/project.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/project.py b/ForgeImporters/forgeimporters/google/project.py
index caf1346..057115f 100644
--- a/ForgeImporters/forgeimporters/google/project.py
+++ b/ForgeImporters/forgeimporters/google/project.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from tg import expose, validate, flash, redirect
+from tg import expose, validate, flash, redirect, config
 from tg.decorators import with_trailing_slash
 from pylons import tmpl_context as c
 from formencode import validators as fev, schema
@@ -74,8 +74,8 @@ class GoogleCodeProjectImporter(base.ProjectImporter):
         for importer_name in tools:
             tasks.import_tool.post(importer_name)
 
-        flash('Welcome to the SourceForge Project System! '
-              'Your project data will be imported and should show up here shortly.')
+        flash('Welcome to the %s Project System! '
+              'Your project data will be imported and should show up here shortly.' % config['site_name'])
         redirect(c.project.script_name + 'admin/overview')
 
     @expose('json:')