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/09/16 22:55:21 UTC

[1/7] git commit: [#6613] ticket:428 Tracker API include config & milestones & saved bins

Updated Branches:
  refs/heads/cj/6529 48c0c6c3e -> 50bd1c4af (forced update)


[#6613]  ticket:428  Tracker API include config & milestones & saved bins


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

Branch: refs/heads/cj/6529
Commit: 023a0a34c9c106efe6fd640a93573c8a5ec3c2af
Parents: 224017c
Author: Yuriy Arhipov <yu...@yandex.ru>
Authored: Thu Sep 12 14:48:43 2013 +0400
Committer: Yuriy Arhipov <yu...@yandex.ru>
Committed: Thu Sep 12 14:48:43 2013 +0400

----------------------------------------------------------------------
 ForgeTracker/forgetracker/model/ticket.py               |  2 +-
 ForgeTracker/forgetracker/tests/functional/test_rest.py | 11 +++++++++++
 ForgeTracker/forgetracker/tracker_main.py               |  3 +++
 3 files changed, 15 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/023a0a34/ForgeTracker/forgetracker/model/ticket.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/model/ticket.py b/ForgeTracker/forgetracker/model/ticket.py
index 71fe6c5..f7534e9 100644
--- a/ForgeTracker/forgetracker/model/ticket.py
+++ b/ForgeTracker/forgetracker/model/ticket.py
@@ -513,7 +513,7 @@ class Bin(Artifact, ActivityObject):
         return result
 
     def __json__(self):
-        return dict(super(Bin,self).__json__(),
+        return dict(
             _id=self._id,
             summary=self.summary,
             terms=self.terms,

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/023a0a34/ForgeTracker/forgetracker/tests/functional/test_rest.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tests/functional/test_rest.py b/ForgeTracker/forgetracker/tests/functional/test_rest.py
index 750bd0e..df0a422 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_rest.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_rest.py
@@ -84,6 +84,17 @@ class TestRestUpdateTicket(TestTrackerApiBase):
         assert len(tickets.json['tickets']) == 1, tickets.json
         assert (tickets.json['tickets'][0]
                 == dict(ticket_num=1, summary='test new ticket')), tickets.json['tickets'][0]
+        assert tickets.json['tracker_config']['options']['mount_point'] == 'bugs'
+        assert tickets.json['tracker_config']['options']['TicketMonitoringType'] == 'AllTicketChanges'
+        assert not tickets.json['tracker_config']['options']['EnableVoting']
+        assert tickets.json['tracker_config']['options']['TicketMonitoringEmail'] == 'test@localhost'
+        assert tickets.json['tracker_config']['options']['mount_label'] == 'Tickets'
+        assert tickets.json['saved_bins'][0]['sort'] == 'mod_date_dt desc'
+        assert tickets.json['saved_bins'][0]['terms'] == '!status:wont-fix && !status:closed'
+        assert tickets.json['saved_bins'][0]['summary'] == 'Changes'
+        assert len(tickets.json['saved_bins'][0]) == 4
+        assert tickets.json['milestones'][0]['name'] == '1.0'
+        assert tickets.json['milestones'][1]['name'] == '2.0'
 
     def test_update_ticket(self):
         args = dict(self.ticket_args, summary='test update ticket', labels='',

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/023a0a34/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index df1e084..bc66e6c 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -1583,6 +1583,9 @@ class RootRestController(BaseController):
                                         limit=int(limit), page=int(page))
         results['tickets'] = [dict(ticket_num=t.ticket_num, summary=t.summary)
                               for t in results['tickets']]
+        results['tracker_config'] = c.app.config
+        results['milestones'] = c.app.milestones
+        results['saved_bins'] = c.app.bins
         results.pop('q', None)
         results.pop('sort', None)
         return results


[7/7] git commit: [#6529] Added docstring and example config entry for login_overlay

Posted by jo...@apache.org.
[#6529] Added docstring and example config entry for login_overlay

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

Branch: refs/heads/cj/6529
Commit: 50bd1c4af028fa23d4166a8268607b08ba0dba76
Parents: 6c18193
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Mon Sep 16 20:54:58 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Mon Sep 16 20:54:58 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/helpers.py | 35 +++++++++++++++++++++++++++++++++++
 Allura/development.ini       |  1 +
 2 files changed, 36 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/50bd1c4a/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index 0b92968..76bedbc 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -1017,6 +1017,41 @@ def daterange(start_date, end_date):
 
 @contextmanager
 def login_overlay(exceptions=None):
+    """
+    Override the default behavior of redirecting to the auth.login_url and
+    instead display an overlay with content from auth.login_fragment_url.
+
+    This is to allow pages that require authentication for any actions but
+    not for the initial view to be more apparent what you will get once
+    logged in.
+
+    This should be wrapped around call to `require_access()` (presumably in
+    the `_check_security()` method on a controller).  The `exceptions` param
+    can be given a list of exposed views to leave with the original behavior.
+
+    For example:
+
+        class MyController(BaseController);
+            def _check_security(self):
+                with login_overlay(exceptions=['process']):
+                    require_access(self.neighborhood, 'register')
+
+            @expose
+            def index(self, *args, **kw):
+                return {}
+
+            @expose
+            def list(self, *args, **kw):
+                return {}
+
+            @expose
+            def process(self, *args, **kw):
+                return {}
+
+    This would show the overlay to unauthenticated users who visit `/`
+    or `/list` but would perform the normal redirect when `/process` is
+    visited.
+    """
     try:
         yield
     except HTTPUnauthorized as e:

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/50bd1c4a/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index ee9911b..9cb4b16 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -78,6 +78,7 @@ show_export_control = false
 auth.method = local
 # auth.login_url = /auth/
 # auth.logout_url = /auth/logout
+# auth.login_fragment_url = /auth/login_fragment
 
 auth.ldap.server = ldap://localhost
 auth.ldap.suffix = ou=people,dc=localdomain


[4/7] git commit: [#6540] Added rate limiting on tool imports

Posted by jo...@apache.org.
[#6540] Added rate limiting on tool imports

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

Branch: refs/heads/cj/6529
Commit: 3c0a7e0f5fd179096d48239e3db8c014960a2181
Parents: cd1be45
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Mon Sep 9 22:35:20 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Sep 12 19:56:41 2013 +0000

----------------------------------------------------------------------
 ForgeImporters/forgeimporters/base.py           | 44 +++++++++++++++++++-
 ForgeImporters/forgeimporters/github/code.py    | 19 +++++----
 .../forgeimporters/github/tests/test_code.py    | 20 +++++++++
 ForgeImporters/forgeimporters/google/code.py    | 17 ++++----
 .../forgeimporters/google/tests/test_code.py    | 18 ++++++++
 ForgeImporters/forgeimporters/google/tracker.py | 19 +++++----
 .../forgeimporters/tests/google/test_tracker.py | 20 ++++++++-
 .../forgeimporters/trac/tests/test_tickets.py   | 18 ++++++++
 ForgeImporters/forgeimporters/trac/tickets.py   | 19 +++++----
 9 files changed, 160 insertions(+), 34 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3c0a7e0f/ForgeImporters/forgeimporters/base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/base.py b/ForgeImporters/forgeimporters/base.py
index ffb1650..d7479b3 100644
--- a/ForgeImporters/forgeimporters/base.py
+++ b/ForgeImporters/forgeimporters/base.py
@@ -68,14 +68,16 @@ class ToolImportForm(schema.Schema):
 
 
 class ImportErrorHandler(object):
-    def __init__(self, importer, project_name):
+    def __init__(self, importer, project_name, project):
         self.importer = importer
         self.project_name = project_name
+        self.project = project
 
     def __enter__(self):
         pass
 
     def __exit__(self, exc_type, exc_val, exc_tb):
+        self.importer.clear_pending(self.project)
         if exc_type:
             g.post_event('import_tool_task_failed',
                 error=str(exc_val),
@@ -89,7 +91,7 @@ class ImportErrorHandler(object):
 @task(notifications_disabled=True)
 def import_tool(importer_name, project_name=None, mount_point=None, mount_label=None, **kw):
     importer = ToolImporter.by_name(importer_name)
-    with ImportErrorHandler(importer, project_name):
+    with ImportErrorHandler(importer, project_name, c.project):
         importer.import_tool(c.project, c.user, project_name=project_name,
                 mount_point=mount_point, mount_label=mount_label, **kw)
 
@@ -326,6 +328,44 @@ class ToolImporter(object):
                 importers[ep.name] = importer()
         return importers
 
+    @property
+    def classname(self):
+        return self.__class__.__name__
+
+    def enforce_limit(self, project):
+        """
+        Enforce rate limiting of tool imports on a given project.
+
+        Returns False if limit is met / exceeded.  Otherwise, increments the
+        count of pending / in-progress imports and returns True.
+        """
+        limit = config.get('tool_import.rate_limit', 1)
+        pending_key = 'tool_data.%s.pending' % self.classname
+        modified_project = M.Project.query.find_and_modify(
+                query={
+                        '_id': project._id,
+                        '$or': [
+                                {pending_key: None},
+                                {pending_key: {'$lt': limit}},
+                            ],
+                    },
+                update={'$inc': {pending_key: 1}},
+                new=True,
+            )
+        return modified_project is not None
+
+    def clear_pending(self, project):
+        """
+        Decrement the pending counter for this importer on the given project,
+        to indicate that an import is complete.
+        """
+        pending_key = 'tool_data.%s.pending' % self.classname
+        M.Project.query.find_and_modify(
+                query={'_id': project._id},
+                update={'$inc': {pending_key: -1}},
+                new=True,
+            )
+
     def import_tool(self, project, user, project_name=None,
             mount_point=None, mount_label=None, **kw):
         """

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3c0a7e0f/ForgeImporters/forgeimporters/github/code.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/github/code.py b/ForgeImporters/forgeimporters/github/code.py
index 92e5626..aa5fe7d 100644
--- a/ForgeImporters/forgeimporters/github/code.py
+++ b/ForgeImporters/forgeimporters/github/code.py
@@ -45,7 +45,7 @@ from forgeimporters.github import GitHubProjectExtractor
 @task(notifications_disabled=True)
 def import_tool(**kw):
     importer = GitHubRepoImporter()
-    with ImportErrorHandler(importer, kw.get('project_name')):
+    with ImportErrorHandler(importer, kw.get('project_name'), c.project):
         importer.import_tool(c.project, c.user, **kw)
 
 
@@ -73,13 +73,16 @@ class GitHubRepoImportController(BaseController):
     @require_post()
     @validate(GitHubRepoImportForm(ForgeGitApp), error_handler=index)
     def create(self, gh_project_name, gh_user_name, mount_point, mount_label, **kw):
-        import_tool.post(
-                project_name=gh_project_name,
-                user_name=gh_user_name,
-                mount_point=mount_point,
-                mount_label=mount_label)
-        flash('Repo import has begun. Your new repo will be available '
-                'when the import is complete.')
+        if GitHubRepoImporter().enforce_limit(c.project):
+            import_tool.post(
+                    project_name=gh_project_name,
+                    user_name=gh_user_name,
+                    mount_point=mount_point,
+                    mount_label=mount_label)
+            flash('Repo import has begun. Your new repo 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')
         redirect(c.project.url() + 'admin/')
 
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3c0a7e0f/ForgeImporters/forgeimporters/github/tests/test_code.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/github/tests/test_code.py b/ForgeImporters/forgeimporters/github/tests/test_code.py
index 09afa87..729d8c5 100644
--- a/ForgeImporters/forgeimporters/github/tests/test_code.py
+++ b/ForgeImporters/forgeimporters/github/tests/test_code.py
@@ -17,9 +17,11 @@
 
 from unittest import TestCase
 from mock import Mock, patch
+from ming.odm import ThreadLocalORMSession
 
 from allura.tests import TestController
 from allura.tests.decorators import with_tool
+from allura import model as M
 from forgeimporters.github.code import GitHubRepoImporter
 
 
@@ -76,3 +78,21 @@ class TestGitHubImportController(TestController, TestCase):
         self.assertEqual(u'mylabel', import_tool.post.call_args[1]['mount_label'])
         self.assertEqual(u'poop', import_tool.post.call_args[1]['project_name'])
         self.assertEqual(u'spooky', import_tool.post.call_args[1]['user_name'])
+
+    @with_git
+    @patch('forgeimporters.github.code.import_tool')
+    def test_create_limit(self, import_tool):
+        project = M.Project.query.get(shortname=test_project_with_repo)
+        project.set_tool_data('GitHubRepoImporter', pending=1)
+        ThreadLocalORMSession.flush_all()
+        params = dict(
+                gh_user_name='spooky',
+                gh_project_name='poop',
+                mount_label='mylabel',
+                mount_point='mymount',
+                )
+        r = self.app.post('/p/{}/admin/ext/import/github-repo/create'.format(test_project_with_repo),
+                params,
+                status=302).follow()
+        self.assertIn('Please wait and try again', r)
+        self.assertEqual(import_tool.post.call_count, 0)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3c0a7e0f/ForgeImporters/forgeimporters/google/code.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/code.py b/ForgeImporters/forgeimporters/google/code.py
index 134ecb6..f8e42b3 100644
--- a/ForgeImporters/forgeimporters/google/code.py
+++ b/ForgeImporters/forgeimporters/google/code.py
@@ -88,7 +88,7 @@ def get_repo_class(type_):
 @task(notifications_disabled=True)
 def import_tool(**kw):
     importer = GoogleRepoImporter()
-    with ImportErrorHandler(importer, kw.get('project_name')):
+    with ImportErrorHandler(importer, kw.get('project_name'), c.project):
         importer.import_tool(c.project, c.user, **kw)
 
 
@@ -140,12 +140,15 @@ class GoogleRepoImportController(BaseController):
     @require_post()
     @validate(GoogleRepoImportForm(), error_handler=index)
     def create(self, gc_project_name, mount_point, mount_label, **kw):
-        import_tool.post(
-                project_name=gc_project_name,
-                mount_point=mount_point,
-                mount_label=mount_label)
-        flash('Repo import has begun. Your new repo will be available '
-                'when the import is complete.')
+        if GoogleRepoImporter().enforce_limit(c.project):
+            import_tool.post(
+                    project_name=gc_project_name,
+                    mount_point=mount_point,
+                    mount_label=mount_label)
+            flash('Repo import has begun. Your new repo 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')
         redirect(c.project.url() + 'admin/')
 
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3c0a7e0f/ForgeImporters/forgeimporters/google/tests/test_code.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tests/test_code.py b/ForgeImporters/forgeimporters/google/tests/test_code.py
index 806a004..96dd687 100644
--- a/ForgeImporters/forgeimporters/google/tests/test_code.py
+++ b/ForgeImporters/forgeimporters/google/tests/test_code.py
@@ -17,9 +17,11 @@
 
 from unittest import TestCase
 from mock import Mock, patch
+from ming.odm import ThreadLocalORMSession
 
 from allura.tests import TestController
 from allura.tests.decorators import with_tool
+from allura import model as M
 
 
 # important to be distinct from 'test' which ForgeSVN uses, so that the tests can run in parallel and not clobber each other
@@ -113,3 +115,19 @@ class TestGoogleRepoImportController(TestController, TestCase):
         self.assertEqual(u'mymount', import_tool.post.call_args[1]['mount_point'])
         self.assertEqual(u'mylabel', import_tool.post.call_args[1]['mount_label'])
         self.assertEqual(u'poop', import_tool.post.call_args[1]['project_name'])
+
+    @with_svn
+    @patch('forgeimporters.google.code.import_tool')
+    def test_create_limit(self, import_tool):
+        project = M.Project.query.get(shortname=test_project_with_repo)
+        project.set_tool_data('GoogleRepoImporter', pending=1)
+        ThreadLocalORMSession.flush_all()
+        params = dict(gc_project_name='poop',
+                mount_label='mylabel',
+                mount_point='mymount',
+                )
+        r = self.app.post('/p/{}/admin/src/_importer/create'.format(test_project_with_repo),
+                params,
+                status=302).follow()
+        self.assertIn('Please wait and try again', r)
+        self.assertEqual(import_tool.post.call_count, 0)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3c0a7e0f/ForgeImporters/forgeimporters/google/tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tracker.py b/ForgeImporters/forgeimporters/google/tracker.py
index 9c259dd..d52945e 100644
--- a/ForgeImporters/forgeimporters/google/tracker.py
+++ b/ForgeImporters/forgeimporters/google/tracker.py
@@ -54,7 +54,7 @@ from forgeimporters.base import (
 @task(notifications_disabled=True)
 def import_tool(**kw):
     importer = GoogleCodeTrackerImporter()
-    with ImportErrorHandler(importer, kw.get('project_name')):
+    with ImportErrorHandler(importer, kw.get('project_name'), c.project):
         importer.import_tool(c.project, c.user, **kw)
 
 
@@ -81,13 +81,16 @@ class GoogleCodeTrackerImportController(BaseController):
     @require_post()
     @validate(GoogleCodeTrackerImportForm(ForgeTrackerApp), error_handler=index)
     def create(self, gc_project_name, mount_point, mount_label, **kw):
-        import_tool.post(
-                project_name=gc_project_name,
-                mount_point=mount_point,
-                mount_label=mount_label,
-                )
-        flash('Ticket import has begun. Your new tracker will be available '
-                'when the import is complete.')
+        if GoogleCodeTrackerImporter().enforce_limit(c.project):
+            import_tool.post(
+                    project_name=gc_project_name,
+                    mount_point=mount_point,
+                    mount_label=mount_label,
+                    )
+            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')
         redirect(c.project.url() + 'admin/')
 
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3c0a7e0f/ForgeImporters/forgeimporters/tests/google/test_tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_tracker.py b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
index d795bab..98216f9 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
@@ -17,13 +17,16 @@
 
 from datetime import datetime
 from unittest import TestCase
+
 import mock
 from mock import patch
+from ming.odm import ThreadLocalORMSession
 
 from allura.tests import TestController
 from allura.tests.decorators import with_tracker
 
-from ...google import tracker
+from allura import model as M
+from forgeimporters.google import tracker
 
 
 class TestTrackerImporter(TestCase):
@@ -299,3 +302,18 @@ class TestGoogleCodeTrackerImportController(TestController, TestCase):
         self.assertEqual(u'mymount', import_tool.post.call_args[1]['mount_point'])
         self.assertEqual(u'mylabel', import_tool.post.call_args[1]['mount_label'])
         self.assertEqual(u'test', import_tool.post.call_args[1]['project_name'])
+
+    @with_tracker
+    @patch('forgeimporters.google.tracker.import_tool')
+    def test_create_limit(self, import_tool):
+        project = M.Project.query.get(shortname='test')
+        project.set_tool_data('GoogleCodeTrackerImporter', pending=1)
+        ThreadLocalORMSession.flush_all()
+        params = dict(gc_project_name='test',
+                mount_label='mylabel',
+                mount_point='mymount',
+                )
+        r = self.app.post('/p/test/admin/bugs/_importer/create', params,
+                status=302).follow()
+        self.assertIn('Please wait and try again', r)
+        self.assertEqual(import_tool.post.call_count, 0)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3c0a7e0f/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 92e7854..b3d2fcb 100644
--- a/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
+++ b/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
@@ -18,12 +18,14 @@
 import json
 from unittest import TestCase
 from mock import Mock, patch
+from ming.orm import ThreadLocalORMSession
 
 from tg import config
 
 from allura.tests import TestController
 from allura.tests.decorators import with_tracker
 
+from allura import model as M
 from forgeimporters.trac.tickets import (
     TracTicketImporter,
     TracTicketImportController,
@@ -132,3 +134,19 @@ class TestTracTicketImportController(TestController, TestCase):
         self.assertEqual(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', import_tool.post.call_args[1]['trac_url'])
+
+    @with_tracker
+    @patch('forgeimporters.trac.tickets.import_tool')
+    def test_create_limit(self, import_tool):
+        project = M.Project.query.get(shortname='test')
+        project.set_tool_data('TracTicketImporter', pending=1)
+        ThreadLocalORMSession.flush_all()
+        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"}')],
+                status=302).follow()
+        self.assertIn('Please wait and try again', r)
+        self.assertEqual(import_tool.post.call_count, 0)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3c0a7e0f/ForgeImporters/forgeimporters/trac/tickets.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/trac/tickets.py b/ForgeImporters/forgeimporters/trac/tickets.py
index 9e4f493..cafd403 100644
--- a/ForgeImporters/forgeimporters/trac/tickets.py
+++ b/ForgeImporters/forgeimporters/trac/tickets.py
@@ -61,7 +61,7 @@ from forgetracker.scripts.import_tracker import import_tracker
 @task(notifications_disabled=True)
 def import_tool(**kw):
     importer = TracTicketImporter()
-    with ImportErrorHandler(importer, kw.get('trac_url')):
+    with ImportErrorHandler(importer, kw.get('trac_url'), c.project):
         importer.import_tool(c.project, c.user, **kw)
 
 
@@ -89,13 +89,16 @@ class TracTicketImportController(BaseController):
     @require_post()
     @validate(TracTicketImportForm(ForgeTrackerApp), error_handler=index)
     def create(self, trac_url, mount_point, mount_label, user_map=None, **kw):
-        import_tool.post(
-                mount_point=mount_point,
-                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.')
+        if TracTicketImporter().enforce_limit(c.project):
+            import_tool.post(
+                    mount_point=mount_point,
+                    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.')
+        else:
+            flash('There are too many imports pending at this time.  Please wait and try again.', 'error')
         redirect(c.project.url() + 'admin/')
 
 


[5/7] git commit: [#6529] Added login overlay for project importers

Posted by jo...@apache.org.
[#6529] Added login overlay for project importers

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

Branch: refs/heads/cj/6529
Commit: 2e5471c2eab72f3caaf412ebc1d773de5d1be6ad
Parents: b6776af
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Tue Sep 10 21:55:05 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Mon Sep 16 20:05:47 2013 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/auth.py               |  4 ++
 Allura/allura/lib/app_globals.py                |  7 +++
 Allura/allura/lib/security.py                   | 10 +++-
 Allura/allura/lib/widgets/forms.py              |  3 +-
 .../lib/widgets/resources/js/login_overlay.js   | 27 +++++++++
 Allura/allura/nf/allura/css/allura.css          | 13 ++++-
 .../allura/templates/jinja_master/master.html   |  3 +
 .../templates/jinja_master/theme_macros.html    | 11 +++-
 Allura/allura/templates/login_fragment.html     | 60 ++++++++++++++++++++
 Allura/allura/templates/widgets/forge_form.html |  1 +
 ForgeImporters/forgeimporters/base.py           |  3 +-
 11 files changed, 135 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2e5471c2/Allura/allura/controllers/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/auth.py b/Allura/allura/controllers/auth.py
index 4c1ee37..fa00208 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -105,6 +105,10 @@ class AuthController(BaseController):
         c.form = F.login_form
         return dict(oid_providers=OID_PROVIDERS, return_to=return_to)
 
+    @expose('jinja:allura:templates/login_fragment.html')
+    def login_fragment(self, *args, **kwargs):
+        return self.index(*args, **kwargs)
+
     @expose('jinja:allura:templates/custom_login.html')
     def login_verify_oid(self, provider, username, return_to=None):
         if provider:

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2e5471c2/Allura/allura/lib/app_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py
index c1c0b32..e684383 100644
--- a/Allura/allura/lib/app_globals.py
+++ b/Allura/allura/lib/app_globals.py
@@ -115,6 +115,7 @@ class Globals(object):
         # Load login/logout urls; only used for SFX logins
         self.login_url = config.get('auth.login_url', '/auth/')
         self.logout_url = config.get('auth.logout_url', '/auth/logout')
+        self.login_fragment_url = config.get('auth.login_fragment_url', '/auth/login_fragment')
 
         # Setup Gravatar
         self.gravatar = gravatar.url
@@ -401,6 +402,12 @@ class Globals(object):
     def resource_manager(self):
         return ew_core.widget_context.resource_manager
 
+    def register_css(self, href, **kw):
+        self.resource_manager.register(ew.CSSLink(href, **kw))
+
+    def register_js(self, href, **kw):
+        self.resource_manager.register(ew.JSLink(href, **kw))
+
     def register_forge_css(self, href, **kw):
         self.resource_manager.register(ew.CSSLink('allura/' + href, **kw))
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2e5471c2/Allura/allura/lib/security.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/security.py b/Allura/allura/lib/security.py
index a0497ca..4718e56 100644
--- a/Allura/allura/lib/security.py
+++ b/Allura/allura/lib/security.py
@@ -383,7 +383,7 @@ def all_allowed(obj, user_or_role=None, project=None):
         return set([M.ALL_PERMISSIONS])
     return perms
 
-def require(predicate, message=None):
+def require(predicate, message=None, login_overlay=False):
     '''
     Example: require(has_access(c.app, 'read'))
 
@@ -401,13 +401,17 @@ def require(predicate, message=None):
     if c.user != M.User.anonymous():
         request.environ['error_message'] = message
         raise exc.HTTPForbidden(detail=message)
+    elif login_overlay:
+        c.show_login_overlay = True
     else:
         raise exc.HTTPUnauthorized()
 
-def require_access(obj, permission, **kwargs):
+def require_access(obj, permission, login_overlay=False, **kwargs):
     if obj is not None:
         predicate = has_access(obj, permission, **kwargs)
-        return require(predicate, message='%s access required' % permission.capitalize())
+        return require(predicate,
+                message='%s access required' % permission.capitalize(),
+                login_overlay=login_overlay)
     else:
         raise exc.HTTPForbidden(detail="Could not verify permissions for this page.")
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2e5471c2/Allura/allura/lib/widgets/forms.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/widgets/forms.py b/Allura/allura/lib/widgets/forms.py
index ae90b26..9d3f602 100644
--- a/Allura/allura/lib/widgets/forms.py
+++ b/Allura/allura/lib/widgets/forms.py
@@ -84,7 +84,8 @@ class ForgeForm(ew.SimpleForm):
         submit_text='Save',
         style='standard',
         method='post',
-        enctype=None)
+        enctype=None,
+        target=None)
 
     def display_label(self, field, label_text=None):
         ctx = super(ForgeForm, self).context_for(field)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2e5471c2/Allura/allura/lib/widgets/resources/js/login_overlay.js
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/widgets/resources/js/login_overlay.js b/Allura/allura/lib/widgets/resources/js/login_overlay.js
new file mode 100644
index 0000000..c852916
--- /dev/null
+++ b/Allura/allura/lib/widgets/resources/js/login_overlay.js
@@ -0,0 +1,27 @@
+/*
+       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.
+*/
+
+/*global jQuery, $ */
+jQuery(function($) {
+    $('#login_overlay').draggable().lightbox_me({
+            closeClick: false,
+            closeEsc: false,
+            centered: true
+        });
+});

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2e5471c2/Allura/allura/nf/allura/css/allura.css
----------------------------------------------------------------------
diff --git a/Allura/allura/nf/allura/css/allura.css b/Allura/allura/nf/allura/css/allura.css
index 1334b0c..38404f7 100644
--- a/Allura/allura/nf/allura/css/allura.css
+++ b/Allura/allura/nf/allura/css/allura.css
@@ -215,4 +215,15 @@ b.ico.ico-vote-down { background-image: url('../images/vote_down.png'); }
 tr.rev div.markdown_content p {
     padding: 0;
     margin-bottom: 0;
-}
\ No newline at end of file
+}
+
+#login_overlay .title {
+    margin-bottom: 0;
+    padding-left: 10px;
+    border-top-left-radius: 4px;
+    border-top-right-radius: 4px;
+}
+
+#login_overlay iframe {
+    width: 400px;
+}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2e5471c2/Allura/allura/templates/jinja_master/master.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/jinja_master/master.html b/Allura/allura/templates/jinja_master/master.html
index e3afa6a..8060240 100644
--- a/Allura/allura/templates/jinja_master/master.html
+++ b/Allura/allura/templates/jinja_master/master.html
@@ -132,6 +132,9 @@
           </section>
         {% endfor %}
     </div>
+    {% if c.show_login_overlay %}
+        {{theme_macros.login_overlay()}}
+    {% endif %}
     {% for blob in g.resource_manager.emit('body_js') %}
       {{ blob }}
     {% endfor %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2e5471c2/Allura/allura/templates/jinja_master/theme_macros.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/jinja_master/theme_macros.html b/Allura/allura/templates/jinja_master/theme_macros.html
index 61f5e2f..7fc070c 100644
--- a/Allura/allura/templates/jinja_master/theme_macros.html
+++ b/Allura/allura/templates/jinja_master/theme_macros.html
@@ -112,4 +112,13 @@
          {% endif %}
       </div>
   {% endif %}
-{%- endmacro %}
\ No newline at end of file
+{%- endmacro %}
+
+{%- macro login_overlay() %}
+    {% do g.register_js('js/jquery.lightbox_me.js') %}
+    {% do g.register_js('js/login_overlay.js') %}
+    <div id="login_overlay" class="ui-widget-content">
+        <h2 class="dark title">Login Required</h2>
+        <iframe src="{{g.login_fragment_url}}"></iframe>
+    </div>
+{%- endmacro %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2e5471c2/Allura/allura/templates/login_fragment.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/login_fragment.html b/Allura/allura/templates/login_fragment.html
new file mode 100644
index 0000000..31fb26d
--- /dev/null
+++ b/Allura/allura/templates/login_fragment.html
@@ -0,0 +1,60 @@
+{#-
+       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.
+-#}
+<!DOCTYPE html>
+<!-- Server: {{g.server_name}} -->
+{% import 'allura:templates/jinja_master/lib.html' as lib with context %}
+{% if g.theme.jinja_macros %}
+  {% import g.theme.jinja_macros as theme_macros with context %}
+{% endif %}
+{% do g.register_forge_js('js/jquery-base.js') %}
+{% do g.register_forge_js('js/allura-base.js') %}
+{% do g.theme.require() %}
+{% do g.resource_manager.register_widgets(c) %}
+{# paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/ #}
+<!--[if lt IE 7 ]> <html lang="en" class="no-js ie6"> <![endif]-->
+<!--[if IE 7 ]>    <html lang="en" class="no-js ie7"> <![endif]-->
+<!--[if IE 8 ]>    <html lang="en" class="no-js ie8"> <![endif]-->
+<!--[if IE 9 ]>    <html lang="en" class="no-js ie9"> <![endif]-->
+<!--[if (gt IE 9)|!(IE)]>--> <html lang="en" class="no-js"> <!--<![endif]-->
+    <head>
+        {{theme_macros.extra_header(g.theme_href(''))}}
+        {% for blob in g.resource_manager.emit('head_css') %}
+          {{ blob }}
+        {% endfor %}
+        {% for blob in g.resource_manager.emit('head_js') %}
+          {{ blob }}
+        {% endfor %}
+        <style type="text/css">
+            html {
+                overflow: hidden;
+            }
+            body {
+                padding-top: 1em;
+                width: 1000px;
+            }
+        </style>
+    </head>
+    <body>
+        {{ c.form.display(action='../do_login', target='_top', value=dict(return_to=return_to)) }}
+
+        {% for blob in g.resource_manager.emit('body_js_tail') %}
+          {{ blob }}
+        {% endfor %}
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2e5471c2/Allura/allura/templates/widgets/forge_form.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/widgets/forge_form.html b/Allura/allura/templates/widgets/forge_form.html
index 8adde73..adbc01c 100644
--- a/Allura/allura/templates/widgets/forge_form.html
+++ b/Allura/allura/templates/widgets/forge_form.html
@@ -18,6 +18,7 @@
 -#}
 <form method="{{method}}"
       {% if enctype %}enctype="{{enctype}}"{% endif %}
+      {% if target %}target="{{target}}"{% endif %}
       action="{{action}}">
   {% set extra_width = 0 %}
   {% if style == 'wide' %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2e5471c2/ForgeImporters/forgeimporters/base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/base.py b/ForgeImporters/forgeimporters/base.py
index d7479b3..0b07c6d 100644
--- a/ForgeImporters/forgeimporters/base.py
+++ b/ForgeImporters/forgeimporters/base.py
@@ -190,7 +190,7 @@ class ProjectImporter(BaseController):
         self.neighborhood = neighborhood
 
     def _check_security(self):
-        require_access(self.neighborhood, 'register')
+        require_access(self.neighborhood, 'register', login_overlay=True)
 
     @LazyProperty
     def tool_importers(self):
@@ -231,6 +231,7 @@ class ProjectImporter(BaseController):
         tools installed and redirect to the new project, presumably with a
         message indicating that some data will not be available immediately.
         """
+        require_access(self.neighborhood, 'register', login_overlay=False)
         try:
             c.project = self.neighborhood.register_project(kw['project_shortname'],
                     project_name=kw['project_name'])


[6/7] git commit: [#6529] Refactored login overlay logic out of allura.lib.security and added tests

Posted by jo...@apache.org.
[#6529] Refactored login overlay logic out of allura.lib.security and added tests

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

Branch: refs/heads/cj/6529
Commit: 6c18193083a4a9e7c30d92a7d197a1befe91b42b
Parents: 2e5471c
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Thu Sep 12 20:10:19 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Mon Sep 16 20:05:48 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/helpers.py                    | 13 ++++++++++
 Allura/allura/lib/security.py                   | 10 +++-----
 Allura/allura/tests/test_helpers.py             | 14 ++++++++++-
 ForgeImporters/forgeimporters/base.py           |  5 ++--
 .../tests/github/functional/test_github.py      |  8 +++++++
 .../forgeimporters/tests/test_base.py           | 25 ++++++++++++++++++++
 6 files changed, 65 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6c181930/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index 9c3d9e4..0b92968 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -52,6 +52,7 @@ from jinja2 import Markup
 from paste.deploy.converters import asbool, aslist
 
 from webhelpers import date, feedgenerator, html, number, misc, text
+from webob.exc import HTTPUnauthorized
 
 from allura.lib import exceptions as exc
 # Reimport to make available to templates
@@ -1012,3 +1013,15 @@ def iter_entry_points(group, *a, **kw):
 def daterange(start_date, end_date):
     for n in range(int((end_date - start_date).days)):
         yield start_date + timedelta(n)
+
+
+@contextmanager
+def login_overlay(exceptions=None):
+    try:
+        yield
+    except HTTPUnauthorized as e:
+        if exceptions:
+            for exception in exceptions:
+                if request.path.rstrip('/').endswith('/%s' % exception):
+                    raise
+        c.show_login_overlay = True

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6c181930/Allura/allura/lib/security.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/security.py b/Allura/allura/lib/security.py
index 4718e56..a0497ca 100644
--- a/Allura/allura/lib/security.py
+++ b/Allura/allura/lib/security.py
@@ -383,7 +383,7 @@ def all_allowed(obj, user_or_role=None, project=None):
         return set([M.ALL_PERMISSIONS])
     return perms
 
-def require(predicate, message=None, login_overlay=False):
+def require(predicate, message=None):
     '''
     Example: require(has_access(c.app, 'read'))
 
@@ -401,17 +401,13 @@ def require(predicate, message=None, login_overlay=False):
     if c.user != M.User.anonymous():
         request.environ['error_message'] = message
         raise exc.HTTPForbidden(detail=message)
-    elif login_overlay:
-        c.show_login_overlay = True
     else:
         raise exc.HTTPUnauthorized()
 
-def require_access(obj, permission, login_overlay=False, **kwargs):
+def require_access(obj, permission, **kwargs):
     if obj is not None:
         predicate = has_access(obj, permission, **kwargs)
-        return require(predicate,
-                message='%s access required' % permission.capitalize(),
-                login_overlay=login_overlay)
+        return require(predicate, message='%s access required' % permission.capitalize())
     else:
         raise exc.HTTPForbidden(detail="Could not verify permissions for this page.")
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6c181930/Allura/allura/tests/test_helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_helpers.py b/Allura/allura/tests/test_helpers.py
index d4e5a0c..38a67c5 100644
--- a/Allura/allura/tests/test_helpers.py
+++ b/Allura/allura/tests/test_helpers.py
@@ -27,6 +27,7 @@ from nose.tools import eq_, assert_equals
 from IPython.testing.decorators import skipif, module_not_available
 from datadiff import tools as dd
 from webob import Request
+from webob.exc import HTTPUnauthorized
 from ming.orm import ThreadLocalORMSession
 
 from allura import model as M
@@ -432,4 +433,15 @@ def test_absurl_with_request():
 
 def test_daterange():
     assert_equals(list(h.daterange(datetime(2013, 1, 1), datetime(2013, 1, 4))),
-                 [datetime(2013, 1, 1), datetime(2013, 1, 2), datetime(2013, 1, 3)])
\ No newline at end of file
+                 [datetime(2013, 1, 1), datetime(2013, 1, 2), datetime(2013, 1, 3)])
+
+@patch.object(h, 'request',
+              new=Request.blank('/p/test/foobar', base_url='https://www.mysite.com/p/test/foobar'))
+def test_login_overlay():
+    with h.login_overlay():
+        raise HTTPUnauthorized()
+    with h.login_overlay(exceptions=['foo']):
+        raise HTTPUnauthorized()
+    with td.raises(HTTPUnauthorized):
+        with h.login_overlay(exceptions=['foobar']):
+            raise HTTPUnauthorized()

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6c181930/ForgeImporters/forgeimporters/base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/base.py b/ForgeImporters/forgeimporters/base.py
index 0b07c6d..8c01b62 100644
--- a/ForgeImporters/forgeimporters/base.py
+++ b/ForgeImporters/forgeimporters/base.py
@@ -26,6 +26,7 @@ from tg import expose, validate, flash, redirect, config
 from tg.decorators import with_trailing_slash
 from pylons import app_globals as g
 from pylons import tmpl_context as c
+from pylons import request
 from formencode import validators as fev, schema
 from webob import exc
 
@@ -190,7 +191,8 @@ class ProjectImporter(BaseController):
         self.neighborhood = neighborhood
 
     def _check_security(self):
-        require_access(self.neighborhood, 'register', login_overlay=True)
+        with h.login_overlay(exceptions=['process']):
+            require_access(self.neighborhood, 'register')
 
     @LazyProperty
     def tool_importers(self):
@@ -231,7 +233,6 @@ class ProjectImporter(BaseController):
         tools installed and redirect to the new project, presumably with a
         message indicating that some data will not be available immediately.
         """
-        require_access(self.neighborhood, 'register', login_overlay=False)
         try:
             c.project = self.neighborhood.register_project(kw['project_shortname'],
                     project_name=kw['project_name'])

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6c181930/ForgeImporters/forgeimporters/tests/github/functional/test_github.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/github/functional/test_github.py b/ForgeImporters/forgeimporters/tests/github/functional/test_github.py
index 3c05a2d..cee88c0 100644
--- a/ForgeImporters/forgeimporters/tests/github/functional/test_github.py
+++ b/ForgeImporters/forgeimporters/tests/github/functional/test_github.py
@@ -26,3 +26,11 @@ class TestGitHubImportController(TestController, TestCase):
         assert '<input id="user_name" name="user_name" value="" autofocus/>' in r
         assert '<input id="project_name" name="project_name" value="" />' in r
         assert '<input id="project_shortname" name="project_shortname" value=""/>' in r
+
+    def test_login_overlay(self):
+        r = self.app.get('/p/import_project/github/', extra_environ=dict(username='*anonymous'))
+        self.assertIn('GitHub Project Importer', r)
+        self.assertIn('Login Required', r)
+
+        r = self.app.post('/p/import_project/github/process', extra_environ=dict(username='*anonymous'), status=302)
+        self.assertIn('/auth/', r.location)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6c181930/ForgeImporters/forgeimporters/tests/test_base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/test_base.py b/ForgeImporters/forgeimporters/tests/test_base.py
index 4aefc35..d4b403d 100644
--- a/ForgeImporters/forgeimporters/tests/test_base.py
+++ b/ForgeImporters/forgeimporters/tests/test_base.py
@@ -21,8 +21,10 @@ from formencode import Invalid
 import mock
 from tg import expose
 from nose.tools import assert_equal, assert_raises
+from webob.exc import HTTPUnauthorized
 
 from alluratest.controller import TestController
+from allura.tests import decorators as td
 
 from .. import base
 
@@ -123,6 +125,29 @@ class TestProjectImporter(TestCase):
         self.assertEqual(flash.call_count, 1)
         redirect.assert_called_once_with('script_name/admin/overview')
 
+    @mock.patch.object(base.h, 'request')
+    @mock.patch.object(base, 'require_access')
+    @mock.patch.object(base.h, 'c')
+    def test_login_overlay(self, c, require_access, request):
+        pi = base.ProjectImporter(mock.Mock())
+        require_access.side_effect = HTTPUnauthorized
+
+        c.show_login_overlay = False
+        request.path = '/test-importer/'
+        pi._check_security()
+        self.assertEqual(c.show_login_overlay, True)
+
+        c.show_login_overlay = False
+        request.path = '/test-importer/check_names/'
+        pi._check_security()
+        self.assertEqual(c.show_login_overlay, True)
+
+        c.show_login_overlay = False
+        request.path = '/test-importer/process/'
+        with td.raises(HTTPUnauthorized):
+            pi._check_security()
+        self.assertEqual(c.show_login_overlay, False)
+
 
 
 TA1 = mock.Mock(tool_label='foo', tool_description='foo_desc')


[2/7] git commit: [#6613] don't expose TicketMonitoringEmail in API, and associated TestRestApiBase changes

Posted by jo...@apache.org.
[#6613] don't expose TicketMonitoringEmail in API, and associated TestRestApiBase changes


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

Branch: refs/heads/cj/6529
Commit: cd1be45da425cc914b50690588585741dad3fd01
Parents: 023a0a3
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Thu Sep 12 17:59:12 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Sep 12 17:59:12 2013 +0000

----------------------------------------------------------------------
 .../tests/functional/test_rest_api_tickets.py   |  3 +-
 AlluraTest/alluratest/controller.py             | 34 +++++++++++++-------
 .../tests/functional/test_import.py             |  8 ++---
 .../tests/functional/test_import.py             | 10 +++---
 .../forgetracker/tests/functional/test_rest.py  |  4 +++
 ForgeTracker/forgetracker/tracker_main.py       |  7 +++-
 6 files changed, 44 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cd1be45d/Allura/allura/tests/functional/test_rest_api_tickets.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_rest_api_tickets.py b/Allura/allura/tests/functional/test_rest_api_tickets.py
index 11e149f..145e143 100644
--- a/Allura/allura/tests/functional/test_rest_api_tickets.py
+++ b/Allura/allura/tests/functional/test_rest_api_tickets.py
@@ -29,7 +29,8 @@ class TestApiTicket(TestRestApiBase):
     def set_api_ticket(self, expire=None):
         if not expire:
             expire = timedelta(days=1)
-        api_ticket = M.ApiTicket(user_id=self.user._id, capabilities={'import': ['Projects','test']},
+        test_admin = M.User.query.get(username='test-admin')
+        api_ticket = M.ApiTicket(user_id=test_admin._id, capabilities={'import': ['Projects','test']},
                                  expires=datetime.utcnow() + expire)
         session(api_ticket).flush()
         self.set_api_token(api_ticket)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cd1be45d/AlluraTest/alluratest/controller.py
----------------------------------------------------------------------
diff --git a/AlluraTest/alluratest/controller.py b/AlluraTest/alluratest/controller.py
index 7b38700..577088d 100644
--- a/AlluraTest/alluratest/controller.py
+++ b/AlluraTest/alluratest/controller.py
@@ -145,23 +145,35 @@ class TestRestApiBase(TestController):
     def setUp(self):
         super(TestRestApiBase, self).setUp()
         setup_global_objects()
-#        h.set_context('test', 'home')
-        self.user = M.User.query.get(username='test-admin')
-        self.token = M.ApiToken(user_id=self.user._id)
-        ming.orm.session(self.token).flush()
+        self._use_token = None
+        self._token_cache = {}
 
     def set_api_token(self, token):
-        self.token = token
+        self._use_token = token
+
+    def token(self, username):
+        if self._use_token:
+            return self._use_token
+
+        # only create token once, else ming gets dupe key error
+        if username not in self._token_cache:
+            user = M.User.query.get(username=username)
+            token = M.ApiToken(user_id=user._id)
+            ming.orm.session(token).flush()
+            self._token_cache[username] = token
+
+        return self._token_cache[username]
 
     def _api_getpost(self, method, path, api_key=None, api_timestamp=None, api_signature=None,
-                 wrap_args=None, **params):
+                 wrap_args=None, user='test-admin', **params):
         if wrap_args:
             params = {wrap_args: params}
         params = variabledecode.variable_encode(params, add_repetitions=False)
         if api_key: params['api_key'] = api_key
         if api_timestamp: params['api_timestamp'] = api_timestamp
         if api_signature: params['api_signature'] = api_signature
-        params = self.token.sign_request(path, params)
+
+        params = self.token(user).sign_request(path, params)
 
         fn = self.app.post if method=='POST' else self.app.get
 
@@ -175,9 +187,9 @@ class TestRestApiBase(TestController):
             return response
 
     def api_get(self, path, api_key=None, api_timestamp=None, api_signature=None,
-                 wrap_args=None, **params):
-        return self._api_getpost('GET', path, api_key, api_timestamp, api_signature, wrap_args, **params)
+                 wrap_args=None, user='test-admin', **params):
+        return self._api_getpost('GET', path, api_key, api_timestamp, api_signature, wrap_args, user, **params)
 
     def api_post(self, path, api_key=None, api_timestamp=None, api_signature=None,
-                 wrap_args=None, **params):
-        return self._api_getpost('POST', path, api_key, api_timestamp, api_signature, wrap_args, **params)
+                 wrap_args=None, user='test-admin', **params):
+        return self._api_getpost('POST', path, api_key, api_timestamp, api_signature, wrap_args, user, **params)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cd1be45d/ForgeDiscussion/forgediscussion/tests/functional/test_import.py
----------------------------------------------------------------------
diff --git a/ForgeDiscussion/forgediscussion/tests/functional/test_import.py b/ForgeDiscussion/forgediscussion/tests/functional/test_import.py
index 17d13c7..76d7896 100644
--- a/ForgeDiscussion/forgediscussion/tests/functional/test_import.py
+++ b/ForgeDiscussion/forgediscussion/tests/functional/test_import.py
@@ -57,7 +57,7 @@ class TestImportController(TestRestApiBase):#TestController):
         assert not r.json['errors']
 
     def test_import_anon(self):
-        api_ticket = M.ApiTicket(user_id=self.user._id, capabilities={'import': ['Projects', 'test']},
+        api_ticket = M.ApiTicket(user_id=c.user._id, capabilities={'import': ['Projects', 'test']},
                                  expires=datetime.utcnow() + timedelta(days=1))
         ming.orm.session(api_ticket).flush()
         self.set_api_token(api_ticket)
@@ -76,7 +76,7 @@ class TestImportController(TestRestApiBase):#TestController):
         assert 'Anonymous' in str(r)
 
     def test_import_map(self):
-        api_ticket = M.ApiTicket(user_id=self.user._id, capabilities={'import': ['Projects', 'test']},
+        api_ticket = M.ApiTicket(user_id=c.user._id, capabilities={'import': ['Projects', 'test']},
                                  expires=datetime.utcnow() + timedelta(days=1))
         ming.orm.session(api_ticket).flush()
         self.set_api_token(api_ticket)
@@ -97,7 +97,7 @@ class TestImportController(TestRestApiBase):#TestController):
         assert 'Anonymous' not in str(r)
 
     def test_import_create(self):
-        api_ticket = M.ApiTicket(user_id=self.user._id, capabilities={'import': ['Projects', 'test']},
+        api_ticket = M.ApiTicket(user_id=c.user._id, capabilities={'import': ['Projects', 'test']},
                                  expires=datetime.utcnow() + timedelta(days=1))
         ming.orm.session(api_ticket).flush()
         self.set_api_token(api_ticket)
@@ -117,7 +117,7 @@ class TestImportController(TestRestApiBase):#TestController):
         assert 'test-rick446' in str(r)
 
     def set_api_ticket(self, caps={'import': ['Projects', 'test']}):
-        api_ticket = M.ApiTicket(user_id=self.user._id, capabilities=caps,
+        api_ticket = M.ApiTicket(user_id=c.user._id, capabilities=caps,
                                  expires=datetime.utcnow() + timedelta(days=1))
         ming.orm.session(api_ticket).flush()
         self.set_api_token(api_ticket)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cd1be45d/ForgeTracker/forgetracker/tests/functional/test_import.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tests/functional/test_import.py b/ForgeTracker/forgetracker/tests/functional/test_import.py
index f876b93..8192115 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_import.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_import.py
@@ -46,7 +46,7 @@ class TestImportController(TestRestApiBase):
         return resp.follow()
 
     def set_api_ticket(self, caps={'import': ['Projects','test']}):
-        api_ticket = M.ApiTicket(user_id=self.user._id, capabilities=caps,
+        api_ticket = M.ApiTicket(user_id=c.user._id, capabilities=caps,
                                  expires=datetime.utcnow() + timedelta(days=1))
         ming.orm.session(api_ticket).flush()
         self.set_api_token(api_ticket)
@@ -107,7 +107,7 @@ class TestImportController(TestRestApiBase):
             '/admin/bugs/set_custom_fields',
             params=variable_encode(params))
         here_dir = os.path.dirname(__file__)
-        api_ticket = M.ApiTicket(user_id=self.user._id, capabilities={'import': ['Projects','test']},
+        api_ticket = M.ApiTicket(user_id=c.user._id, capabilities={'import': ['Projects','test']},
                                  expires=datetime.utcnow() + timedelta(days=1))
         ming.orm.session(api_ticket).flush()
         self.set_api_token(api_ticket)
@@ -129,7 +129,7 @@ class TestImportController(TestRestApiBase):
     @td.with_tracker
     def test_import(self):
         here_dir = os.path.dirname(__file__)
-        api_ticket = M.ApiTicket(user_id=self.user._id, capabilities={'import': ['Projects','test']},
+        api_ticket = M.ApiTicket(user_id=c.user._id, capabilities={'import': ['Projects','test']},
                                  expires=datetime.utcnow() + timedelta(days=1))
         ming.orm.session(api_ticket).flush()
         self.set_api_token(api_ticket)
@@ -184,7 +184,7 @@ class TestImportController(TestRestApiBase):
 
     @td.with_tracker
     def test_links(self):
-        api_ticket = M.ApiTicket(user_id=self.user._id, capabilities={'import': ['Projects','test']},
+        api_ticket = M.ApiTicket(user_id=c.user._id, capabilities={'import': ['Projects','test']},
                                  expires=datetime.utcnow() + timedelta(days=1))
         ming.orm.session(api_ticket).flush()
         self.set_api_token(api_ticket)
@@ -207,7 +207,7 @@ class TestImportController(TestRestApiBase):
 
     @td.with_tracker
     def test_slug(self):
-        api_ticket = M.ApiTicket(user_id=self.user._id, capabilities={'import': ['Projects','test']},
+        api_ticket = M.ApiTicket(user_id=c.user._id, capabilities={'import': ['Projects','test']},
                                  expires=datetime.utcnow() + timedelta(days=1))
         ming.orm.session(api_ticket).flush()
         self.set_api_token(api_ticket)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cd1be45d/ForgeTracker/forgetracker/tests/functional/test_rest.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tests/functional/test_rest.py b/ForgeTracker/forgetracker/tests/functional/test_rest.py
index df0a422..b687efb 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_rest.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_rest.py
@@ -96,6 +96,10 @@ class TestRestUpdateTicket(TestTrackerApiBase):
         assert tickets.json['milestones'][0]['name'] == '1.0'
         assert tickets.json['milestones'][1]['name'] == '2.0'
 
+    def test_ticket_index_noauth(self):
+        tickets = self.api_get('/rest/p/test/bugs', user='*anonymous')
+        assert 'TicketMonitoringEmail' not in tickets.json['tracker_config']['options']
+
     def test_update_ticket(self):
         args = dict(self.ticket_args, summary='test update ticket', labels='',
                     assigned_to=self.ticket_args['assigned_to_id'] or '')

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/cd1be45d/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index bc66e6c..28bd4aa 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -1583,7 +1583,12 @@ class RootRestController(BaseController):
                                         limit=int(limit), page=int(page))
         results['tickets'] = [dict(ticket_num=t.ticket_num, summary=t.summary)
                               for t in results['tickets']]
-        results['tracker_config'] = c.app.config
+        results['tracker_config'] = c.app.config.__json__()
+        if not has_access(c.app, 'admin', c.user):
+            try:
+                del results['tracker_config']['options']['TicketMonitoringEmail']
+            except KeyError:
+                pass
         results['milestones'] = c.app.milestones
         results['saved_bins'] = c.app.bins
         results.pop('q', None)


[3/7] git commit: [#6540] bump GoogleCodeWikiImporter and TracWikiImporter versions for their rate-limiting additions

Posted by jo...@apache.org.
[#6540] bump GoogleCodeWikiImporter and TracWikiImporter versions for their rate-limiting additions


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

Branch: refs/heads/cj/6529
Commit: b6776afe3b6cdba86a7a75648044279b40476fdc
Parents: 3c0a7e0
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Thu Sep 12 19:56:33 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Sep 12 19:56:41 2013 +0000

----------------------------------------------------------------------
 requirements-sf.txt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/b6776afe/requirements-sf.txt
----------------------------------------------------------------------
diff --git a/requirements-sf.txt b/requirements-sf.txt
index ecad4a2..071e528 100644
--- a/requirements-sf.txt
+++ b/requirements-sf.txt
@@ -6,7 +6,7 @@ kombu==1.0.4
 coverage==3.5a1-20110413
 ForgeHg==0.1.16
 ForgePastebin==0.2.7
-GoogleCodeWikiImporter==0.3.3
+GoogleCodeWikiImporter==0.4.3
 mechanize==0.2.4
 mercurial==1.4.3
 MySQL-python==1.2.3c1
@@ -20,7 +20,7 @@ wsgipreload==1.2
 pyzmq==2.1.7
 html2text==3.200.3dev-20121112
 PyMollom==0.1
-TracWikiImporter==0.2.2
+TracWikiImporter==0.3.2
 
 # use version built from https://github.com/johnsca/GitPython/commits/tv/6000
 # for unmerged fixes for [#5411], [#6000], and [#6078]