root/CPS3/legacy/CPSIO/trunk/export_modules/Plone2Exporter.py

Revision 11029, 19.9 kB (checked in by sfermigier, 4 years ago)

Coding style / unused imports.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 # (C) Copyright 2004 Nuxeo SARL <http://nuxeo.com>
2 # Author: Emmanuel Pietriga <ep@nuxeo.com>
3 #
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License version 2 as published
6 # by the Free Software Foundation.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
16 # 02111-1307, USA.
17 #
18 # $Id$
19
20 from Globals import InitializeClass
21
22 from Products.CMFCore.permissions import ManagePortal
23 from Products.CPSIO.BaseExporter import BaseExporter
24 from Products.CPSIO.IOBase import IOBase
25
26 from AccessControl import ClassSecurityInfo
27
28 from elementtree.ElementTree import ElementTree, Element, SubElement
29
30 import os
31 from types import ListType, TupleType
32
33 from zLOG import LOG, DEBUG, INFO, WARNING, ERROR
34
35 MAIN_NAMESPACE_URI = 'http://www.nuxeo.com/2004/06/'
36
37 class Exporter(BaseExporter):
38
39     options_template = 'plone2exporter_form'
40
41     security = ClassSecurityInfo()
42     security.declareObjectPublic()
43
44     __roles__ = None
45     __allow_access_to_unprotected_subobjects__ = 1
46
47     def __init__(self, portal):
48         self.portal = portal
49         self.ns_uri = MAIN_NAMESPACE_URI + 'cps3#'
50
51     security.declareProtected(ManagePortal, 'export')
52     def exportFile(self):
53         """Main Export"""
54
55         self.log("Exporting to file " + self.file_path)
56         LOG("Exporting to file ", DEBUG, self.file_path)
57         root = self.buildTree()
58         if 'export_portal_types' in self.options:
59             file_name = PortalTypeExporter(self.portal, self.dir_name).exportFile()
60             el = SubElement(root, "{%s}cpsportaltypes" % self.ns_uri)
61             el.set('ref', file_name)
62         if 'export_workflows' in self.options:
63             file_name = WorkflowExporter(self.portal, self.dir_name).exportFile()
64             el = SubElement(root, "{%s}cpsworkflows" % self.ns_uri)
65             el.set('ref', file_name)
66         if ('export_hierarchy' in self.options or
67             'export_documents' in self.options):
68             ehms = [item for item in self.options if item.startswith('export_hierarchy_')]
69             if ehms:
70                 ehm = ehms[0][17:]
71             else:
72                 ehm = None
73             file_name = HierarchyExporter(self.portal, self.dir_name, ehm).exportFile()
74             el = SubElement(root, "{%s}cpshierarchy" % self.ns_uri)
75             el.set('ref', file_name)
76         doc = ElementTree(root)
77         doc.write(self.file_path, encoding="iso-8859-15")
78
79         self.archiveExport()
80
81     def buildTree(self):
82         root = Element("{%s}cpsdefinitions" % self.ns_uri)
83         return root
84
85
86 InitializeClass(Exporter)
87
88 #
89 # CMF/Plone 2 Portal Type Exporter
90 #
91 class PortalTypeExporter(IOBase):
92
93     def __init__(self, portal, dir_name):
94         self.portal = portal
95         self.pt_tool = self.portal.portal_types
96         self.file_name = 'portal_types'
97         self.file_path = os.path.join(CLIENT_HOME, dir_name, self.file_name)
98         self.ns_uri = MAIN_NAMESPACE_URI + 'cpsportaltypes#'
99
100     def exportFile(self):
101         """Export portal types"""
102
103         self.log("Exporting portal types to file " + self.file_path)
104         LOG("Exporting portal types to file", DEBUG, self.file_path)
105
106         root = self.buildTree()
107         doc = ElementTree(root)
108         doc.write(self.file_path, encoding="iso-8859-15")
109         return self.file_name
110
111     def buildTree(self):
112         """Build the elementtree representing all FTIs"""
113
114         root = Element("{%s}portalTypes" % self.ns_uri)
115
116         for pt_id, pt in self.pt_tool.objectItems():
117             el = self.exportCMFFTI(pt_id, pt, root)
118
119         return root
120
121     def exportCMFFTI(self, pt_id, fti, parent):
122         """Build an elementtree representation of a Factory-based Type
123         Information object"""
124
125         el = SubElement(parent, "{%s}cmffti" % self.ns_uri)
126         el.set('id', pt_id)
127         # process properties
128         for prop in self._getFTIProperties(fti):
129             # export some properties as attributes
130             if prop[0] in ('content_icon', 'content_meta_type', 'product',
131                            'factory', 'immediate_view', 'global_allow',
132                            'filter_content_types', 'allow_discussion'):
133                 if prop[1] is not None:
134                     el.set(prop[0], str(prop[1]))
135                 else:
136                     el.set(prop[0], '')
137             # export all other as elements - this includes the ones
138             # we do not know anything about
139             else:
140                 el2 = SubElement(el, "{%s}%s" % (self.ns_uri, prop[0]))
141                 if isinstance(prop[1], ListType) or isinstance(prop[1], TupleType):
142                     el2.text = ','.join([token for token in prop[1]])
143                 else:
144                     el2.text = str(prop[1])
145                 el2.set('type', type(prop[1]).__name__)
146
147         # process actions
148         self.exportActions(fti, el)
149         return el
150
151     def exportActions(self, fti, parent):
152         """Process actions associated with an FTI"""
153
154         el = SubElement(parent, "{%s}actions" % self.ns_uri)
155         for action in self._getActions(fti):
156             el2 = SubElement(el, "{%s}action" % self.ns_uri)
157             el2.set('id', action.getId())
158             el2.set('name', action.Title())
159             el2.set('category', action.getCategory())
160             if action.getVisibility():
161                 el2.set('visibility', '1')
162             else:
163                 el2.set('visibility', '0')
164             el3 = SubElement(el2, "{%s}expression" % self.ns_uri)
165             el3.text = action.getActionExpression()
166             if action.getCondition():
167                 el3 = SubElement(el2, "{%s}condition" % self.ns_uri)
168                 el3.text = action.getCondition()
169             perms = action.getPermissions()
170             if len(perms) and perms[0]:
171                 # no permissions <=> perms = ('',)
172                 el3 = SubElement(el2, "{%s}permission" % self.ns_uri)
173                 el3.text = ','.join([token for token in action.getPermissions()])
174
175     def _getFTIProperties(self, fti):
176         """Get all properties of a given FTI"""
177
178         return fti.propertyItems()
179
180     def _getActions(self, fti):
181         """Get action definitions (python ds)"""
182
183         return fti.listActions()
184
185 #
186 # CMF/Plone 2 Workflow Exporter
187 #
188 class WorkflowExporter(IOBase):
189
190     def __init__(self, portal, dir_name):
191         self.portal = portal
192         self.wtool = self.portal.portal_workflow
193         self.pt_tool = self.portal.portal_types
194         self.file_name = 'workflows'
195         self.file_path = os.path.join(CLIENT_HOME, dir_name, self.file_name)
196         self.ns_uri = MAIN_NAMESPACE_URI + 'cpsworkflows#'
197
198     def exportFile(self):
199         """Export workflows"""
200
201         self.log("Exporting workflows to file " + self.file_path)
202         LOG("Exporting workflows to file", DEBUG, self.file_path)
203
204         root = self.buildTree()
205         doc = ElementTree(root)
206         doc.write(self.file_path, encoding="iso-8859-15")
207         return self.file_name
208
209     def buildTree(self):
210         """Build the elementtree representing all workflows"""
211
212         root = Element("{%s}workflows" % self.ns_uri)
213
214         # first, get chains at the portal_work level
215         el = SubElement(root, "{%s}globalChains" % self.ns_uri)
216         for portal_type in self.pt_tool.objectIds():
217             chain = list(self.wtool.getChainFor(portal_type))
218             if chain:
219                 el2 = SubElement(el, "{%s}globalChain" % self.ns_uri)
220                 el2.set('chain', ','.join(chain))
221                 el2.set('portal_type', portal_type)
222
223         el = SubElement(root, "{%s}workflowDefinitions" % self.ns_uri)
224         for wf_id, wf in self.wtool.objectItems():
225             self.buildWorkflow(wf_id, wf, el)
226         # provide trigger type mapping in case constant values change
227         # in the code
228         el = SubElement(root, "{%s}triggerTypes" % self.ns_uri)
229         from Products.DCWorkflow import Transitions
230         for trigger_type in [attr for attr in Transitions.__dict__.keys()
231                              if attr.startswith('TRIGGER_')]:
232             el2 = SubElement(el, "{%s}triggerType" % self.ns_uri)
233             el2.set('name', trigger_type)
234             el2.set('ref', str(getattr(Transitions, trigger_type)))
235         # there are no transition behaviors in CMF/Plone, but this
236         # is a required element of the relax-ng schema
237         el = SubElement(root, "{%s}transitionBehaviors" % self.ns_uri)
238         return root
239
240     def buildWorkflow(self, wf_id, workflow, parent):
241         """Build an elementtree representation of a workflow"""
242
243         el = SubElement(parent, "{%s}workflow" % self.ns_uri)
244         el.set('id', wf_id)
245         el.set('title', workflow.title)
246         if workflow.state_var:
247             el.set('state_variable', workflow.state_var)
248         if workflow.permissions:
249             el.set('permissions', ','.join(list(workflow.permissions)))
250
251         self.buildStates(workflow.states.objectValues(), el)
252         self.buildTransitions(workflow.transitions.objectValues(), el)
253         self.buildScripts(workflow.scripts.objectValues(), el)
254         self.buildVariables(workflow.variables.objectValues(), el)
255
256     def buildStates(self, states, parent):
257         """Build an elementtree representation of a workflow's states"""
258
259         el = SubElement(parent, "{%s}states" % self.ns_uri)
260         for state in states:
261             el2 = SubElement(el, "{%s}state" % self.ns_uri)
262             el2.set('id', state.id)
263             el2.set('title', state.title)
264             el2.set('description', state.description)
265             if state.transitions:
266                 el2.set('allowedTransitions', ','.join(list(state.transitions)))
267             if state.permissions:
268                 el3 = SubElement(el2, "{%s}permissions" % self.ns_uri)
269                 for permission in state.permissions:
270                     el4 = SubElement(el3, "{%s}permission" % self.ns_uri)
271                     el4.set('title', permission)
272                     perm_info = state.getPermissionInfo(permission)
273                     el4.set('acquired', str(perm_info.get('acquired', 1)))
274                     roles = perm_info.get('roles', [])
275                     if roles:
276                         el4.set('roles', ','.join(roles))
277             if state.var_values:
278                 el3 = SubElement(el2, "{%s}variableValues" % self.ns_uri)
279                 for var_name, var_value in state.var_values.items():
280                     el4 = SubElement(el3, "{%s}variableValue" % self.ns_uri)
281                     el4.set('name', str(var_name))
282                     el4.set('value', str(var_value))
283                     el4.set('type', type(var_value).__name__)
284
285     def buildTransitions(self, transitions, parent):
286         """Build an elementtree representation of a workflow's transitions"""
287
288         el = SubElement(parent, "{%s}transitions" % self.ns_uri)
289
290         for transition in transitions:
291             el2 = SubElement(el, "{%s}transition" % self.ns_uri)
292             el2.set('id',transition.getId())
293             # DCWorkflow Transition data
294             el2.set('title', transition.title)
295             el2.set('description', transition.description)
296             el2.set('new_state_id', transition.new_state_id)
297             # trigger_type is an int
298             el2.set('trigger_type', str(transition.trigger_type))
299             if transition.actbox_name:
300                 el2.set('actbox_name', transition.actbox_name)
301             if transition.actbox_url:
302                 el2.set('actbox_url', transition.actbox_url)
303             if transition.actbox_category:
304                 el2.set('actbox_category', transition.actbox_category)
305             if transition.script_name:
306                 el2.set('script_name', transition.script_name)
307             if transition.after_script_name:
308                 el2.set('after_script_name', transition.after_script_name)
309             guard = transition.getGuard()
310             g_permissions = guard.getPermissionsText()
311             g_roles = guard.getRolesText()
312             g_expression = guard.getExprText()
313             if g_permissions or g_roles or g_expression:
314                 el3 = SubElement(el2, "{%s}guard" % self.ns_uri)
315                 if g_permissions:
316                     el3.set('permissions', g_permissions)
317                 if g_roles:
318                     el3.set('roles', g_roles)
319                 if g_expression:
320                     el3.set('expr', g_expression)
321
322     def buildScripts(self, scripts, parent):
323         """Build an elementtree representation of a workflow's scripts"""
324
325         el = SubElement(parent, "{%s}scripts" % self.ns_uri)
326         for script in scripts:
327             el2 = SubElement(el, "{%s}script" % self.ns_uri)
328             el2.set('id', script.id)
329             el2.set('title', script.title)
330             # get script code, remove lines starting with ##bind (not necessary)
331             code = script.read()
332             code_lines = code.splitlines(1)
333             code_lines = [line for line in code_lines if not line.startswith('##bind')]
334             code = ''.join(code_lines)
335             el3 = SubElement(el2, "{%s}code" % self.ns_uri)
336             el3.set('xml:space', 'preserve')
337             el3.text = code
338             if getattr(script, '_proxy_roles', None):
339                 el2.set('proxy_roles', ','.join(list(script._proxy_roles)))
340             if getattr(script, '_owner', None):
341                 el2.set('owner', str(script._owner))
342
343     def buildVariables(self, variables, parent):
344         """Build an elementtree representation of a workflow's variables"""
345
346         el = SubElement(parent, "{%s}variables" % self.ns_uri)
347         for variable in variables:
348             el2 = SubElement(el, "{%s}variable" % self.ns_uri)
349             el2.set('id', variable.id)
350             el2.set('description', variable.description)
351             if variable.for_catalog:
352                 el2.set('availableToCatalog', '1')
353             else:
354                 el2.set('availableToCatalog', '0')
355             if variable.for_status:
356                 el2.set('storeInWorkflowStatus', '1')
357             else:
358                 el2.set('storeInWorkflowStatus', '0')
359             if variable.default_value:
360                 el3 = SubElement(el2, "{%s}defaultValue" % self.ns_uri)
361                 el3.text = variable.default_value
362             det = variable.getDefaultExprText()
363             if det:
364                 el3 = SubElement(el2, "{%s}defaultExpression" % self.ns_uri)
365                 el3.text = det
366             if variable.update_always:
367                 el2.set('always_update', '1')
368             else:
369                 el2.set('always_update', '0')
370             guard = variable.getInfoGuard()
371             g_permissions = guard.getPermissionsText()
372             g_roles = guard.getRolesText()
373             g_expression = guard.getExprText()
374             if g_permissions or g_roles or g_expression:
375                 el3 = SubElement(el2, "{%s}guard" % self.ns_uri)
376                 if g_permissions:
377                     el3.set('permissions', g_permissions)
378                 if g_roles:
379                     el3.set('roles', g_roles)
380                 if g_expression:
381                     el3.set('expr', g_expression)
382
383 #
384 # CMF/Plone 2 Hierarchy Exporter
385 #
386 class HierarchyExporter(IOBase):
387
388     def __init__(self, portal, dir_name, export_hierarchy_method):
389         self.portal = portal
390         self.mtool = self.portal.portal_membership
391         self.file_name = 'hierarchy'
392         self.file_path = os.path.join(CLIENT_HOME, dir_name, self.file_name)
393         self.ns_uri = MAIN_NAMESPACE_URI + 'cpshierarchy#'
394         # should be wssc, ws or sc
395         self.export_hierarchy_method = export_hierarchy_method
396
397     def exportFile(self):
398         """Export hierarchy"""
399
400         self.log("Exporting hierarchy to file " + self.file_path)
401         LOG("Exporting hierarchy to file", DEBUG, self.file_path)
402
403         root = self.buildTree()
404         doc = ElementTree(root)
405         doc.write(self.file_path, encoding="utf-8")
406         return self.file_name
407
408     def buildTree(self):
409         """Build the elementtree representing hierarchy"""
410
411         root = Element("{%s}hierarchy" % self.ns_uri)
412
413         if self.export_hierarchy_method in ('wssc', 'ws'):
414             ws_el = self.createFolder('workspaces', 'Workspace', root,
415                                       {'title': 'Workspaces'},
416                                       {'Title': 'Workspaces'})
417
418         if self.export_hierarchy_method in ('wssc', 'sc'):
419             sc_el = self.createFolder('sections', 'Section', root,
420                                       {'title': 'Sections'},
421                                       {'Title': 'Sections'})
422        
423         # get all CMF/Plone hierarchy elements which are direct children
424         # of the portal object (typically Members/ and other folders)
425         # and do a recursive descent of the tree
426         for object in self.portal.objectValues():
427             if object.meta_type in ('Plone Folder', 'Large Plone Folder',
428                                     'Folder'):
429                 if self.export_hierarchy_method in ('wssc', 'ws'):
430                     self.buildFolder(object, ws_el, 'Workspace')
431                 if (self.export_hierarchy_method in ('wssc', 'sc')
432                     and object.id != 'Members'):
433                     # do not duplicate Members sub-hierarchy as sections
434                     # (does not really make sense, or does it?)
435                     self.buildFolder(object, sc_el, 'Section')
436
437         return root
438
439     def createFolder(self, folder_id, portal_type, parent, props, dm):
440         """Create a folder from scratch (not actually present
441         in the portal's hierarchy)"""
442        
443         el = SubElement(parent, "{%s}folder" % self.ns_uri)
444         # folder properties
445         el.set('id', folder_id)
446         el.set('portal_type', portal_type)
447         el2 = SubElement(el, "{%s}datamodel" % self.ns_uri)
448         for field_id, field_val in dm.items():
449             el3 = SubElement(el2, "{%s}field" % self.ns_uri)
450             el3.text = str(field_val)
451             el3.set('name', field_id)
452             el3.set('type', type(field_val).__name__)
453         el2 = SubElement(el, "{%s}properties" % self.ns_uri)
454         for property_id, property_val in props.items():
455             el3 = SubElement(el2, "{%s}%s" % (self.ns_uri, property_id))
456             el3.text = str(property_val)
457             el3.set('type', type(property_val).__name__)
458         return el
459    
460     def buildFolder(self, folder, parent, portal_type):
461         """Build an elementtree representation of a folder"""
462
463         if self.export_hierarchy_method in ('wssc', 'ws'):
464             el = SubElement(parent, "{%s}folder" % self.ns_uri)
465             # folder properties
466             el.set('id', folder.id)
467             el.set('portal_type', portal_type)
468             # required by schema, even if empty
469             el2a = SubElement(el, "{%s}datamodel" % self.ns_uri)
470             el2b = SubElement(el, "{%s}properties" % self.ns_uri)
471             for property_id, property_val in folder.propertyItems():
472                 if property_val:
473                     el3 = SubElement(el2b, "{%s}%s" % (self.ns_uri, property_id))
474                     el3.text = str(property_val)
475                     el3.set('type', type(property_val).__name__)
476                     if property_id == 'title':
477                         # 'Title' seems to be the only property that
478                         # can be retrieved and mapped to a CPS datamodel field
479                         el3 = SubElement(el2a, "{%s}field" % self.ns_uri)
480                         el3.text = str(property_val)
481                         el3.set('name', 'Title')
482                         el3.set('type', 'str')
483
484         # process its children
485         for object in folder.objectValues():
486             if object.meta_type in ('Plone Folder', 'Large Plone Folder',
487                                     'Folder'):
488                 self.buildFolder(object, el, portal_type)
Note: See TracBrowser for help on using the browser.