You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by tv...@apache.org on 2013/09/12 22:52:09 UTC

[19/29] git commit: [#6541] Refactored import_id and ImportIdConverter

[#6541] Refactored import_id and ImportIdConverter

Made default import_id implementation use a dict to
record source and other info for use with multiple importers.

Requires Ming 0.3.9 (from 0.3.x branch) for MIM bug fixes for
tests to pass.

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

Branch: refs/heads/db/6640
Commit: 448664290746b2c16fb99c8df1b04434f0296e37
Parents: c3d8491
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Wed Aug 28 16:31:26 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Mon Sep 9 20:27:29 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/plugin.py                     | 32 ++++++++++++++++++++
 Allura/allura/model/artifact.py                 |  7 +++--
 ForgeImporters/forgeimporters/google/tracker.py | 11 +++++--
 .../tests/google/functional/test_tracker.py     | 11 +++++--
 .../forgeimporters/tests/google/test_tracker.py | 11 ++++++-
 ForgeTracker/forgetracker/model/ticket.py       |  2 +-
 ForgeTracker/forgetracker/plugins.py            | 25 ---------------
 .../forgetracker/tests/functional/test_root.py  |  2 +-
 ForgeTracker/forgetracker/tracker_main.py       | 12 +++++---
 requirements-common.txt                         |  2 +-
 10 files changed, 75 insertions(+), 40 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/44866429/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index f600363..3376034 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -947,3 +947,35 @@ class AdminExtension(object):
         :rtype: ``None``
         """
         pass
+
+class ImportIdConverter(object):
+    '''
+    An interface to convert to and from import_id values for indexing,
+    searching, or displaying.
+
+    To provide a new converter, expose an entry point in setup.py:
+
+        [allura.tickets.import_id_converter]
+        mysource = foo.bar:SourceIdConverter
+
+    Then in your .ini file, set tickets.import_id_converter=mysource
+    '''
+
+    @classmethod
+    def get(cls):
+        converter = config.get('import_id_converter')
+        if converter:
+            return g.entry_points['allura.import_id_converter'][converter]()
+        return cls()
+
+    def simplify(self, import_id):
+        if hasattr(import_id, 'get'):
+            return import_id.get('source_id')
+        return None
+
+    def expand(self, source_id, app_instance):
+        import_id = {
+                'source_id': source_id,
+            }
+        import_id.update(app_instance.config.options.get('import_id', {}))
+        return import_id

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/44866429/Allura/allura/model/artifact.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/artifact.py b/Allura/allura/model/artifact.py
index 294c3d0..46c4b01 100644
--- a/Allura/allura/model/artifact.py
+++ b/Allura/allura/model/artifact.py
@@ -83,8 +83,11 @@ class Artifact(MappedClass):
     references = FieldProperty(S.Deprecated)
     backreferences = FieldProperty(S.Deprecated)
     app_config = RelationProperty('AppConfig')
-    # Not null if artifact originated from external import, then API ticket id
-    import_id = FieldProperty(str, if_missing=None)
+    # Not null if artifact originated from external import.  The import ID is
+    # implementation specific, but should probably be an object indicating
+    # the source, original ID, and any other info needed to identify where
+    # the artifact came from.  But if you only have one source, a str might do.
+    import_id = FieldProperty(None, if_missing=None)
     deleted=FieldProperty(bool, if_missing=False)
 
     def __json__(self):

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/44866429/ForgeImporters/forgeimporters/google/tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tracker.py b/ForgeImporters/forgeimporters/google/tracker.py
index eebdae0..58f28d2 100644
--- a/ForgeImporters/forgeimporters/google/tracker.py
+++ b/ForgeImporters/forgeimporters/google/tracker.py
@@ -40,11 +40,12 @@ from tg.decorators import (
 
 from allura.controllers import BaseController
 from allura.lib import helpers as h
+from allura.lib.plugin import ImportIdConverter
 from allura.lib.decorators import require_post, task
 
 from forgetracker.tracker_main import ForgeTrackerApp
 from forgetracker import model as TM
-from . import GoogleCodeProjectExtractor
+from forgeimporters.google import GoogleCodeProjectExtractor
 from forgeimporters.base import (
         ToolImporter,
         ToolImportForm,
@@ -112,11 +113,15 @@ class GoogleCodeTrackerImporter(ToolImporter):
 
     def import_tool(self, project, user, project_name, mount_point=None,
             mount_label=None, **kw):
+        import_id_converter = ImportIdConverter.get()
         app = project.install_app('tickets', mount_point, mount_label,
                 EnableVoting=True,
                 open_status_names='New Accepted Started',
                 closed_status_names='Fixed Verified Invalid Duplicate WontFix Done',
-                import_id='%s/%s/issues' % (self.source, project_name),
+                import_id={
+                        'source': self.source,
+                        'project_name': project_name,
+                    },
             )
         ThreadLocalORMSession.flush_all()
         try:
@@ -128,7 +133,7 @@ class GoogleCodeTrackerImporter(ToolImporter):
                         app_config_id=app.config._id,
                         custom_fields=dict(),
                         ticket_num=ticket_num,
-                        import_id='%s/%s' % (app.config.options.import_id, ticket_num))
+                        import_id=import_id_converter.expand(ticket_num, app))
                     self.process_fields(ticket, issue)
                     self.process_labels(ticket, issue)
                     self.process_comments(ticket, issue)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/44866429/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py b/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
index 0bd97ab..7f504a5 100644
--- a/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
@@ -142,9 +142,16 @@ class TestGCTrackerImporter(TestCase):
 
     def test_import_id(self):
         ticket = self._make_ticket(self.test_issue, issue_id=6)
-        self.assertEqual(ticket.app.config.options.import_id, 'Google Code/test-issue-project/issues')
+        self.assertEqual(ticket.app.config.options.import_id, {
+                'source': 'Google Code',
+                'project_name': 'test-issue-project',
+            })
         self.assertEqual(ticket.ticket_num, 6)
-        self.assertEqual(ticket.import_id, 'Google Code/test-issue-project/issues/6')
+        self.assertEqual(ticket.import_id, {
+                'source': 'Google Code',
+                'project_name': 'test-issue-project',
+                'source_id': 6,
+            })
 
     @skipif(module_not_available('html2text'))
     def test_html2text_escaping(self):

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/44866429/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 d2cedc6..05b33ae 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
@@ -42,6 +42,12 @@ class TestTrackerImporter(TestCase):
         importer.postprocess_custom_fields = mock.Mock()
         project, user = mock.Mock(), mock.Mock()
         app = project.install_app.return_value
+        app.config.options = {
+                'import_id': {
+                        'source': 'Google Code',
+                        'project_name': 'project_name',
+                    },
+            }
         issues = gpe.iter_issues.return_value = [(50, mock.Mock()), (100, mock.Mock())]
         tickets = TM.Ticket.side_effect = [mock.Mock(), mock.Mock()]
 
@@ -52,7 +58,10 @@ class TestTrackerImporter(TestCase):
                 EnableVoting=True,
                 open_status_names='New Accepted Started',
                 closed_status_names='Fixed Verified Invalid Duplicate WontFix Done',
-                import_id='Google Code/project_name/issues',
+                import_id={
+                        'source': 'Google Code',
+                        'project_name': 'project_name',
+                    }
             )
         gpe.iter_issues.assert_called_once_with('project_name')
         self.assertEqual(importer.process_fields.call_args_list, [

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/44866429/ForgeTracker/forgetracker/model/ticket.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/model/ticket.py b/ForgeTracker/forgetracker/model/ticket.py
index d16039e..1d4aeb2 100644
--- a/ForgeTracker/forgetracker/model/ticket.py
+++ b/ForgeTracker/forgetracker/model/ticket.py
@@ -47,9 +47,9 @@ from allura.lib import security
 from allura.lib.search import search_artifact, SearchError
 from allura.lib import utils
 from allura.lib import helpers as h
+from allura.lib.plugin import ImportIdConverter
 from allura.tasks import mail_tasks
 
-from forgetracker.plugins import ImportIdConverter
 
 log = logging.getLogger(__name__)
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/44866429/ForgeTracker/forgetracker/plugins.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/plugins.py b/ForgeTracker/forgetracker/plugins.py
index a32dcfc..3afbca2 100644
--- a/ForgeTracker/forgetracker/plugins.py
+++ b/ForgeTracker/forgetracker/plugins.py
@@ -22,28 +22,3 @@ from pylons import app_globals as g
 
 log = logging.getLogger(__name__)
 
-
-class ImportIdConverter(object):
-    '''
-    An interface to provide authentication services for Allura.
-
-    To provide a new converter, expose an entry point in setup.py:
-
-        [allura.tickets.import_id_converter]
-        mylegacy = foo.bar:LegacyConverter
-
-    Then in your .ini file, set tickets.import_id_converter=mylegacy
-    '''
-
-    @classmethod
-    def get(cls):
-        converter = config.get('tickets.import_id_converter')
-        if converter:
-            return g.entry_points['allura.tickets.import_id_converter'][converter]()
-        return cls()
-
-    def simplify(self, import_id):
-        return import_id
-
-    def expand(self, url_part, app_instance):
-        return url_part

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/44866429/ForgeTracker/forgetracker/tests/functional/test_root.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tests/functional/test_root.py b/ForgeTracker/forgetracker/tests/functional/test_root.py
index 0ba4f0b..86ef522 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -1573,7 +1573,7 @@ class TestFunctionalController(TrackerTestController):
     def test_imported_tickets_redirect(self):
         self.new_ticket(summary='Imported ticket')
         ticket = tm.Ticket.query.get(ticket_num=1)
-        ticket.import_id = '42000'
+        ticket.import_id = {'source_id': '42000'}
         ThreadLocalORMSession.flush_all()
 
         # expect permanent redirect to /p/test/bugs/1/

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/44866429/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 8aa29f6..3afdb15 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -58,6 +58,7 @@ from allura.lib import validators as V
 from allura.lib.widgets import form_fields as ffw
 from allura.lib.widgets.subscriptions import SubscribeForm
 from allura.lib.zarkov_helpers import zero_fill_zarkov_result
+from allura.lib.plugin import ImportIdConverter
 from allura.controllers import AppDiscussionController, AppDiscussionRestController
 from allura.controllers import attachments as ac
 from allura.controllers import BaseController
@@ -75,7 +76,6 @@ from forgetracker.widgets.bin_form import BinForm
 from forgetracker.widgets.ticket_search import TicketSearchResults, MassEdit, MassEditForm, MassMoveForm, SearchHelp
 from forgetracker.widgets.admin_custom_fields import TrackerFieldAdmin, TrackerFieldDisplay
 from forgetracker.import_support import ImportSupport
-from forgetracker.plugins import ImportIdConverter
 
 log = logging.getLogger(__name__)
 
@@ -1196,11 +1196,15 @@ class TicketController(BaseController, FeedController):
             self.ticket = TM.Ticket.query.get(app_config_id=c.app.config._id,
                                                     ticket_num=self.ticket_num)
             if self.ticket is None:
-                self.ticket = TM.Ticket.query.get(
-                        app_config_id=c.app.config._id,
-                        import_id=str(ImportIdConverter.get().expand(ticket_num, c.app)))
+                query = {'app_config_id': c.app.config._id}
+                import_id = ImportIdConverter.get().expand(ticket_num, c.app)
+                if import_id:
+                    query.update({'import_id.%s' % k: v for k,v in import_id.iteritems()})
+                self.ticket = TM.Ticket.query.get(**query)
                 if self.ticket is not None:
                     utils.permanent_redirect(self.ticket.url())
+                else:
+                    raise exc.HTTPNotFound('Ticket #%s does not exist.' % ticket_num)
             self.attachment = AttachmentsController(self.ticket)
             # self.comments = CommentController(self.ticket)
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/44866429/requirements-common.txt
----------------------------------------------------------------------
diff --git a/requirements-common.txt b/requirements-common.txt
index 5e261a0..5e4d6cc 100644
--- a/requirements-common.txt
+++ b/requirements-common.txt
@@ -21,7 +21,7 @@ httplib2==0.7.4
 iso8601==0.1.4
 Jinja2==2.6
 Markdown==2.2.0
-Ming==0.3.7
+Ming==0.3.9
 oauth2==1.5.170
 # tg2 dep PasteDeploy must specified before TurboGears2, to avoid a version/allow-hosts problem
 Paste==1.7.5.1