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/08/03 00:01:35 UTC
[2/2] git commit: [#6480] Add trac project and wiki importers;
refactor bases
[#6480] Add trac project and wiki importers; refactor bases
Signed-off-by: Tim Van Steenburgh <tv...@gmail.com>
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/c0940697
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/c0940697
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/c0940697
Branch: refs/heads/tv/6480
Commit: c094069721c10506bbbec789fd41f7524afbef0a
Parents: 5b4ccd4
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Fri Aug 2 22:01:08 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Fri Aug 2 22:01:08 2013 +0000
----------------------------------------------------------------------
ForgeImporters/forgeimporters/base.py | 96 +++++++++++++++-
ForgeImporters/forgeimporters/google/project.py | 66 +++--------
ForgeImporters/forgeimporters/google/tasks.py | 6 -
.../google/templates/project.html | 62 -----------
.../forgeimporters/templates/project_base.html | 89 ++++++++++++++-
ForgeImporters/forgeimporters/trac/project.py | 63 +++++++++++
.../forgeimporters/trac/templates/project.html | 32 ++++++
.../trac/templates/wiki/index.html | 42 +++++++
ForgeImporters/forgeimporters/trac/tickets.py | 2 +-
ForgeImporters/forgeimporters/trac/wiki.py | 110 +++++++++++++++++++
ForgeImporters/setup.py | 3 +
11 files changed, 445 insertions(+), 126 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c0940697/ForgeImporters/forgeimporters/base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/base.py b/ForgeImporters/forgeimporters/base.py
index 034a580..749ff68 100644
--- a/ForgeImporters/forgeimporters/base.py
+++ b/ForgeImporters/forgeimporters/base.py
@@ -15,16 +15,46 @@
# specific language governing permissions and limitations
# under the License.
+import logging
+
from pkg_resources import iter_entry_points
-from tg import expose
+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
+
+from allura.lib.decorators import require_post
+from allura.lib.decorators import task
+from allura.lib.security import require_access
+from allura.lib.widgets.forms import NeighborhoodProjectShortNameValidator
+from allura.lib import exceptions
+
from paste.deploy.converters import aslist
-from formencode import validators as fev
from ming.utils import LazyProperty
from allura.controllers import BaseController
+log = logging.getLogger(__name__)
+
+
+class ProjectImportForm(schema.Schema):
+ def __init__(self, source):
+ super(ProjectImportForm, self).__init__()
+ self.add_field('tools', ToolsValidator(source))
+
+ neighborhood = fev.PlainText(not_empty=True)
+ project_name = fev.UnicodeString(not_empty=True, max=40)
+ project_shortname = NeighborhoodProjectShortNameValidator()
+
+
+@task
+def import_tool(importer_name, mount_point=None, mount_label=None, **kw):
+ importer = ToolImporter.by_name(importer_name)
+ importer.import_tool(c.project, mount_point, mount_label, **kw)
+
+
class ProjectImporter(BaseController):
"""
Base class for project importers.
@@ -33,6 +63,14 @@ class ProjectImporter(BaseController):
:meth:`process()` views described below.
"""
source = None
+ process_validator = None
+ index_template = None
+
+ def __init__(self, neighborhood, *a, **kw):
+ self.neighborhood = neighborhood
+
+ def _check_security(self):
+ require_access(self.neighborhood, 'register')
@LazyProperty
def tool_importers(self):
@@ -47,6 +85,8 @@ class ProjectImporter(BaseController):
tools[ep.name] = epv()
return tools
+ @with_trailing_slash
+ @expose()
def index(self, **kw):
"""
Override and expose this view to present the project import form.
@@ -58,9 +98,12 @@ class ProjectImporter(BaseController):
This will list the available tool importers. Other project fields
(e.g., project_name) should go in the project_fields block.
"""
- raise NotImplemented
+ return {'importer': self, 'tg_template': self.index_template}
- def process(self, tools=None, **kw):
+ @require_post()
+ @expose()
+ @validate(process_validator, error_handler=index)
+ def process(self, **kw):
"""
Override and expose this to handle a project import.
@@ -68,7 +111,50 @@ class ProjectImporter(BaseController):
tools installed and redirect to the new project, presumably with a
message indicating that some data will not be available immediately.
"""
- raise NotImplemented
+ try:
+ c.project = self.neighborhood.register_project(kw['project_shortname'],
+ project_name=kw['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:
+ log.error('error registering project: %s', kw['project_shortname'], exc_info=True)
+ flash('Internal Error. Please try again later.', 'error')
+ redirect('.')
+
+ self.after_project_create(c.project, **kw)
+ for importer_name in kw['tools']:
+ import_tool.post(importer_name, **kw)
+
+ 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:')
+ @validate(process_validator)
+ def check_names(self, **kw):
+ """
+ Ajax form validation.
+
+ """
+ return c.form_errors
+
+ def after_project_create(self, project, **kw):
+ """
+ Called after project is created.
+
+ Useful for doing extra processing on the project before individual
+ tool imports happen.
+
+ :param project: The newly created project.
+ :param \*\*kw: The keyword arguments that were posted to the controller
+ method that created the project.
+
+ """
+ pass
class ToolImporter(object):
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c0940697/ForgeImporters/forgeimporters/google/project.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/project.py b/ForgeImporters/forgeimporters/google/project.py
index d579606..dda41ea 100644
--- a/ForgeImporters/forgeimporters/google/project.py
+++ b/ForgeImporters/forgeimporters/google/project.py
@@ -17,16 +17,12 @@
import logging
-from tg import expose, validate, flash, redirect, config
+from formencode import validators as fev
+
+from tg import expose, validate
from tg.decorators import with_trailing_slash
-from pylons import tmpl_context as c
-from formencode import validators as fev, schema
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
from .. import base
from . import tasks
@@ -35,15 +31,12 @@ from . import tasks
log = logging.getLogger(__name__)
-class GoogleCodeProjectForm(schema.Schema):
- neighborhood = fev.PlainText(not_empty=True)
+class GoogleCodeProjectForm(base.ProjectImportForm):
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')
class GoogleCodeProjectImporter(base.ProjectImporter):
@@ -55,50 +48,25 @@ class GoogleCodeProjectImporter(base.ProjectImporter):
import.
"""
source = 'Google Code'
+ process_validator = GoogleCodeProjectForm(source)
+ index_template = 'jinja:forgeimporters.google:templates/project.html'
- def __init__(self, neighborhood, *a, **kw):
- super(GoogleCodeProjectImporter, self).__init__(*a, **kw)
- self.neighborhood = neighborhood
-
- def _check_security(self):
- require_access(self.neighborhood, 'register')
+ def after_project_create(self, project, **kw):
+ project.set_tool_data('google-code', project_name=project.name)
+ tasks.import_project_info.post()
@with_trailing_slash
- @expose('jinja:forgeimporters.google:templates/project.html')
+ @expose(index_template)
def index(self, **kw):
- return {'importer': self}
+ return super(self.__class__, self).index(**kw)
@require_post()
@expose()
- @validate(GoogleCodeProjectForm(), error_handler=index)
- def process(self, project_name=None, project_shortname=None, tools=None, **kw):
- project_name = h.really_unicode(project_name).encode('utf-8')
- project_shortname = h.really_unicode(project_shortname).encode('utf-8').lower()
-
- try:
- 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')
- 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_shortname, exc_info=True)
- flash('Internal Error. Please try again later.', 'error')
- redirect('.')
-
- c.project.set_tool_data('google-code', project_name=project_name)
- tasks.import_project_info.post()
- for importer_name in tools:
- tasks.import_tool.post(importer_name)
-
- 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')
+ @validate(process_validator, error_handler=index)
+ def process(self, **kw):
+ return super(self.__class__, self).process(**kw)
@expose('json:')
- @validate(GoogleCodeProjectForm())
- def check_names(self, project_name=None, project_shortname=None, tools=None, **kw):
- return c.form_errors
+ @validate(process_validator)
+ def check_names(self, **kw):
+ return super(self.__class__, self).check_names(**kw)
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c0940697/ForgeImporters/forgeimporters/google/tasks.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tasks.py b/ForgeImporters/forgeimporters/google/tasks.py
index 65dd126..433daa8 100644
--- a/ForgeImporters/forgeimporters/google/tasks.py
+++ b/ForgeImporters/forgeimporters/google/tasks.py
@@ -23,7 +23,6 @@ from ming.orm import ThreadLocalORMSession
from allura.lib.decorators import task
from . import GoogleCodeProjectExtractor
-from ..base import ToolImporter
@task
@@ -34,8 +33,3 @@ def import_project_info():
extractor.get_license()
ThreadLocalORMSession.flush_all()
g.post_event('project_updated')
-
-@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/c0940697/ForgeImporters/forgeimporters/google/templates/project.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/templates/project.html b/ForgeImporters/forgeimporters/google/templates/project.html
index 2cda0d0..172dcf5 100644
--- a/ForgeImporters/forgeimporters/google/templates/project.html
+++ b/ForgeImporters/forgeimporters/google/templates/project.html
@@ -18,68 +18,6 @@
-#}
{% 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() {
- var $project_shortname = $('#project_shortname');
- if (!manual) {
- $project_shortname.val($('#project_name').val());
- }
- $project_shortname.trigger('change');
- }
-
- function check_names() {
- var data = {
- 'neighborhood': $('#neighborhood').val(),
- 'project_name': $('#project_name').val(),
- 'project_shortname': $('#project_shortname').val()
- };
- $.getJSON('check_names', data, function(result) {
- $('#project_name_error').addClass('hidden');
- $('#project_shortname_error').addClass('hidden');
- for(var field in result) {
- $('#'+field+'_error').text(result[field]).removeClass('hidden');
- }
- });
- }
-
- function update_url() {
- $('#url-fragment').text($('#project_shortname').val());
- }
-
- $(function() {
- $('#project_name').focus().bind('change keyup', suggest_name);
-
- $('#project_shortname').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>
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c0940697/ForgeImporters/forgeimporters/templates/project_base.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/templates/project_base.html b/ForgeImporters/forgeimporters/templates/project_base.html
index fc654f2..d4db30e 100644
--- a/ForgeImporters/forgeimporters/templates/project_base.html
+++ b/ForgeImporters/forgeimporters/templates/project_base.html
@@ -23,13 +23,97 @@
{% block title %}{{importer.source}} Project Importer{% endblock %}
{% block header %}{{importer.source}} Project Importer{% endblock %}
-{% block content %}
+{% 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() {
+ var $project_shortname = $('#project_shortname');
+ if (!manual) {
+ $project_shortname.val($('#project_name').val());
+ }
+ $project_shortname.trigger('change');
+ }
+
+ function check_names() {
+ var data = {
+ 'neighborhood': $('#neighborhood').val(),
+ 'project_name': $('#project_name').val(),
+ 'project_shortname': $('#project_shortname').val()
+ };
+ $.getJSON('check_names', data, function(result) {
+ $('#project_name_error').addClass('hidden');
+ $('#project_shortname_error').addClass('hidden');
+ for(var field in result) {
+ $('#'+field+'_error').text(result[field]).removeClass('hidden');
+ }
+ });
+ }
+
+ function update_url() {
+ $('#url-fragment').text($('#project_shortname').val());
+ }
+ $(function() {
+ $('#project_name').focus().bind('change keyup', suggest_name);
+
+ $('#project_shortname').bind('change keyup', function(event) {
+ if (event.type == 'keyup') {
+ manual = true;
+ }
+ update_url();
+ delay(check_names, 500);
+ });
+ });
+ </script>
+{% endblock %}
+
+{% block content %}
<form id="project-import-form" method="POST" action="process">
<input type="hidden" id="neighborhood" name="neighborhood" value="{{importer.neighborhood.name}}"/>
<fieldset id="project-fields">
- {% block project_fields %}{% endblock %}
+ {% block project_fields %}
+ <div class="grid-6" style="clear:left">
+ <label>Project Name</label>
+ </div>
+ <div class="grid-10">
+ <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>
+
+ <div class="grid-6" style="clear:left">
+ <label>URL Name</label>
+ </div>
+ <div class="grid-10">
+ <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']}}{{importer.neighborhood.url()}}<span id="url-fragment">{{c.form_values['project_shortname']}}</span>
+ </div>
+ </div>
+ {% endblock %}
</fieldset>
<fieldset id="tool-fields">
@@ -50,5 +134,4 @@
<input type="submit" value="Import"/>
</form>
-
{% endblock %}
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c0940697/ForgeImporters/forgeimporters/trac/project.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/trac/project.py b/ForgeImporters/forgeimporters/trac/project.py
new file mode 100644
index 0000000..66e8326
--- /dev/null
+++ b/ForgeImporters/forgeimporters/trac/project.py
@@ -0,0 +1,63 @@
+# 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 logging
+
+from formencode import validators as fev
+
+from tg import expose, validate
+from tg.decorators import with_trailing_slash
+
+from allura.lib.decorators import require_post
+
+from .. import base
+
+
+log = logging.getLogger(__name__)
+
+
+class TracProjectForm(base.ProjectImportForm):
+ trac_url = fev.URL(not_empty=True)
+
+
+class TracProjectImporter(base.ProjectImporter):
+ """
+ Project importer for Trac.
+
+ """
+ source = 'Trac'
+ process_validator = TracProjectForm(source)
+ index_template = 'jinja:forgeimporters.trac:templates/project.html'
+
+ def after_project_create(self, project, **kw):
+ project.set_tool_data('trac', url=kw['trac_url'])
+
+ @with_trailing_slash
+ @expose(index_template)
+ def index(self, **kw):
+ return super(self.__class__, self).index(**kw)
+
+ @require_post()
+ @expose()
+ @validate(process_validator, error_handler=index)
+ def process(self, **kw):
+ return super(self.__class__, self).process(**kw)
+
+ @expose('json:')
+ @validate(process_validator)
+ def check_names(self, **kw):
+ return super(self.__class__, self).check_names(**kw)
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c0940697/ForgeImporters/forgeimporters/trac/templates/project.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/trac/templates/project.html b/ForgeImporters/forgeimporters/trac/templates/project.html
new file mode 100644
index 0000000..abcfb48
--- /dev/null
+++ b/ForgeImporters/forgeimporters/trac/templates/project.html
@@ -0,0 +1,32 @@
+{#-
+ 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 project_fields %}
+ <div class="grid-6">
+ <label>Trac URL</label>
+ </div>
+ <div class="grid-10">
+ <input id="trac_url" name="trac_url" value="{{c.form_values['trac_url']}}"/>
+ <div id="trac_ur_errorl" class="error{% if not c.form_errors['trac_url'] %} hidden{% endif %}">
+ {{c.form_errors['trac_url']}}
+ </div>
+ </div>
+ {{ super() }}
+{% endblock %}
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c0940697/ForgeImporters/forgeimporters/trac/templates/wiki/index.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/trac/templates/wiki/index.html b/ForgeImporters/forgeimporters/trac/templates/wiki/index.html
new file mode 100644
index 0000000..6083b9c
--- /dev/null
+++ b/ForgeImporters/forgeimporters/trac/templates/wiki/index.html
@@ -0,0 +1,42 @@
+{#-
+ 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 g.theme.master %}
+
+{% block title %}
+{{c.project.name}} / Import Trac Wiki
+{% endblock %}
+
+{% block header %}
+Import wiki from Trac
+{% endblock %}
+
+{% block content %}
+<form action="create" method="post" class="pad">
+ <label for="trac_url">URL of the Trac instance</label>
+ <input name="trac_url" />
+
+ <label for="mount_label">Label</label>
+ <input name="mount_label" value="Source" />
+
+ <label for="mount_point">Mount Point</label>
+ <input name="mount_point" value="source" />
+
+ <input type="submit" />
+</form>
+{% endblock %}
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c0940697/ForgeImporters/forgeimporters/trac/tickets.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/trac/tickets.py b/ForgeImporters/forgeimporters/trac/tickets.py
index cc31741..969dfd2 100644
--- a/ForgeImporters/forgeimporters/trac/tickets.py
+++ b/ForgeImporters/forgeimporters/trac/tickets.py
@@ -48,7 +48,7 @@ from allura.scripts.trac_export import (
from forgeimporters.base import ToolImporter
from forgetracker.tracker_main import ForgeTrackerApp
-from forgetracker.script.import_tracker import import_tracker
+from forgetracker.scripts.import_tracker import import_tracker
class TracTicketImportSchema(fe.Schema):
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c0940697/ForgeImporters/forgeimporters/trac/wiki.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/trac/wiki.py b/ForgeImporters/forgeimporters/trac/wiki.py
new file mode 100644
index 0000000..2417863
--- /dev/null
+++ b/ForgeImporters/forgeimporters/trac/wiki.py
@@ -0,0 +1,110 @@
+# 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 argparse
+from datetime import (
+ datetime,
+ timedelta,
+ )
+import tempfile
+
+import formencode as fe
+from formencode import validators as fev
+
+from pylons import tmpl_context as c
+from pylons import app_globals as g
+from tg import (
+ config,
+ expose,
+ redirect,
+ validate,
+ )
+from tg.decorators import (
+ with_trailing_slash,
+ without_trailing_slash,
+ )
+
+from allura.controllers import BaseController
+from allura.lib.decorators import require_post
+from allura.model import ApiTicket
+
+from forgeimporters.base import ToolImporter
+
+from forgewiki.scripts.wiki_from_trac.extractors import WikiExporter
+from forgewiki.scripts.wiki_from_trac.loaders import load_data
+from forgewiki.scripts.wiki_from_trac.wiki_from_trac import WikiFromTrac
+from forgewiki.wiki_main import ForgeWikiApp
+
+
+class TracWikiImportSchema(fe.Schema):
+ trac_url = fev.URL(not_empty=True)
+ mount_point = fev.UnicodeString()
+ mount_label = fev.UnicodeString()
+
+
+class TracWikiImportController(BaseController):
+ @with_trailing_slash
+ @expose('jinja:forgeimporters.trac:templates/wiki/index.html')
+ def index(self, **kw):
+ return {}
+
+ @without_trailing_slash
+ @expose()
+ @require_post()
+ @validate(TracWikiImportSchema(), error_handler=index)
+ def create(self, trac_url, mount_point, mount_label, **kw):
+ app = TracWikiImporter.import_tool(c.project,
+ mount_point=mount_point,
+ mount_label=mount_label,
+ trac_url=trac_url,
+ user=c.user)
+ redirect(app.url())
+
+
+class TracWikiImporter(ToolImporter):
+ target_app = ForgeWikiApp
+ source = 'Trac'
+ controller = TracWikiImportController
+ tool_label = 'Trac Wiki Importer'
+ tool_description = 'Import your wiki from Trac'
+
+ def import_tool(self, project=None, mount_point=None, mount_label=None,
+ trac_url=None, user=None):
+ """ Import Trac wiki into a new Allura Wiki tool.
+
+ """
+ mount_point = mount_point or 'wiki'
+ app = project.install_app(
+ 'Wiki',
+ mount_point=mount_point,
+ mount_label=mount_label or 'Wiki',
+ )
+ api_ticket = ApiTicket(user_id=user._id,
+ capabilities={"import": ["Projects", project.shortname]},
+ expires=datetime.utcnow() + timedelta(minutes=60))
+ options = argparse.Namespace()
+ options.api_key = api_ticket.api_key
+ options.secret_key = api_ticket.secret_key
+ options.project = project.shortname
+ options.wiki = mount_point
+ options.base_url = config['base_url']
+ with tempfile.NamedTemporaryFile() as f:
+ WikiExporter(trac_url, options).export(f)
+ f.flush()
+ load_data(f.name, WikiFromTrac.parser(), options)
+ g.post_event('project_updated')
+ return app
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c0940697/ForgeImporters/setup.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/setup.py b/ForgeImporters/setup.py
index 8af3c1a..d79a687 100644
--- a/ForgeImporters/setup.py
+++ b/ForgeImporters/setup.py
@@ -35,7 +35,10 @@ setup(name='ForgeImporters',
# -*- Entry points: -*-
[allura.project_importers]
google-code = forgeimporters.google.project:GoogleCodeProjectImporter
+ trac = forgeimporters.trac.project:TracProjectImporter
[allura.importers]
google-code-repo = forgeimporters.google.code:GoogleRepoImporter
+ trac-tickets = forgeimporters.trac.tickets:TracTicketImporter
+ trac-wiki = forgeimporters.trac.wiki:TracWikiImporter
""",)