blob: 5318ec5bd5dca3b1261394ca66d10b47592c3609 [file] [log] [blame]
# 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.
#-*- python -*-
import logging
from datetime import datetime
from ming import schema as S
from ming.orm import ThreadLocalORMSession, session
from pylons import tmpl_context as c
from allura import model as M
from forgediscussion import model as DM
log = logging.getLogger(__name__)
def validate_import(json, username_mapping, default_username=None):
warnings = []
schema = make_schema(username_mapping, default_username, warnings)
json = schema.validate(json)
return warnings, json
def perform_import(json, username_mapping, default_username=None, create_users=False):
if create_users:
default_username = create_user
# Validate the import, create missing users
warnings, json = validate_import(json, username_mapping, default_username)
for w in warnings:
log.warning('Importing to %s/%s: %s',
c.project.shortname,
c.app.config.options.mount_point,
w)
for name, forum in json.forums.iteritems():
log.info('... %s has %d threads with %d total posts',
name, len(forum.threads), sum(len(t) for t in forum.threads.itervalues()))
for name, forum in json.forums.iteritems():
log.info('... creating %s/%s: %s',
c.project.shortname,
c.app.config.options.mount_point,
name)
f = DM.Forum(
app_config_id=c.app.config._id,
name=forum['name'],
shortname=forum['name'],
description=forum['description'])
for tid, posts in forum.threads.iteritems():
rest, head = posts[:-1], posts[-1]
t = DM.ForumThread.new(
_id=tid,
discussion_id=f._id,
subject=head['subject'])
for p in posts:
p = create_post(f._id, t._id, p)
t.first_post_id = p._id
ThreadLocalORMSession.flush_all()
t.update_stats()
ThreadLocalORMSession.flush_all()
f.update_stats()
return warnings
def make_schema(user_name_map, default_username, warnings):
USER = AlluraUser(user_name_map, default_username, warnings)
TIMESTAMP = TimeStamp()
POST = {
'msg_id': str,
'is_followup_to': str,
'is_deleted': str,
'thread_id': str,
'poster_name': str,
'poster_user': USER,
'subject': str,
'date': TIMESTAMP,
'body': str,
}
FORUM = {
'name': str,
'description': str,
'threads': {str: [POST]},
}
result = S.SchemaItem.make({
'class': str,
'trackers': [None],
'forums': {str: FORUM}
})
return result
class AlluraUser(S.FancySchemaItem):
def __init__(self, mapping, default_username, warnings, **kw):
self.mapping = mapping
self.default_username = default_username
self.warnings = warnings
super(AlluraUser, self).__init__(**kw)
def _validate(self, value, **kw):
value = S.String().validate(value)
sf_username = self.mapping.get(value, value)
result = M.User.by_username(sf_username)
if result is None:
self.warnings.append('User %s not found' % value)
if callable(self.default_username):
sf_username = self.default_username(value)
else:
sf_username = self.default_username
self.warnings.append('... setting username to %r' % sf_username)
result = M.User.by_username(sf_username)
self.mapping[value] = sf_username
return result
def _from_python(self, value, state):
return value.username
class TimeStamp(S.FancySchemaItem):
def _validate(self, value, **kwargs):
try:
value = int(value)
except TypeError:
raise S.Invalid('%s is not int()-able' % value, value, None)
value = datetime.utcfromtimestamp(value)
return value
def create_user(json_username):
allura_username = c.project.shortname + '-' + json_username
while True:
try:
M.User.register(
dict(
username=allura_username,
display_name=allura_username),
False)
session(M.User).flush()
break
except:
raise
return allura_username
def create_post(discussion_id, thread_id, json_post):
p = DM.ForumPost(
_id='%s@import' % (json_post.msg_id),
thread_id=thread_id,
discussion_id=discussion_id,
timestamp=json_post.date,
author_id=json_post.poster_user._id,
text=json_post.body,
status='ok')
if json_post.is_followup_to not in ('0', '-1'):
p.parent_id = '%s@import' % (json_post['is_followup_to'])
return p