| 34 | | portal= portal_url.getPortalObject() |
| 35 | | |
| 36 | | updateAdmins(portal) |
| 37 | | updateBaseProperties(portal) |
| 38 | | updateCourses(portal) |
| 39 | | |
| 40 | | |
| 41 | | def updateAdmins(portal): |
| | 42 | portal= portal_url.getPortalObject() |
| | 43 | |
| | 44 | oldsite = getattr(portal.aq_parent, 'eduCommons') |
| | 45 | |
| | 46 | deleteDefaultContent(self, portal, out) |
| | 47 | copyZMIObjects(self, portal, oldsite, out) |
| | 48 | copyFolders(self, portal, oldsite, out) |
| | 49 | migrateTheme(self, portal, oldsite, out) |
| | 50 | migrateProperties(self, portal, oldsite, out) |
| | 51 | migrateUsers(self, portal, oldsite, out) |
| | 52 | updateAdmins(self, portal, oldsite, out) |
| | 53 | updateBaseProperties(self, portal, oldsite, out) |
| | 54 | #deleteOldSite(self, portal, oldsite, out) |
| | 55 | |
| | 56 | def deleteDefaultContent(self, portal, out): |
| | 57 | """ Remove default objects """ |
| | 58 | portal.manage_delObjects(['about', 'help', 'front-page']) |
| | 59 | print >> out, '<li>Deleted default content</li>\n' |
| | 60 | |
| | 61 | def copyZMIObjects(self, portal, oldsite, out): |
| | 62 | """ Copies old objects to new instace """ |
| | 63 | portal.MailHost = oldsite.MailHost |
| | 64 | portal.portal_skins.custom = oldsite.portal_skins.custom |
| | 65 | |
| | 66 | def copyFolders(self, portal, oldsite, out): |
| | 67 | """ Copies the top level folders from oldsite to portal """ |
| | 68 | |
| | 69 | folders = oldsite.portal_catalog.searchResults(Type='Folder', |
| | 70 | path={'query':'/', |
| | 71 | 'depth':2,}) |
| | 72 | print >> out, ' <li>Copying Folders</li>\n' |
| | 73 | print >> out, ' <ul>\n' |
| | 74 | |
| | 75 | for folder in folders: |
| | 76 | obj = folder.getObject() |
| | 77 | if obj.__annotations__.has_key('dept.text'): |
| | 78 | migrateDivision(self, portal, obj) |
| | 79 | else: |
| | 80 | co = oldsite.manage_copyObjects(obj.id) |
| | 81 | portal.manage_pasteObjects(co) |
| | 82 | setWorkflow(self, getattr(portal, obj.id), obj) |
| | 83 | print >> out, ' <li>Copied %s</li>\n' %obj.Title() |
| | 84 | print >> out, ' </ul>\n' |
| | 85 | print >> out, ' <li>Copied Content</li>\n' |
| | 86 | |
| | 87 | # Migrate other top level content |
| | 88 | |
| | 89 | objs = oldsite.portal_catalog.searchResults(portal_type=['File', 'Image', 'Document'], |
| | 90 | path={'query':'/', |
| | 91 | 'depth':2,}) |
| | 92 | obj_ids = [x.id for x in objs] |
| | 93 | co = oldsite.manage_copyObjects(obj_ids) |
| | 94 | portal.manage_pasteObjects(co) |
| | 95 | for x in obj_ids: |
| | 96 | obj = getattr(oldsite, x) |
| | 97 | newobj = getattr(portal, x) |
| | 98 | if x != 'front-page': |
| | 99 | newobj.setExcludeFromNav(True) |
| | 100 | if obj.__annotations__.has_key('review_state'): |
| | 101 | moveWorkflow(self, newobj, obj.__annotations__['review_state']) |
| | 102 | |
| | 103 | |
| | 104 | |
| | 105 | def migrateTheme(self, portal, oldsite, out): |
| | 106 | """ Delete default base_properties in portal and migrate oldsite base_properties """ |
| | 107 | if getattr(oldsite.portal_skins.custom, 'base_properties', None): |
| | 108 | old_custom = oldsite.portal_skins.custom |
| | 109 | new_custom = portal.portal_skins.custom |
| | 110 | new_custom.base_properties = old_custom.base_properties |
| | 111 | print >> out, ' <li>Migrated theme</li>\n' |
| | 112 | |
| | 113 | |
| | 114 | def migrateProperties(self, portal, oldsite, out): |
| | 115 | """ Transfer old properties to new """ |
| | 116 | #Migrate eduCommons Properties |
| | 117 | old_ec_props = oldsite.portal_properties.educommons_properties |
| | 118 | new_ec_props = portal.portal_properties.educommons_properties |
| | 119 | for prop in old_ec_props.propertyMap(): |
| | 120 | #Overwrite default new values with default old values |
| | 121 | if prop['id'] in new_ec_props.propertyIds(): |
| | 122 | id = prop['id'] |
| | 123 | key_value = {id : old_ec_props.getProperty(id) } |
| | 124 | new_ec_props.manage_changeProperties(**key_value) |
| | 125 | #Add properties if they don't exist in new |
| | 126 | else: |
| | 127 | id = prop['id'] |
| | 128 | type = prop['type'] |
| | 129 | value = old_ec_props.getProperty(id) |
| | 130 | new_ec_props.manage_addProperty(id=id, type=type, value=value) |
| | 131 | |
| | 132 | print >> out, ' <li>Migrated eduCommons Properties</li>\n' |
| | 133 | |
| | 134 | #Migrate ContentLicensing Propertiese |
| | 135 | old_cl_props = oldsite.portal_properties.content_licensing_properties |
| | 136 | new_cl_props = portal.portal_properties.content_licensing_properties |
| | 137 | for prop in old_cl_props.propertyMap(): |
| | 138 | #Overwrite default new values with default old values |
| | 139 | if prop['id'] in new_cl_props.propertyIds(): |
| | 140 | id = prop['id'] |
| | 141 | if id != 'Jurisdiction': |
| | 142 | key_value = {id : old_cl_props.getProperty(id) } |
| | 143 | new_cl_props.manage_changeProperties(**key_value) |
| | 144 | else: |
| | 145 | for value in new_cl_props.jurisdiction_options: |
| | 146 | if old_cl_props.getProperty(id) in value: |
| | 147 | new_cl_props.manage_changeProperties(Jurisdiction=value) |
| | 148 | #Add properties if they don't exist in new |
| | 149 | else: |
| | 150 | id = prop['id'] |
| | 151 | type = prop['type'] |
| | 152 | value = old_cl_props.getProperty(id) |
| | 153 | new_cl_props.manage_addProperty(id=id, type=type, value=value) |
| | 154 | |
| | 155 | print >> out, ' <li>Migrated ContentLicensing Properties</li>\n' |
| | 156 | |
| | 157 | #Migrate relevant old site properties |
| | 158 | old_site_props = oldsite.portal_properties.migrateable_properties |
| | 159 | portal.manage_changeProperties(title=old_site_props.site_title, |
| | 160 | description=old_site_props.description, |
| | 161 | email_from_address=old_site_props.email_from_address, |
| | 162 | email_from_name=old_site_props.email_from_name |
| | 163 | ) |
| | 164 | |
| | 165 | print >> out, ' <li>Migrated Site properties</li>\n' |
| | 166 | |
| | 167 | |
| | 168 | |
| | 169 | def migrateUsers(self, portal, oldsite, out): |
| | 170 | """ Migrate Users """ |
| | 171 | old_users = oldsite.acl_users.manage_copyObjects(['local_roles', |
| | 172 | 'mutable_properties', |
| | 173 | 'portal_role_manager', |
| | 174 | 'source_groups', |
| | 175 | 'source_users']) |
| | 176 | portal.acl_users.manage_delObjects(['local_roles', |
| | 177 | 'mutable_properties', |
| | 178 | 'portal_role_manager', |
| | 179 | 'source_groups', |
| | 180 | 'source_users']) |
| | 181 | portal.acl_users.manage_pasteObjects(old_users) |
| | 182 | |
| | 183 | #Activate plugins for each copied object |
| | 184 | acl_users = portal.acl_users |
| | 185 | acl_users.local_roles.manage_activateInterfaces(['ILocalRolesPlugin', |
| | 186 | 'IRolesPlugin']) |
| | 187 | acl_users.mutable_properties.manage_activateInterfaces(['IPropertiesPlugin', |
| | 188 | 'IUserEnumerationPlugin']) |
| | 189 | acl_users.portal_role_manager.manage_activateInterfaces(['IRoleAssignerPlugin', |
| | 190 | 'IRoleEnumerationPlugin', |
| | 191 | 'IRolesPlugin']) |
| | 192 | acl_users.source_groups.manage_activateInterfaces(['IGroupEnumerationPlugin', |
| | 193 | 'IGroupIntrospection', |
| | 194 | 'IGroupManagement', |
| | 195 | 'IGroupsPlugin']) |
| | 196 | acl_users.source_users.manage_activateInterfaces(['IAuthenticationPlugin', |
| | 197 | 'IUserAdderPlugin', |
| | 198 | 'IUserEnumerationPlugin', |
| | 199 | 'IUserIntrospection', |
| | 200 | 'IUserManagement']) |
| | 201 | |
| | 202 | old_pgd = oldsite.portal_groupdata |
| | 203 | portal.portal_groupdata = old_pgd |
| | 204 | |
| | 205 | old_pmd = oldsite.portal_memberdata |
| | 206 | portal.portal_memberdata = old_pmd |
| | 207 | |
| | 208 | #Set all users default editor to Kupu |
| | 209 | users = portal.acl_users.getUsers() |
| | 210 | for user in users: |
| | 211 | user.setProperties(wysiwyg_editor = 'Kupu') |
| | 212 | |
| | 213 | print >> out, ' <li>Migrated Users</li>\n' |
| | 214 | |
| | 215 | |
| | 216 | def updateAdmins(self, portal, oldsite, out): |
| 65 | | def updateCourses(portal): |
| 66 | | """ Convert existent zipped course downloads to new Common Cartridge based package """ |
| 67 | | |
| 68 | | course_brains = portal.portal_catalog(path= {'query':'/'.join(portal.getPhysicalPath())+'/'}, portal_type='Course') |
| 69 | | |
| 70 | | for course in course_brains: |
| 71 | | course = course.getObject() |
| 72 | | |
| 73 | | #repackage Download this Course object for existent courses |
| 74 | | zip_exists = 0 |
| 75 | | for object in course.listFolderContents(): |
| 76 | | if 'download this course' == string.lower(object.Title()): |
| 77 | | #delete object, repackage as FSS based IMS package |
| 78 | | zip_exists = 1 |
| 79 | | course.manage_delObjects([object.getId()]) |
| 80 | | |
| 81 | | if zip_exists == 1: |
| 82 | | file_id = course.id + '.zip' |
| 83 | | |
| 84 | | ims_util = getUtility(IIMSTransportUtility) |
| 85 | | data, course = ims_util.exportPackage(course, file_id, packagetype='IMS Common Cartridge') |
| 86 | | |
| 87 | | course.invokeFactory("FSSFile",id=file_id, title="Download this Course") |
| 88 | | fileobj = getattr(course,file_id) |
| 89 | | publishObject(fileobj) |
| 90 | | fileobj.setTitle("Download This Course") |
| 91 | | |
| 92 | | fileobj.setFile(data) |
| 93 | | appendObjPosition(fileobj) |
| 94 | | |
| 95 | | course.portal_catalog.reindexObject(fileobj) |
| | 240 | def repackageCourse(self, course): |
| | 241 | """ Convert existent zipped course downloads to new Common Cartridge based package """ |
| | 242 | file_id = course.id + '.zip' |
| | 243 | |
| | 244 | ims_util = getUtility(IIMSTransportUtility) |
| | 245 | data, course = ims_util.exportPackage(course, file_id, packagetype='IMS Common Cartridge') |
| | 246 | |
| | 247 | course.invokeFactory("FSSFile",id=file_id, title="Download this Course") |
| | 248 | fileobj = getattr(course,file_id) |
| | 249 | publishObject(fileobj) |
| | 250 | fileobj.setTitle("Download This Course") |
| | 251 | |
| | 252 | fileobj.setFile(data) |
| | 253 | fileobj.setExcludeFromNav(True) |
| | 254 | appendObjPosition(fileobj) |
| | 255 | |
| | 256 | course.portal_catalog.reindexObject(fileobj) |
| | 257 | |
| | 258 | def deleteOldSite(self, portal, oldsite, out): |
| | 259 | """ Remove the old site """ |
| | 260 | app = self.aq_parent.aq_parent |
| | 261 | app.manage_delObjects(oldsite.getId()) |
| | 262 | app.manage_renameObject(portal.getId(), 'eduCommons', REQUEST=None) |
| | 263 | |
| | 264 | print >> out, '</ul>\n' |
| | 265 | print >> out, 'Done.\n' |
| | 266 | return out.getvalue() |
| 107 | | |
| 108 | | |
| 109 | | |
| | 278 | def migrateDivision(self, portal, dobj): |
| | 279 | """ Migrate a division from the old site to the new. """ |
| | 280 | # Create a new division |
| | 281 | _createObjectByType('Division', |
| | 282 | portal, |
| | 283 | id=dobj.getId(), |
| | 284 | title=dobj.Title(), |
| | 285 | description=dobj.Description(), |
| | 286 | subject=dobj.Subject(), |
| | 287 | contributors=dobj.Contributors(), |
| | 288 | creators=dobj.Creators(), |
| | 289 | language=dobj.Language(), |
| | 290 | rights=dobj.Rights(), |
| | 291 | creation_date=dobj.CreationDate(), |
| | 292 | ) |
| | 293 | # Copy over remaining division attributes |
| | 294 | div = getattr(portal, dobj.getId()) |
| | 295 | div.setText(dobj.__annotations__['dept.text']) |
| | 296 | #div.syndication_information = dobj.syndication_information |
| | 297 | for x in dobj.__annotations__.keys(): |
| | 298 | if 'review_state' == x: |
| | 299 | moveWorkflow(self, div, dobj.__annotations__[x]) |
| | 300 | if x != 'dept.text': |
| | 301 | div.__annotations__[x] = dobj.__annotations__[x] |
| | 302 | |
| | 303 | # Copy Course sub objects |
| | 304 | oc = [] |
| | 305 | for oid,obj in dobj.objectItems(): |
| | 306 | if 'Folder' == obj.Type(): |
| | 307 | ann = getattr(obj, '__annotations__', None) |
| | 308 | if ann and ann.has_key('course.text'): |
| | 309 | migrateCourse(self, div, obj) |
| | 310 | elif oid != 'syndication_information': |
| | 311 | oc.append(oid) |
| | 312 | else: |
| | 313 | oc.append(oid) |
| | 314 | |
| | 315 | # Copy all other sub objects |
| | 316 | co = dobj.manage_copyObjects(oc) |
| | 317 | div.manage_pasteObjects(co) |
| | 318 | |
| | 319 | for oid,obj in div.objectItems(): |
| | 320 | if 'Course' != obj.Type() and 'syndication_information' != oid: |
| | 321 | moveWorkflow(self, obj, getattr(dobj, oid).__annotations__['review_state']) |
| | 322 | obj.workflow_history = getattr(dobj, oid).workflow_history |
| | 323 | |
| | 324 | def migrateCourse(self, div, cobj): |
| | 325 | """ Migrate a course from the old site to the new. """ |
| | 326 | |
| | 327 | # Create a new course |
| | 328 | _createObjectByType('Course', |
| | 329 | div, |
| | 330 | id=cobj.getId(), |
| | 331 | title=cobj.Title(), |
| | 332 | description=cobj.Description(), |
| | 333 | subject=cobj.Subject(), |
| | 334 | contributors=cobj.Contributors(), |
| | 335 | creators=cobj.Creators(), |
| | 336 | language=cobj.Language(), |
| | 337 | rights=cobj.Rights(), |
| | 338 | creation_date=cobj.CreationDate(), |
| | 339 | ) |
| | 340 | |
| | 341 | # Copy over remaining course attributes |
| | 342 | course = getattr(div, cobj.getId()) |
| | 343 | course.setText(cobj.__annotations__['course.text']) |
| | 344 | a2f = {'course.term':'term', |
| | 345 | 'course.courseid':'courseId', |
| | 346 | 'course.instructorname':'instructorName', |
| | 347 | 'course.instructor_principal':'instructorAsCreator', |
| | 348 | 'course.instructoremail':'instructorEmail', |
| | 349 | 'course.displayInstructorEmail':'displayInstEmail', |
| | 350 | 'course.structure':'structure', |
| | 351 | 'course.level':'level', |
| | 352 | 'course.crosslisting':'crosslisting'} |
| | 353 | |
| | 354 | for x in cobj.__annotations__: |
| | 355 | if x in a2f: |
| | 356 | mut = course.getField(a2f[x]).getMutator(course) |
| | 357 | mut(cobj.__annotations__[x]) |
| | 358 | elif 'review_state' == x: |
| | 359 | moveWorkflow(self, course, cobj.__annotations__[x]) |
| | 360 | else: |
| | 361 | course.__annotations__[x] = cobj.__annotations__[x] |
| | 362 | |
| | 363 | #ensure course has 0 position |
| | 364 | course.__annotations__['eduCommons.objPositionInCourse'] = 0 |
| | 365 | |
| | 366 | #ensure portlets exist on courses |
| | 367 | rightColumn = getUtility(IPortletManager, name=u'plone.rightcolumn', context=course) |
| | 368 | right = getMultiAdapter((course, rightColumn), IPortletAssignmentMapping, context=course) |
| | 369 | |
| | 370 | #This code breaks the course object when the server has no outbound access to the web |
| | 371 | if u'OER Recommender' not in right: |
| | 372 | right[u'OER Recommender'] = portlet.oerrecommenderportlet.Assignment() |
| | 373 | |
| | 374 | if u'Course Summary' not in right: |
| | 375 | right[u'Course Summary'] = portlet.courseinfoportlet.Assignment() |
| | 376 | |
| | 377 | if u'Reuse Course' not in right: |
| | 378 | right[u'Reuse Course'] = portlet.reusecourseportlet.Assignment() |
| | 379 | |
| | 380 | # Copy Course Objects |
| | 381 | ids = cobj.objectIds() |
| | 382 | |
| | 383 | if 'syndication_information' in ids: |
| | 384 | ids.remove('syndication_information') |
| | 385 | |
| | 386 | # don't copy course download |
| | 387 | zip = cobj.getId() + '.zip' |
| | 388 | if zip in ids: |
| | 389 | ids.remove(zip) |
| | 390 | |
| | 391 | co = cobj.manage_copyObjects(ids) |
| | 392 | |
| | 393 | course.manage_pasteObjects(co) |
| | 394 | #ensure each object has correct position in course |
| | 395 | for oid in ids: |
| | 396 | olditem = getattr(cobj, oid) |
| | 397 | if olditem.__annotations__.has_key('eduCommons.objPositionInCourse'): |
| | 398 | pos = olditem.__annotations__['eduCommons.objPositionInCourse'] |
| | 399 | |
| | 400 | newitem = getattr(course, oid) |
| | 401 | newitem.__annotations__['eduCommons.objPositionInCourse'] = pos |
| | 402 | |
| | 403 | setWorkflow(self, course, cobj) |
| | 404 | #If the course package existed, repackage |
| | 405 | if zip in cobj.objectIds(): |
| | 406 | repackageCourse(self, course) |
| | 407 | |
| | 408 | |
| | 409 | def setWorkflow(self, new, old, omappings={}, retainHistory=True): |
| | 410 | for oldid,olditem in old.objectItems(): |
| | 411 | zip = new.id + '.zip' |
| | 412 | if oldid in omappings: |
| | 413 | oldid = omappings[oldid] |
| | 414 | if oldid != zip: |
| | 415 | newitem = getattr(new.aq_explicit, oldid) |
| | 416 | try: |
| | 417 | if olditem.__annotations__.has_key('review_state'): |
| | 418 | moveWorkflow(self, newitem, olditem.__annotations__['review_state']) |
| | 419 | if retainHistory: |
| | 420 | newitem.workflow_history = olditem.workflow_history |
| | 421 | if 'Folder' == olditem.Type(): |
| | 422 | setWorkflow(self, newitem, olditem) |
| | 423 | else: |
| | 424 | state = olditem.portal_workflow.getInfoFor(olditem, 'review_state') |
| | 425 | moveWorkflow(self, newitem, state) |
| | 426 | if retainHistory: |
| | 427 | newitem.workflow_history = olditem.workflow_history |
| | 428 | if 'Folder' == olditem.Type(): |
| | 429 | setWorkflow(self, newitem, olditem) |
| | 430 | |
| | 431 | except AttributeError: |
| | 432 | pass |
| | 433 | |
| | 434 | |
| | 435 | def moveWorkflow(self, newobj, ostate): |
| | 436 | wt = newobj.portal_workflow |
| | 437 | nstate = wt.getInfoFor(newobj, 'review_state') |
| | 438 | result = False |
| | 439 | if 'Visible' == ostate: |
| | 440 | ostate = 'Published' |
| | 441 | if nstate == ostate: |
| | 442 | result = True |
| | 443 | elif 'InProgress' == nstate: |
| | 444 | wt.doActionFor(newobj, 'submit', comment='', include_subfolders=False) |
| | 445 | result = moveWorkflow(self, newobj, ostate) |
| | 446 | elif 'QA' == nstate: |
| | 447 | wt.doActionFor(newobj, 'release', comment='', include_subfolders=False) |
| | 448 | result = moveWorkflow(self, newobj, ostate) |
| | 449 | elif 'Released' == nstate: |
| | 450 | wt.doActionFor(newobj, 'publish', comment='', include_subfolders=False) |
| | 451 | result = moveWorkflow(self, newobj, ostate) |
| | 452 | elif 'Published' == nstate: |
| | 453 | result = True |
| | 454 | return result |
| | 455 | |
| | 456 | |
| | 457 | |