2011-09-26 14:19:34 -05:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
import time
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
class Migrator:
|
|
|
|
'''This class is responsible for performing migrations, when, on
|
|
|
|
installation, we've detected a new Appy version.'''
|
|
|
|
def __init__(self, installer):
|
|
|
|
self.installer = installer
|
2012-02-02 10:30:54 -06:00
|
|
|
self.logger = installer.logger
|
|
|
|
self.app = installer.app
|
2011-09-26 14:19:34 -05:00
|
|
|
|
2012-02-02 10:30:54 -06:00
|
|
|
bypassRoles = ('Authenticated', 'Member')
|
|
|
|
bypassGroups = ('Administrators', 'Reviewers')
|
|
|
|
def migrateUsers(self, ploneSite):
|
|
|
|
'''Migrate users from Plone's acl_users to Zope acl_users with
|
|
|
|
corresponding Appy objects.'''
|
|
|
|
# First of all, remove the Plone-patched root acl_users by a standard
|
|
|
|
# (hum, Appy-patched) Zope UserFolder.
|
|
|
|
tool = self.app.config.appy()
|
|
|
|
from AccessControl.User import manage_addUserFolder
|
|
|
|
self.app.manage_delObjects(ids=['acl_users'])
|
|
|
|
manage_addUserFolder(self.app)
|
|
|
|
# Put an admin user into it
|
|
|
|
newUsersDb = self.app.acl_users
|
|
|
|
newUsersDb._doAddUser('admin', 'admin', ['Manager'], ())
|
|
|
|
# Copy users from Plone acl_users to Zope acl_users
|
|
|
|
for user in ploneSite.acl_users.getUsers():
|
|
|
|
id = user.getId()
|
|
|
|
userRoles = user.getRoles()
|
|
|
|
for br in self.bypassRoles:
|
|
|
|
if br in userRoles: userRoles.remove(br)
|
|
|
|
userInfo = ploneSite.portal_membership.getMemberById(id)
|
|
|
|
userName = userInfo.getProperty('fullname') or id
|
|
|
|
userEmail = userInfo.getProperty('email') or ''
|
|
|
|
appyUser = tool.create('users', login=id,
|
|
|
|
password1='fake', password2='fake', roles=userRoles,
|
|
|
|
name=userName, firstName=' ', email=userEmail)
|
|
|
|
appyUser.title = appyUser.title.strip()
|
|
|
|
# Set the correct password
|
|
|
|
password = ploneSite.acl_users.source_users._user_passwords[id]
|
|
|
|
newUsersDb.data[id].__ = password
|
|
|
|
# Manage groups. Exclude not-used default Plone groups.
|
|
|
|
for groupId in user.getGroups():
|
|
|
|
if groupId in self.bypassGroups: continue
|
2012-05-05 10:04:19 -05:00
|
|
|
if tool.count('Group', noSecurity=True, login=groupId):
|
2012-02-02 10:30:54 -06:00
|
|
|
# The Appy group already exists, get it
|
2012-05-05 10:04:19 -05:00
|
|
|
appyGroup = tool.search('Group', noSecurity=True,
|
|
|
|
login=groupId)[0]
|
2012-02-02 10:30:54 -06:00
|
|
|
else:
|
|
|
|
# Create the group. Todo: get Plone group roles and title
|
|
|
|
appyGroup = tool.create('groups', login=groupId,
|
|
|
|
title=groupId)
|
|
|
|
appyGroup.addUser(appyUser)
|
|
|
|
|
|
|
|
def reindexObject(self, obj):
|
|
|
|
obj.reindex()
|
|
|
|
i = 1
|
|
|
|
for subObj in obj.objectValues():
|
|
|
|
i += self.reindexObject(subObj)
|
|
|
|
return i # The number of reindexed (sub-)object(s)
|
|
|
|
|
|
|
|
def migrateTo_0_8_0(self):
|
|
|
|
'''Migrates a Plone-based (<= 0.7.1) Appy app to a Ploneless (0.8.0)
|
|
|
|
Appy app.'''
|
|
|
|
self.logger.info('Migrating to Appy 0.8.0...')
|
|
|
|
# Find the Plone site. It must be at the root of the Zope tree.
|
|
|
|
ploneSite = None
|
|
|
|
for obj in self.app.objectValues():
|
|
|
|
if obj.__class__.__name__ == 'PloneSite':
|
|
|
|
ploneSite = obj
|
|
|
|
break
|
|
|
|
# As a preamble: delete translation objects from self.app.config: they
|
|
|
|
# will be copied from the old tool.
|
|
|
|
self.app.config.manage_delObjects(ids=self.app.config.objectIds())
|
|
|
|
# Migrate data objects:
|
|
|
|
# - from oldDataFolder to self.app.data
|
|
|
|
# - from oldTool to self.app.config (excepted translation
|
|
|
|
# objects that were re-created from i18n files).
|
|
|
|
appName = self.app.config.getAppName()
|
|
|
|
for oldFolderName in (appName, 'portal_%s' % appName.lower()):
|
|
|
|
oldFolder = getattr(ploneSite, oldFolderName)
|
|
|
|
objectIds = [id for id in oldFolder.objectIds()]
|
|
|
|
cutted = oldFolder.manage_cutObjects(ids=objectIds)
|
|
|
|
if oldFolderName == appName:
|
|
|
|
destFolder = self.app.data
|
|
|
|
else:
|
|
|
|
destFolder = self.app.config
|
|
|
|
destFolder.manage_pasteObjects(cutted)
|
|
|
|
i = 0
|
|
|
|
for obj in destFolder.objectValues():
|
|
|
|
i += self.reindexObject(obj)
|
|
|
|
self.logger.info('%d objects imported into %s.' % \
|
|
|
|
(i, destFolder.getId()))
|
|
|
|
if oldFolderName != appName:
|
|
|
|
# Re-link objects copied into the self.app.config with the Tool
|
|
|
|
# through Ref fields.
|
|
|
|
tool = self.app.config.appy()
|
|
|
|
pList = tool.o.getProductConfig().PersistentList
|
|
|
|
for field in tool.fields:
|
|
|
|
if field.type != 'Ref': continue
|
|
|
|
n = field.name
|
|
|
|
if n in ('users', 'groups'): continue
|
|
|
|
uids = getattr(oldFolder, n)
|
|
|
|
if uids:
|
|
|
|
# Update the forward reference
|
|
|
|
setattr(tool.o, n, pList(uids))
|
|
|
|
# Update the back reference
|
|
|
|
for obj in getattr(tool, n):
|
|
|
|
backList = getattr(obj.o, field.back.name)
|
|
|
|
backList.remove(oldFolder._at_uid)
|
|
|
|
backList.append(tool.uid)
|
|
|
|
self.logger.info('config.%s: linked %d object(s)' % \
|
|
|
|
(n, len(uids)))
|
2011-09-26 14:19:34 -05:00
|
|
|
else:
|
2012-02-02 10:30:54 -06:00
|
|
|
self.logger.info('config.%s: no object to link.' % n)
|
|
|
|
self.migrateUsers(ploneSite)
|
|
|
|
self.logger.info('Migration done.')
|
2011-09-26 14:19:34 -05:00
|
|
|
|
|
|
|
def run(self):
|
2012-02-02 10:30:54 -06:00
|
|
|
if self.app.acl_users.__class__.__name__ == 'UserFolder':
|
|
|
|
return # Already Ploneless
|
|
|
|
tool = self.app.config.appy()
|
|
|
|
appyVersion = tool.appyVersion
|
|
|
|
if not appyVersion or (appyVersion < '0.8.0'):
|
|
|
|
# Migration is required.
|
|
|
|
startTime = time.time()
|
|
|
|
self.migrateTo_0_8_0()
|
|
|
|
stopTime = time.time()
|
|
|
|
elapsed = (stopTime-startTime) / 60.0
|
|
|
|
self.logger.info('Migration done in %d minute(s).' % elapsed)
|
2011-09-26 14:19:34 -05:00
|
|
|
# ------------------------------------------------------------------------------
|