source: ZMS/trunk/_versionmanager.py @ 1831

Revision 1831, 62.5 KB checked in by zmsdev, 2 months ago (diff)

ZMS2Go: prepared support for new simplified content-object model

Line 
1################################################################################
2# _versionmanager.py
3#
4# This program is free software; you can redistribute it and/or
5# modify it under the terms of the GNU General Public License
6# as published by the Free Software Foundation; either version 2
7# of the License, or (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program; if not, write to the Free Software
16# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17################################################################################
18
19# Imports.
20from AccessControl import ClassSecurityInfo
21from App.special_dtml import HTMLFile
22import Globals
23import copy
24import operator
25import sys
26import time
27import urllib
28import zExceptions
29# Product Imports.
30import _globals
31import _blobfields
32import _zmsattributecontainer
33
34
35# ------------------------------------------------------------------------------
36#  _versionmanager.getObjStates:
37#
38#  Returns a list of object-states (including language suffixes).
39# ------------------------------------------------------------------------------
40def getObjStates(self):
41  # Get object-states.
42  if not hasattr(self,'__work_state__'):
43    self.__work_state__ = _globals.MyClass()
44  states = getattr(self.__work_state__,'states',[])
45  # Make object-states unique.
46  d = {}
47  map(lambda x: operator.setitem(d, x, None), states)
48  states = d.keys()
49  # Return object-states.
50  return states
51
52
53# ------------------------------------------------------------------------------
54#  _versionmanager.setChangedBy:
55#
56#  Applies information about user-id and date of change.
57# ------------------------------------------------------------------------------
58def setChangedBy(self, REQUEST, createWorkAttrCntnr=True):
59  prim_lang = self.getPrimaryLanguage()
60  lang = REQUEST.get('lang',prim_lang)
61  auth_user = REQUEST.get('AUTHENTICATED_USER',None)
62  if auth_user is not None:
63    #-- Create new work-version.
64    if createWorkAttrCntnr:
65      has_version_work = self.version_work_id is not None and self.version_work_id != self.version_live_id and hasattr( self, self.version_work_id)
66      has_version_live = self.version_live_id is not None and hasattr( self, self.version_live_id)
67      if has_version_work:
68        oldAttrCntnr = getattr( self, self.version_work_id)
69      elif has_version_live:
70        oldAttrCntnr = getattr( self, self.version_live_id)
71      if ((lang == prim_lang or self.getDCCoverage(REQUEST).find('.%s'%lang) > 0) and self.getHistory()) or not has_version_work:
72        request = {'lang':'*'}
73        newAttrCntnr = _zmsattributecontainer.manage_addZMSAttributeContainer(self)
74        _globals.writeLog( self, "[setChangedBy]: Create new work-version: %s"%newAttrCntnr.id)
75        self.cloneObjAttrs(oldAttrCntnr,newAttrCntnr,request)
76        self.version_work_id = newAttrCntnr.id
77      #-- Set minor-version.
78      if ((lang == prim_lang or self.getDCCoverage(REQUEST).endswith('.%s'%lang)) and self.getHistory()) or not has_version_work:
79        try:
80          req = {'lang':lang,'preview':'preview','fetchReqBuff':False}
81          minor_version = self.getObjProperty( 'minor_version', req) + 1
82        except:
83          minor_version = 1
84        self.setObjProperty( 'minor_version' ,minor_version, lang)
85        _globals.writeLog( self, "[setChangedBy]: Set minor-version: %i"%minor_version)
86    #-- Set properties.
87    self.setObjProperty( 'change_uid' ,str(auth_user) ,lang)
88    self.setObjProperty( 'change_dt' ,_globals.getDateTime( time.time()) ,lang)
89
90
91# ------------------------------------------------------------------------------
92#  _versionmanager.setCreatedBy:
93#
94#  Applies information about user-id and date of creation.
95# ------------------------------------------------------------------------------
96def setCreatedBy(self, REQUEST):
97  auth_user = REQUEST.get('AUTHENTICATED_USER',None)
98  if auth_user is not None:
99    #-- Set properties.
100    _globals.writeLog( self, "[setCreatedBy]: Set created by: %s"%str(auth_user))
101    self.setObjProperty( 'created_uid' ,str(auth_user))
102    self.setObjProperty( 'created_dt' ,_globals.getDateTime( time.time()))
103
104
105# ------------------------------------------------------------------------------
106#  _versionmanager.getObjStateName:
107#
108#  Returns name object state in given language.
109# ------------------------------------------------------------------------------
110def getObjStateName(obj_state, lang):
111  obj_state_name = obj_state
112  if lang is not None:
113    obj_state_name += '_'+lang.upper()
114  return obj_state_name
115
116
117# ------------------------------------------------------------------------------
118#  _versionmanager.doAutocommit:
119#
120#  Commit pending changes of all objects.
121# ------------------------------------------------------------------------------
122def doAutocommit(self, REQUEST):
123 
124  ##### Auto-Commit ####
125  if len( getObjStates( self)) > 0:
126   
127    if self.inObjStates(['STATE_DELETED'],REQUEST):
128       parent = self.getParentNode()
129       parent.moveObjsToTrashcan([self.id], REQUEST)
130       return
131   
132    if self.version_work_id is not None:
133      if self.version_live_id is not None and \
134         self.version_live_id in self.objectIds( self.dGlobalAttrs.keys()):
135        ids = [ self.version_live_id]
136        self.manage_delObjects( ids=ids)
137      self.version_live_id = self.version_work_id
138      self.version_work_id = None
139    self.initializeWorkVersion()
140 
141  ##### Process child-objects ####
142  for ob in self.getChildNodes():
143    doAutocommit( ob, REQUEST)
144
145
146################################################################################
147################################################################################
148###
149###   class VersionItem
150###
151################################################################################
152################################################################################
153class VersionItem:
154
155    # Create a SecurityInfo for this class. We will use this
156    # in the rest of our class definition to make security
157    # assertions.
158    security = ClassSecurityInfo()
159
160
161    # Management Interface.
162    # ---------------------
163    version_object_state = HTMLFile('dtml/versionmanager/version_object_state', globals())
164
165
166    # --------------------------------------------------------------------------
167    #  VersionItem.tagObjVersions:
168    #
169    #  Tag object-versions.
170    # --------------------------------------------------------------------------
171    def tagObjVersions(self, master_version, REQUEST, checkPending=None):
172      _globals.writeLog( self, "[tagObjVersions]")
173      count = 1
174      if checkPending is None:
175        self.tagObjVersions( master_version, REQUEST, checkPending=True)
176        self.tagObjVersions( master_version, REQUEST, checkPending=False)
177      else:
178        if checkPending:
179          #-- Check for pending changes.
180          if self.getObjStateNames(REQUEST):
181            raise zExceptions.InternalError("Can't tagObjVersions: %s@%s has pending changes %s"%(self.meta_id,self.absolute_url(),str(self.getObjStateNames(REQUEST))))
182        else:
183          #-- Tag master-version.
184          obj_version = None
185          if obj_version is None and self.version_live_id is not None and hasattr( self, self.version_live_id):
186            obj_version = getattr( self, self.version_live_id)
187          if obj_version is None and self.version_work_id is not None and hasattr( self, self.version_work_id):
188            obj_version = getattr( self, self.version_work_id)
189          if 'change_history' in self.getObjAttrs().keys():
190            change_history = []
191            record = {}
192            record[ 'version_dt'] = _globals.getDateTime( time.time())
193            record[ 'version_uid'] = str( REQUEST.get( 'AUTHENTICATED_USER'))
194            record[ 'master_version'] = master_version
195            record[ 'major_version'] = 0
196            change_history.append( record)
197            setattr( obj_version, 'change_history', change_history)
198          setattr( obj_version, 'master_version', master_version)
199          setattr( obj_version, 'major_version', 0)
200          setattr( obj_version, 'minor_version', 0)
201          self.version_live_id = obj_version.id
202          self.version_work_id = None
203          ids = []
204          for obj_version in self.getObjVersions():
205            if obj_version.id != self.version_live_id:
206              ids.append( obj_version.id)
207          self.manage_delObjects( ids=ids)
208        #-- Recursion.
209        for ob in self.getChildNodes():
210          count += ob.tagObjVersions( master_version, REQUEST, checkPending)
211      return count
212
213
214    """
215    ############################################################################
216    #  Workflow
217    ############################################################################
218    """
219
220    # --------------------------------------------------------------------------
221    #  VersionItem.getWfStates
222    # --------------------------------------------------------------------------
223    def getWfStates(self, REQUEST):
224      states = getObjStates(self)
225      lang = REQUEST.get('lang',None)
226      obj_states = []
227      wfActivitiesIds = self.getWfActivitiesIds()
228      for obj_state in wfActivitiesIds:
229        obj_state_name = getObjStateName(obj_state,lang)
230        if obj_state_name in states:
231          obj_states.append(obj_state)
232      if len( obj_states) == 0 and \
233         len( wfActivitiesIds) > 0 and \
234         lang is not None and \
235        ( 'STATE_NEW_%s'%lang.upper() in states or \
236          'STATE_MODIFIED_%s'%lang.upper() in states or \
237          'STATE_DELETED_%s'%lang.upper() in states):
238        obj_states.append( wfActivitiesIds[0])
239      return obj_states
240
241
242    # --------------------------------------------------------------------------
243    #  VersionItem.getVersionItems
244    # 
245    #  Returns all version-items.
246    # --------------------------------------------------------------------------
247    def getVersionItems(self, REQUEST, recursive=False):
248      children = []
249      if not self.getAutocommit():
250        pc = self.isPageContainer()
251        types = self.getMetaobjIds(sort=0)+['*']
252        for metaobjAttrId in self.getMetaobjAttrIds( self.meta_id, types=types):
253          for child in self.getObjChildren( metaobjAttrId , REQUEST):
254            if recursive or not pc or not child.isPage():
255              children.append( child)
256              if not pc:
257                children.extend( child.getVersionItems( REQUEST, recursive=True))
258      return children
259
260
261    # --------------------------------------------------------------------------
262    #  VersionItem.isObjModified:
263    #
264    #  Returns true if version-item is modified, false otherwise.
265    # --------------------------------------------------------------------------
266    def isObjModified(self, REQUEST):
267      return self.inObjStates( [ 'STATE_NEW', 'STATE_MODIFIED', 'STATE_DELETED'], REQUEST)
268
269
270    # --------------------------------------------------------------------------
271    #  VersionItem.syncObjModifiedChildren:
272    #
273    #  Returns true if object has modified children, false otherwise.
274    # --------------------------------------------------------------------------
275    def syncObjModifiedChildren(self, REQUEST, depth=0):
276      obj_state = 'STATE_MODIFIED_OBJS'
277      rtnVal = False
278      for child in self.getVersionItems( REQUEST):
279        if child.isObjModified(REQUEST):
280          rtnVal = True
281        else:
282          rtnVal = child.syncObjModifiedChildren( REQUEST, depth+1)
283        if rtnVal:
284          break
285      if depth==0:
286        if rtnVal:
287          if not self.inObjStates( [ obj_state], REQUEST):
288            self.setObjState( obj_state, REQUEST[ 'lang'])
289        else:
290          if self.inObjStates( [ obj_state], REQUEST):
291            self.delObjStates( [ obj_state], REQUEST)
292      return rtnVal
293
294
295    # --------------------------------------------------------------------------
296    #  VersionItem.hasObjModifiedChildren:
297    #
298    #  Returns true if object has modified children, false otherwise.
299    # --------------------------------------------------------------------------
300    def hasObjModifiedChildren(self, REQUEST, depth=0):
301      obj_state = 'STATE_MODIFIED_OBJS'
302      return self.inObjStates( [ obj_state], REQUEST)
303
304
305    # --------------------------------------------------------------------------
306    #  VersionItem.resetObjTranslation:
307    #
308    #  Resets translation.
309    # --------------------------------------------------------------------------
310    def resetObjTranslation(self):
311      prim_lang = self.getPrimaryLanguage()
312      for ob in self.getObjVersions():
313        for lang in self.getLangIds():
314          if lang != prim_lang:
315            setattr(ob,'change_uid_%s'%lang,'')
316
317
318    # --------------------------------------------------------------------------
319    #  VersionItem.initializeWorkVersion:
320    #
321    #  Initializes work-version of object-attributes.
322    # --------------------------------------------------------------------------
323    def initializeWorkVersion(self):
324      # States.
325      self.__work_state__ = _globals.MyClass()
326      # Create new work-version.
327      if len(self.objectValues(['ZMSAttributeContainer']))==0:
328        newAttrCntnr = _zmsattributecontainer.manage_addZMSAttributeContainer(self)
329        _globals.writeLog( self, "[initializeWorkVersion]: Create new work-version: %s"%newAttrCntnr.id)
330        self.version_work_id = newAttrCntnr.id
331        self.version_live_id = None
332
333
334    # --------------------------------------------------------------------------
335    #  VersionItem.isCommitted:
336    #
337    #  Checks if object can by displayed.
338    # --------------------------------------------------------------------------
339    def isCommitted(self, REQUEST):
340      if _globals.isPreviewRequest( REQUEST):
341        committed = not self.inObjStates( [ 'STATE_DELETED'], REQUEST)
342      else:
343        committed = not self.inObjStates( [ 'STATE_NEW'], REQUEST)
344      return committed
345
346
347    """
348    ############################################################################
349    #  API object-state
350    ############################################################################
351    """
352
353    # --------------------------------------------------------------------------
354    #  VersionItem.setObjState:
355    #
356    #  Sets object-state.
357    # --------------------------------------------------------------------------
358    def setObjState(self, obj_state, lang):
359      state = getObjStateName(obj_state,lang)
360      states = getObjStates(self)
361      if not state in states:
362        states.append(state)
363      self.__work_state__.states = copy.deepcopy(states)
364      self.__work_state__ = copy.deepcopy(self.__work_state__)
365
366    # --------------------------------------------------------------------------
367    #  VersionItem.delObjStates:
368    #
369    #  Deletes object-state of this object.
370    # --------------------------------------------------------------------------
371    def delObjStates(self, obj_states=[], REQUEST={}):
372      prim_lang = self.getPrimaryLanguage()
373      lang = REQUEST.get('lang',prim_lang)
374      states = getObjStates(self)
375      for obj_state in obj_states:
376        while obj_state in states:
377          del states[states.index(obj_state)]
378        while getObjStateName(obj_state,lang) in states:
379          del states[states.index(getObjStateName(obj_state,lang))]
380      self.__work_state__.states = copy.deepcopy(states)
381      self.__work_state__ = copy.deepcopy(self.__work_state__)
382
383
384    # --------------------------------------------------------------------------
385    #  VersionItem.resetObjStates:
386    #
387    #  Resets object-state of this object.
388    # --------------------------------------------------------------------------
389    def resetObjStates(self, REQUEST=None):
390      if REQUEST is None:
391        self.version_live_id = self.version_work_id
392        self.version_work_id = None
393        self.__work_state__.states = []
394        self.__work_state__ = copy.deepcopy(self.__work_state__)
395      else:
396        self.delObjStates( [ 'STATE_NEW', 'STATE_MODIFIED', 'STATE_MODIFIED_OBJS', 'STATE_DELETED'], REQUEST)
397
398
399    # --------------------------------------------------------------------------
400    #  VersionItem.inObjStates:
401    #
402    #  Checks if given states are in object-states of this object.
403    # --------------------------------------------------------------------------
404    def inObjStates(self, obj_states, REQUEST):
405      states = getObjStates(self)
406      states.extend(self.getObjStateNames(REQUEST))
407      if len(states) > 0:
408        prim_lang = self.getPrimaryLanguage()
409        lang = REQUEST.get('lang',prim_lang)
410        for obj_state in obj_states:
411          obj_state_name = getObjStateName( obj_state, lang)
412          if obj_state_name in states:
413            return True
414      return False
415
416
417    # --------------------------------------------------------------------------
418    #  VersionItem.filteredObjStates:
419    #
420    #  Checks if given states are in object-states of this object.
421    # --------------------------------------------------------------------------
422    def filteredObjStates(self, REQUEST):
423      obj_states = []
424      states = getObjStates(self)
425      if len(states) > 0:
426        lang = REQUEST.get('lang',self.getPrimaryLanguage())
427        for obj_state in [ 'STATE_NEW', 'STATE_MODIFIED', 'STATE_DELETED']:
428          obj_state_name = getObjStateName(obj_state,lang)
429          if obj_state_name in states:
430            obj_states.append( obj_state)
431      return obj_states
432
433
434    # --------------------------------------------------------------------------
435    #  VersionItem.getObjStateNames:
436    #
437    #  Returns a list of normalized object-states (language suffixes stripped off).
438    # --------------------------------------------------------------------------
439    def getObjStateNames(self, REQUEST):
440      lang = REQUEST.get('lang')
441     
442      # Current Object.
443      states = getObjStates(self)
444      obj_states = []
445      for obj_state in [ 'STATE_NEW', 'STATE_MODIFIED', 'STATE_DELETED']:
446        obj_state_name = getObjStateName(obj_state,lang)
447        if obj_state_name in states:
448          obj_states.append(obj_state_name)
449     
450      # Return value.
451      return obj_states
452
453
454    """
455    ############################################################################
456    #  Change object-state.
457    ############################################################################
458    """
459
460    # --------------------------------------------------------------------------
461    #  VersionItem.setObjStateNew
462    # --------------------------------------------------------------------------
463    def setObjStateNew(self, REQUEST, reset=1):
464      obj_state = 'STATE_NEW'
465      if reset: self.initializeWorkVersion()
466      setChangedBy( self, REQUEST)
467      setCreatedBy( self, REQUEST)
468      #-- Set Master-Version.
469      parent = self.getParentNode()
470      master_version = 0
471      if parent is not None:
472        master_version = parent.getObjProperty( 'master_version', REQUEST)
473      self.setObjProperty( 'master_version', master_version)
474      self.setObjState(obj_state,REQUEST['lang'])
475
476    # --------------------------------------------------------------------------
477    #  VersionItem.setObjStateModified
478    # --------------------------------------------------------------------------
479    def setObjStateModified(self, REQUEST):
480      obj_state = 'STATE_MODIFIED'
481      setChangedBy( self, REQUEST)
482      self.setObjState(obj_state,REQUEST['lang'])
483
484    # --------------------------------------------------------------------------
485    #  VersionItem.setObjStateDeleted
486    # --------------------------------------------------------------------------
487    def setObjStateDeleted(self, REQUEST):
488      obj_state = 'STATE_DELETED'
489      setChangedBy( self, REQUEST)
490      self.setObjState(obj_state,REQUEST['lang'])
491
492
493    """
494    ############################################################################
495    #
496    #   Commit
497    #
498    ############################################################################
499    """
500
501    # --------------------------------------------------------------------------
502    #  VersionItem.onChangeObj:
503    # --------------------------------------------------------------------------
504    def onChangeObj(self, REQUEST, forced=False, do_history=True):
505      _globals.writeLog( self, "[onChangeObj]")
506      prim_lang = self.getPrimaryLanguage()
507      lang = REQUEST.get('lang',prim_lang)
508     
509      ##### Trigger thumbnail generation of image fields ####
510      _blobfields.thumbnailImageFields( self, lang, REQUEST)
511     
512      ##### Trigger custom onChangeObj-Event (if there is one) ####
513      _globals.triggerEvent( self, 'onChangeObjEvt', preview=True, REQUEST=REQUEST)
514     
515      ##### Commit or initiate workflow transition ####
516      if self.getAutocommit() or forced:
517        self.commitObj(REQUEST,forced,do_history)
518      else:
519        self.autoWfTransition(REQUEST)
520      _globals.writeLog( self, "[onChangeObj]: Finished!")
521
522    # --------------------------------------------------------------------------
523    #  VersionItem.onSynchronizeObj:
524    # --------------------------------------------------------------------------
525    def onSynchronizeObj(self, REQUEST):
526      _globals.writeLog( self, "[onSynchronizeObj]")
527      #-- Catalog
528      ob = self.getCatalogItem()
529      obs = REQUEST.get('ZMS_SYNCHRONIZE_CATALOG',[])
530      if ob not in obs:
531        obs.append(ob)
532        try:
533          REQUEST.set('ZMS_SYNCHRONIZE_CATALOG',obs)
534        except:
535          REQUEST['ZMS_SYNCHRONIZE_CATALOG'] = obs
536      #-- Cache
537      self.synchronizeCachePage(REQUEST)
538      #-- Access
539      self.synchronizePublicAccess()
540      #-- References
541      self.synchronizeRefToObjs()
542      self.synchronizeRefByObjs()
543
544
545    # --------------------------------------------------------------------------
546    #  VersionItem.commitObjChanges
547    # --------------------------------------------------------------------------
548    def _commitObjChanges(self, parent, REQUEST, forced=False, do_history=True, do_delete=True):
549      _globals.writeLog( self, "[_commitObjChanges]: forced=%s, do_history=%s, do_delete=%s"%(str(forced),str(do_history),str(do_delete)))
550      delete = False
551      prim_lang = self.getPrimaryLanguage()
552      lang = REQUEST.get('lang',prim_lang)
553     
554      ##### Trigger custom beforeCommitObjChanges-Event (if there is one) ####
555      _globals.triggerEvent( self, 'beforeCommitObjChangesEvt', preview=True, REQUEST=REQUEST)
556     
557      ##### Commit delete. ####
558      if self.inObjStates(['STATE_DELETED'],REQUEST):
559        if do_delete:
560          parent.moveObjsToTrashcan([self.id], REQUEST)
561        delete = True
562     
563      ##### Commit modifications. ####
564      modified = self.getObjStateNames(REQUEST) or forced
565      if modified:
566       
567        if (lang == prim_lang or self.getDCCoverage(REQUEST).find('.%s'%lang) > 0) and (self.getHistory() and do_history):
568          version_hist_id = None
569          if self.getObjStateNames(REQUEST) and \
570             self.version_work_id is not None:
571            # Clone current live-version to history-version.
572            if self.version_live_id is not None and self.version_live_id in self.objectIds(['ZMSAttributeContainer']):
573              request = {'lang':'*'}
574              histAttrCntnr = _zmsattributecontainer.manage_addZMSAttributeContainer(self)
575              self.cloneObjAttrs(getattr(self,self.version_live_id),histAttrCntnr,request)
576              version_hist_id = histAttrCntnr.id
577            # Replace current live-version by work-version.
578            if self.version_work_id is not None and self.version_work_id in self.objectIds(['ZMSAttributeContainer']):
579              self.version_live_id = self.version_work_id
580              self.version_work_id = None
581          # Increase version-number.
582          major_version = self.getObjProperty( 'major_version', REQUEST)
583          self.setObjProperty( 'major_version', major_version + 1)
584          self.setObjProperty( 'minor_version' ,0)
585          # Remove previous minor-versions.
586          ids = []
587          for ob_version in self.getObjVersions():
588            if ob_version.id != version_hist_id and \
589               ob_version.getObjProperty('major_version',REQUEST) == major_version:
590              ids.append( ob_version.id)
591          _globals.writeLog( self, "[_commitObjChanges]: Remove previous minor-versions: ids=%s"%str(ids))
592          self.manage_delObjects( ids=ids)
593       
594        else:
595          if self.getObjStateNames(REQUEST) and \
596             self.version_work_id is not None:
597            if self.version_live_id is None:
598              self.version_live_id = self.version_work_id
599            if self.getAutocommit():
600              # Replace current live-version by work-version.
601              self.version_live_id = self.version_work_id
602              self.version_work_id = None
603            elif self.version_live_id != self.version_work_id:
604              # Clone current work-version to live-version.
605              self.cloneObjAttrs(getattr(self,self.version_work_id),getattr(self,self.version_live_id),REQUEST)
606          # Reset version-number.
607          if self.getHistory() and not do_history:
608            self.setObjProperty( 'major_version', 0)
609            self.setObjProperty( 'minor_version' ,0)
610         
611      ##### Commit version-items. ####
612      if not delete:
613        ids = []
614        for child in self.getVersionItems( REQUEST):
615          delete_child = child._commitObjChanges( self, REQUEST, False, do_history, False)
616          if delete_child:
617            ids.append( child.id)
618        if len( ids) > 0:
619          self.moveObjsToTrashcan( ids, REQUEST)
620     
621      ##### Reset object-state. ####
622      self.resetObjStates(REQUEST)
623      # Remove work-version.
624      attrCntnrIds = self.objectIds(['ZMSAttributeContainer'])
625      if (self.getAutocommit() or len( filter( lambda x: x.find( 'STATE_') == 0, getObjStates( self))) == 0) and getattr( self, 'version_live_id', None) is not None:
626        if self.version_live_id in attrCntnrIds:
627          ids = []
628          if self.version_live_id != self.version_work_id and self.version_work_id in attrCntnrIds:
629            ids.append( self.version_work_id)
630          if self.getAutocommit() and not (self.getHistory() and do_history):
631            for id in attrCntnrIds:
632              if id != self.version_live_id and id != self.version_work_id:
633                ids.append( id)
634          self.version_work_id = None
635          if len( ids) > 0:
636            _globals.writeLog( self, "[_commitObjChanges]: Remove work-version: ids=%s"%str(ids))
637          self.manage_delObjects( ids=ids)
638        elif self.version_work_id in attrCntnrIds:
639          self.version_live_id = self.version_work_id
640          self.version_work_id = None
641     
642      ##### Synchronize listeners. ####
643      if modified:
644        self.onSynchronizeObj(REQUEST)
645     
646      ##### Trigger custom afterCommitObjChanges-Event (if there is one) ####
647      _globals.triggerEvent( self, 'afterCommitObjChangesEvt', preview=True, REQUEST=REQUEST)
648     
649      # Return flag for deleted objects.
650      return delete
651
652    def commitObjChanges(self, parent, REQUEST, forced=False, do_history=True, do_delete=True):
653      _globals.writeLog( self, "[commitObjChanges]: forced=%s, do_history=%s, do_delete=%s"%(str(forced),str(do_history),str(do_delete)))
654      delete = self._commitObjChanges( parent, REQUEST, forced, do_history, do_delete)
655      ##### Synchronize catalog. ####
656      obs = REQUEST.get('ZMS_SYNCHRONIZE_CATALOG',[])
657      for ob in obs:
658        ob.synchronizeSearch(REQUEST)
659      # Return flag for deleted objects.
660      return delete
661
662
663    """
664    ############################################################################
665    #
666    #   Rollback
667    #
668    ############################################################################
669    """
670
671    # --------------------------------------------------------------------------
672    #  VersionItem.rollbackObjChanges
673    # --------------------------------------------------------------------------
674    def _rollbackObjChanges(self, parent, REQUEST, forced=0, do_delete=True):
675      _globals.writeLog( self, "[_rollbackObjChanges]")
676      delete = False
677      prim_lang = self.getPrimaryLanguage()
678      lang = REQUEST.get('lang',prim_lang)
679     
680      ##### Trigger custom beforeRollbackObjChanges-Event (if there is one) ####
681      _globals.triggerEvent( self, 'beforeRollbackObjChangesEvt', preview=True, REQUEST=REQUEST)
682     
683      ##### Rollback insert. ####
684      # Self.
685      if self.inObjStates(['STATE_NEW'],REQUEST):
686        if do_delete:
687          parent.moveObjsToTrashcan([self.id], REQUEST)
688        delete = True
689     
690      ##### Rollback modifications. ####
691      modified = self.getObjStateNames(REQUEST) or forced
692      if modified and not delete:
693       
694        if (lang == prim_lang or self.getDCCoverage(REQUEST).find('.%s'%lang) > 0) and self.getHistory():
695          # Reset work-version.
696          self.version_work_id = None
697          # Current version-number.
698          major_version = self.getObjProperty( 'major_version', REQUEST)
699          # Remove next minor-versions.
700          ids = []
701          for ob_version in self.getObjVersions():
702            if ob_version.getObjProperty('major_version',REQUEST) == major_version and \
703               ob_version.getObjProperty('minor_version',REQUEST) > 0:
704              ids.append( ob_version.id)
705          _globals.writeLog( self, "[_rollbackObjChanges]: Remove next minor-versions: ids=%s"%str(ids))
706          self.manage_delObjects( ids=ids)
707       
708        else:
709          if self.getObjStateNames(REQUEST) and \
710             self.version_work_id is not None:
711            if self.version_live_id is None:
712              self.version_live_id = self.version_work_id
713            if self.getAutocommit():
714              # Remove current work-version.
715              self.version_work_id = None
716            elif self.version_live_id is not None and self.version_live_id != self.version_work_id:
717              # Clone current live-version to work-version.
718              _globals.writeLog( self, "[_rollbackObjChanges]: Clone current live-version '%s' to work-version '%s'"%(self.version_live_id,self.version_work_id))
719              self.cloneObjAttrs(getattr(self,self.version_live_id),getattr(self,self.version_work_id),REQUEST)
720     
721      ##### Rollback version-items. ####
722      if not delete:
723        ids = []
724        for child in self.getVersionItems( REQUEST):
725          delete_child = child._rollbackObjChanges( self, REQUEST, 0, False)
726          if delete_child:
727            ids.append( child.id)
728        if len( ids) > 0:
729          self.moveObjsToTrashcan( ids, REQUEST)
730     
731      ##### Reset object-state. ####
732      self.resetObjStates(REQUEST)
733      # Remove work-version.
734      attrCntnrIds = self.objectIds(['ZMSAttributeContainer'])
735      if (self.getAutocommit() or len( filter( lambda x: x.find( 'STATE_') == 0, getObjStates( self))) == 0) and getattr( self, 'version_live_id', None) is not None:
736        if self.version_live_id in attrCntnrIds:
737          ids = []
738          if self.version_live_id != self.version_work_id and self.version_work_id in attrCntnrIds:
739            ids.append( self.version_work_id)
740          if self.getAutocommit() and not self.getHistory():
741            for id in attrCntnrIds:
742              if id != self.version_live_id and id != self.version_work_id:
743                ids.append( id)
744          self.version_work_id = None
745          if len( ids) > 0:
746            _globals.writeLog( self, "[_rollbackObjChanges]: Remove work-version: ids=%s"%str(ids))
747          self.manage_delObjects( ids=ids)
748        elif self.version_work_id in attrCntnrIds:
749          self.version_live_id = self.version_work_id
750          self.version_work_id = None
751     
752      ##### Synchronize listeners. ####
753      if modified and not delete:
754        self.onSynchronizeObj(REQUEST)
755     
756      ##### Trigger custom afterRollbackObjChanges-Event (if there is one) ####
757      _globals.triggerEvent( self, 'afterRollbackObjChangesEvt', preview=True, REQUEST=REQUEST)
758     
759      # Return flag for deleted objects.
760      return delete
761
762    def rollbackObjChanges(self, parent, REQUEST, forced=0, do_delete=True):
763      delete = self._rollbackObjChanges( parent, REQUEST, forced, do_delete)
764      ##### Synchronize catalog. ####
765      obs = REQUEST.get('ZMS_SYNCHRONIZE_CATALOG',[])
766      for ob in obs:
767        ob.synchronizeSearch(REQUEST)
768      # Return flag for deleted objects.
769      return delete
770
771
772    """
773    ############################################################################
774    #
775    #   History
776    #
777    ############################################################################
778    """
779
780    # --------------------------------------------------------------------------
781    #  VersionItem.packHistory:
782    #
783    #  Pack history.
784    # --------------------------------------------------------------------------
785    def packHistory(self):
786      count = 0
787      if not self.getHistory():
788        #-- Remove version-attribute-containers.
789        ids = []
790        for id in self.objectIds(['ZMSAttributeContainer']):
791          if id not in [ self.version_work_id, self.version_live_id]:
792            ids.append( id)
793        count += len( ids)
794        self.manage_delObjects( ids=ids)
795        #-- Remove version-attributes.
796        for key in ['master_version','major_version', 'minor_version', 'change_history']:
797          for id in [ self.version_work_id, self.version_live_id]:
798            if id is not None:
799              ob = getattr( self, id, None)
800              if ob is not None:
801                try:
802                  delattr( ob, key)
803                except:
804                  pass
805        #-- Recursion.
806        for ob in self.objectValues( self.dGlobalAttrs.keys()):
807          count += ob.packHistory()
808      return count
809
810
811    # --------------------------------------------------------------------------
812    #  VersionItem.getHistory:
813    #
814    #  Returns true if history is active, false otherwise.
815    # --------------------------------------------------------------------------
816    def getHistory( self):
817      active = True
818      if active:
819        active = active and self.getConfProperty('ZMS.Version.active',0)==1
820      if active:
821        baseurl = self.getDocumentElement().absolute_url()
822        url = self.absolute_url()
823        if len( url) >= len( baseurl):
824          url = url[ len( baseurl)+1:]
825        url = '$'+url
826        found = False
827        nodes = self.getConfProperty('ZMS.Version.nodes',['{$}'])
828        for node in nodes:
829          if node[1:-1] == '$' or (url+'/').find(node[1:-1]+'/') == 0:
830            found = True
831            break
832        active = active and found
833      return active
834   
835
836    # --------------------------------------------------------------------------
837    #  VersionItem.ajaxBodyContentObjHistory:
838    # --------------------------------------------------------------------------
839    security.declareProtected('View', 'ajaxBodyContentObjHistory')
840    def ajaxBodyContentObjHistory(self, version_nr, REQUEST):
841      """
842      Returns ajax-xml with body-content of object-history for given version-nr.
843      """
844     
845      #-- Get versions.
846      master_version = int( version_nr[ :version_nr.find( '.')])
847      major_version = int( version_nr[ version_nr.find( '.')+1: version_nr.rfind( '.')])
848      minor_version = int( version_nr[ version_nr.rfind( '.')+1:])
849      REQUEST.set( 'ZMS_VERSION_%s'%self.id, None)
850      version_dt = None
851      if 'change_history' in self.getObjAttrs().keys():
852        change_history = copy.copy( self.getObjProperty( 'change_history', REQUEST))
853        change_history.reverse()
854        for item in change_history:
855          if version_dt is None and \
856             item.get( 'master_version', 0) <= master_version and \
857             item.get( 'major_version', 0) <= major_version:
858            version_dt = item[ 'version_dt']
859            break
860     
861      #-- Build xml.
862      RESPONSE = REQUEST.RESPONSE
863      content_type = 'text/xml; charset=utf-8'
864      filename = 'ajaxBodyContentObjHistory.xml'
865      RESPONSE.setHeader('Content-Type',content_type)
866      RESPONSE.setHeader('Content-Disposition','inline;filename="%s"'%filename)
867      RESPONSE.setHeader('Cache-Control', 'no-cache')
868      RESPONSE.setHeader('Pragma', 'no-cache')
869      self.f_standard_html_request( self, REQUEST)
870      xml = self.getXmlHeader()
871      xml += "<BodyContentObjHistory version_nr=\""+version_nr+"\">\n"
872      if self.meta_type == 'ZMSCustom':
873        obj_version = self.getObjHistory( version_nr, REQUEST, False)
874        REQUEST.set( 'ZMS_VERSION_%s'%self.id, obj_version.id)
875        xml += '<ObjHistory id="' + obj_version.id + '">'
876        xml += '<![CDATA[' + obj_version.getBodyContent( REQUEST) + ']]>'
877        xml += '</ObjHistory>\n'
878      else:
879        obj_history = self.getObjHistory( version_nr, REQUEST)
880        for history_version in obj_history:
881          if history_version.isActive(REQUEST):
882            xml += '<ObjHistory id="' + history_version.id + '">'
883            xml += '<![CDATA[' + history_version.renderShort( REQUEST) + ']]>'
884            xml += '</ObjHistory>\n'
885      xml += "</BodyContentObjHistory>\n"
886      return xml
887
888
889    # --------------------------------------------------------------------------
890    #  VersionItem.getObjHistory:
891    #
892    #  Returns object-history for given version-nr.
893    # --------------------------------------------------------------------------
894    def getObjHistory(self, version_nr, REQUEST, children=True, deleted=True):
895      _globals.writeLog( self, '[getObjHistory]: version_nr=%s'%str(version_nr))
896      obs = []
897      ZMS_VERSION = REQUEST.get( 'ZMS_VERSION_%s'%self.id)
898      master_version = int( version_nr[ :version_nr.find( '.')])
899      major_version = int( version_nr[ version_nr.find( '.')+1: version_nr.rfind( '.')])
900      minor_version = int( version_nr[ version_nr.rfind( '.')+1:])
901      REQUEST.set( 'ZMS_VERSION_%s'%self.id, None)
902      version_dt = None
903      change_history = []
904      if 'change_history' in self.getObjAttrs().keys():
905        change_history = copy.copy( self.getObjProperty( 'change_history', REQUEST))
906        change_history.reverse()
907        for item in change_history:
908          if version_dt is None and \
909             item.get( 'master_version', 0) <= master_version and \
910             item.get( 'major_version', 0) <= major_version:
911            version_dt = item[ 'version_dt']
912            break
913      _globals.writeLog( self, '[getObjHistory]: version_dt=%s'%str(version_dt))
914      found = False
915      last_ob_version = None
916      for ob_version in self.getObjVersions():
917        REQUEST.set( 'ZMS_VERSION_%s'%self.id, ob_version.id)
918        last_ob_version = ob_version
919        ob_version_master_version = getattr( ob_version, 'master_version', 0)
920        ob_version_major_version = getattr( ob_version, 'major_version', 0)
921        ob_version_minor_version = getattr( ob_version, 'minor_version', 0)
922        ob_version_nr = '%i.%i.%i'%(ob_version_master_version,ob_version_major_version,ob_version_minor_version)
923        ob_version_change_dt = ob_version.getObjProperty( 'change_dt', REQUEST, {'fetchReqBuff':0})
924        if ob_version_nr <= version_nr:
925          if not children:
926            _globals.writeLog( self, '[getObjHistory]: return %s'%str(last_ob_version.id))
927            return last_ob_version
928          for ob_child in self.getVersionItems( REQUEST, recursive=True):
929            for ob_child_version in ob_child.getObjVersions():
930              REQUEST.set( 'ZMS_VERSION_%s'%ob_child.id, ob_child_version.id)
931              ob_child_master_version = getattr( ob_child_version, 'master_version', 0)
932              ob_child_major_version = getattr( ob_child_version, 'major_version', 0)
933              ob_child_minor_version = getattr( ob_child_version, 'minor_version', 0)
934              ob_child_nr = '%i.%i.%i'%(ob_child_master_version,ob_child_major_version,ob_child_minor_version)
935              ob_child_change_dt = ob_child.getObjProperty( 'change_dt', REQUEST, {'fetchReqBuff':0})
936              if ( version_dt is None and \
937                   ((ob_child_master_version == 0 and ob_child_major_version == 0 and ob_child_minor_version == 0) or \
938                    (len( change_history) == 0 and ob_version_change_dt >= ob_child_change_dt))) or \
939                 ( version_dt >= ob_child_change_dt) or \
940                 ( minor_version > 0 and ob_child_minor_version > 0) or \
941                 ( minor_version > 0 and ob_child_change_dt > version_dt):
942                obs.append( ob_child_version)
943                break
944          found = True
945          break
946      if not found:
947        if not children:
948          _globals.writeLog( self, '[getObjHistory]: return %s'%str(last_ob_version.id))
949          return last_ob_version
950        for ob_child in self.getVersionItems( REQUEST, recursive=True):
951          for ob_child_version in ob_child.getObjVersions():
952            REQUEST.set( 'ZMS_VERSION_%s'%ob_child.id, ob_child_version.id)
953            ob_child_master_version = getattr( ob_child_version, 'master_version', 0)
954            ob_child_major_version = getattr( ob_child_version, 'major_version', 0)
955            ob_child_minor_version = getattr( ob_child_version, 'minor_version', 0)
956            ob_child_nr = '%i.%i.%i'%(ob_child_master_version,ob_child_major_version,ob_child_minor_version)
957            ob_child_change_dt = ob_child.getObjProperty( 'change_dt', REQUEST)
958            if ( version_dt is None and ob_child_master_version == 0 and ob_child_major_version == 0 and ob_child_minor_version == 0) or \
959               ( ob_child_change_dt <= version_dt):
960              obs.append( ob_child_version)
961              break
962      REQUEST.set( 'ZMS_VERSION_%s'%self.id, ZMS_VERSION)
963      return obs
964
965    # --------------------------------------------------------------------------
966    #  VersionItem.getObjVersion:
967    #
968    #  Returns attribute-container. If Http-Request has key >ZMS_VERSION< the
969    #  desired version is returned, if Http-Request has key >preview< the work-
970    #  version is returned, else the live-version is returned.
971    # --------------------------------------------------------------------------
972    def getObjVersion(self, REQUEST={}):
973        try:
974            ob = None
975            id = REQUEST.get( 'ZMS_VERSION_%s'%self.id, None)
976            if id is not None:
977                return getattr( self, id)
978            elif REQUEST.get('preview') == 'preview':
979                if self.version_work_id is not None:
980                    ob = getattr(self, self.version_work_id, None)
981            else:
982                if self.version_live_id is not None:
983                    ob = getattr(self, self.version_live_id, None)
984            if ob is None:
985                if self.version_work_id is not None:
986                    ob = getattr(self, self.version_work_id, None)
987            if ob is None:
988                if self.version_live_id is not None:
989                    ob = getattr(self, self.version_live_id, None)
990            s = ob.id # Never delete this line!
991            return ob
992        except:
993            raise zExceptions.InternalError(_globals.writeError( self, '[getObjVersion]: an unexpected error occured!'))
994
995
996    # --------------------------------------------------------------------------
997    #  VersionItem.getObjVersions:
998    #
999    #  Returns all attribute-containers.
1000    # --------------------------------------------------------------------------
1001    def getObjVersions(self):
1002      try:
1003        obs = []
1004        for ob in self.objectValues(['ZMSAttributeContainer']):
1005          master_version = getattr( ob,'master_version',0)
1006          if type(master_version) is not int: master_version = 0
1007          major_version = getattr( ob,'major_version',0)
1008          if type(major_version) is not int: major_version = 0
1009          minor_version = getattr( ob,'minor_version',0)
1010          if type(minor_version) is not int: minor_version = 0
1011          obs.insert(0,(master_version*10000+major_version*100+minor_version,ob))
1012        # sort object-items
1013        obs.sort()
1014        obs.reverse()
1015        # truncate version-nr from sorted object-items
1016        obs = map( lambda ob: ob[1], obs)
1017        # return object-items
1018        return obs
1019      except:
1020        raise zExceptions.InternalError(_globals.writeError( self, '[getObjVersions]: an unexpected error occured!'))
1021
1022
1023    # --------------------------------------------------------------------------
1024    #  VersionItem.restoreObjVersion:
1025    #
1026    #  Restore object-version.
1027    # --------------------------------------------------------------------------
1028    def restoreObjVersion( self, ob_version, REQUEST):
1029      if ob_version is not None and \
1030         ob_version.id != self.version_work_id:
1031        REQUEST.set( 'ZMS_VERSION_%s'%self.id, None)
1032        if 'change_history' in self.getObjAttrs().keys():
1033          change_history = self.getObjProperty('change_history',REQUEST)
1034        master_version = self.getObjProperty('master_version',REQUEST)
1035        major_version = self.getObjProperty('major_version',REQUEST)
1036        minor_version = self.getObjProperty('minor_version',REQUEST) + 1
1037        # Restore attributes.
1038        self.setObjStateModified( REQUEST)
1039        self.cloneObjAttrs(ob_version,getattr(self,self.version_work_id),REQUEST)
1040        setChangedBy(self, REQUEST, createWorkAttrCntnr=False)
1041        if 'change_history' in self.getObjAttrs().keys():
1042          self.setObjProperty('change_history',change_history)
1043        self.setObjProperty('master_version',master_version)
1044        self.setObjProperty('major_version',major_version)
1045        self.setObjProperty('minor_version',minor_version)
1046        self.onChangeObj(REQUEST)
1047        return True
1048      return False
1049
1050
1051    ############################################################################
1052    #  VersionItem.manage_UndoVersion:
1053    #
1054    #  Undo version changes.
1055    ############################################################################
1056    manage_VersionLangModified = HTMLFile('dtml/versionmanager/manage_versionlangmodified', globals())
1057    manage_UndoVersionForm = HTMLFile('dtml/versionmanager/manage_undoversionform', globals())
1058    def manage_UndoVersion(self, lang, REQUEST):
1059      """ VersionItem.manage_UndoVersion """
1060      message = ''
1061     
1062      # Reset.
1063      # ------
1064      if REQUEST.get('btn','') == self.getZMILangStr('BTN_RESET'):
1065        version_nrs = REQUEST.get('version_nrs',[])
1066        if len(version_nrs) == 1:
1067          version_nr = version_nrs[0]
1068          ob_version = self.getObjHistory( version_nr, REQUEST, children=False)
1069          if self.restoreObjVersion( ob_version, REQUEST):
1070            # Restore children.
1071            ob_child_versions = self.getObjHistory( version_nr, REQUEST, children=True)
1072            for ob_child_version in ob_child_versions:
1073              ob_child = ob_child_version.aq_parent
1074              ob_child.restoreObjVersion( ob_child_version, REQUEST)
1075          message = self.getZMILangStr('MSG_CHANGED')
1076
1077      # Return with message.
1078      message = urllib.quote(message)
1079      return REQUEST.RESPONSE.redirect('manage_UndoVersionForm?lang=%s&manage_tabs_message=%s'%(lang,message))
1080
1081
1082################################################################################
1083################################################################################
1084###
1085###   class VersionManagerContainer
1086###
1087################################################################################
1088################################################################################
1089class VersionManagerContainer:
1090
1091    # --------------------------------------------------------------------------
1092    #  VersionItem.isVersionContainer
1093    # --------------------------------------------------------------------------
1094    def isVersionContainer(self):
1095      b = False
1096      if self.isPage():
1097        b = self.isPageContainer()
1098        if not b:
1099          b = self.meta_id == 'ZMSLinkElement' and self.isEmbedded(self.REQUEST)
1100        if not b:
1101          parent = self.getParentNode()
1102          b = parent is not None and parent.isPageContainer()
1103      return b
1104
1105    # --------------------------------------------------------------------------
1106    #  VersionManagerContainer.getVersionContainer
1107    # --------------------------------------------------------------------------
1108    def getVersionContainer(self):
1109      if self.isVersionContainer() or self.getParentNode() is None:
1110        return self
1111      return self.getParentNode().getVersionContainer()
1112
1113
1114    """
1115    ############################################################################
1116    #  Notification
1117    ############################################################################
1118    """
1119
1120    # --------------------------------------------------------------------------
1121    #  VersionManagerContainer.getRecipientWf
1122    # --------------------------------------------------------------------------
1123    def getRecipientWf(self, REQUEST=None):
1124      raw = self.getConfProperty('zms._versionmanager.getRecipientWf.raw',0)!=0
1125      recipient = ''
1126      name = self.getObjProperty('work_uid',REQUEST)
1127      if raw:
1128        userObj = self.findUser(name)
1129        recipient = userObj
1130      else:
1131        mto = self.getUserAttr(name,'email','')
1132        if len(mto) > 0:
1133          recipient = name + ' <' + mto + '>'
1134      return recipient
1135   
1136    # --------------------------------------------------------------------------
1137    #  VersionManagerContainer.getRecipientsByRole
1138    # --------------------------------------------------------------------------
1139    def getRecipientsByRole(self, roles=['ZMSEditor'], REQUEST=None):
1140      raw = self.getConfProperty('zms._versionmanager.getRecipientsByRole.raw',0)!=0
1141      recipients = []
1142      langs = [REQUEST['lang']]
1143      ob = self
1144      while ob is not None and len(recipients) == 0:
1145        for local_role in ob.get_local_roles():
1146          name = local_role[0]
1147          userObj = self.findUser(name)
1148          mto = self.getUserAttr(name,'email','')
1149          if userObj is not None and len(mto) > 0 and \
1150             len(self.intersection_list(roles, ob.getUserRoles(userObj, aq_parent=0))) > 0 and \
1151             len(self.intersection_list(langs, ob.getUserLangs(userObj, aq_parent=0))) > 0:
1152            if raw:
1153              recipients.append( userObj)
1154            else:
1155              recipients.append( name + ' <' + mto + '>')
1156        ob = ob.getParentNode()
1157      if raw:
1158        return recipients
1159      return ', '.join( recipients)
1160
1161    """
1162    ############################################################################
1163    #  Workflow
1164    ############################################################################
1165    """
1166
1167    # --------------------------------------------------------------------------
1168    #  VersionManagerContainer.resetWfStates:
1169    #
1170    #  Resets information about workflow-events.
1171    # --------------------------------------------------------------------------
1172    def resetWfStates(self, REQUEST):
1173      lang = REQUEST['lang']
1174      self.delObjStates(self.getWfActivitiesIds(), REQUEST)
1175      self.autoWfTransition(REQUEST)
1176
1177    # --------------------------------------------------------------------------
1178    #  VersionManagerContainer.logWfTransition
1179    # --------------------------------------------------------------------------
1180    def logWfTransition(self, id, desc, REQUEST=None):
1181      REQUEST = _globals.nvl( REQUEST, self.REQUEST)
1182      lang = REQUEST.get('lang')
1183      # Set Properties.
1184      dt = _globals.getDateTime( time.time())
1185      uid = str(REQUEST.get('AUTHENTICATED_USER'))
1186      # Log Protocol.
1187      log = ''
1188      log = log + self.getLangFmtDate(dt,lang,'%Y-%m-%d %H:%M:%S') + '\t'
1189      log = log + id + '\t'
1190      log = log + self.absolute_url()[len(self.getHome().absolute_url()):] + '\t'
1191      log = log + self.display_type(REQUEST) + '\t'
1192      log = log + uid + '\t'
1193      log = log + desc
1194      self.workflow_manager.writeProtocol(log)
1195
1196    # --------------------------------------------------------------------------
1197    #  VersionManagerContainer.autoWfTransition
1198    # --------------------------------------------------------------------------
1199    def autoWfTransition(self, REQUEST):
1200      _globals.writeBlock( self, "[autoWfTransition]")
1201      lang = REQUEST['lang']
1202      # Enter Container.
1203      if not self.isVersionContainer():
1204        versionContainer = self.getVersionContainer()
1205        if versionContainer != self:
1206          return versionContainer.autoWfTransition(REQUEST)
1207     
1208      # Enter Workflow.
1209      self.syncObjModifiedChildren(REQUEST)
1210      wfStates = self.getWfStates(REQUEST)
1211      _globals.writeBlock( self, "[autoWfTransition]: wfStates=%s"%str(wfStates))
1212      modified = self.isObjModified(REQUEST) or self.hasObjModifiedChildren(REQUEST)
1213      # Check if current workflow-state is empty.
1214      enter = len(wfStates) == 0
1215      if not enter:
1216        # Check if current workflow-state is from-state of a workflow-exit (empty to-state).
1217        for wfTransition in self.getWfTransitions():
1218          if len(self.intersection_list(wfStates, wfTransition.get('from',[]))) > 0 and \
1219             len(wfTransition.get('to',[])) == 0:
1220            _globals.writeBlock( self, "[autoWfTransition]: enter name=%s, id=%s, to=%s"%(wfTransition['name'],wfTransition['id'],str(wfTransition['to'])))
1221            enter = True
1222            break
1223      if modified and enter:
1224        # Initialize with workflow-entry (empty from-state).
1225        for wfTransition in self.getWfTransitions():
1226          if len(wfTransition.get('from',[])) == 0 and \
1227             len(wfTransition.get('to',[])) == 1:
1228            _globals.writeBlock( self, "[autoWfTransition]: name=%s, id=%s, to=%s"%(wfTransition['name'],wfTransition['id'],str(wfTransition['to'])))
1229            # Delete old state.
1230            _globals.writeBlock( self, "[autoWfTransition]: delObjStates(%s)"%str(wfStates))
1231            self.delObjStates(wfStates, REQUEST)
1232            # Add new state.
1233            self.setObjState(wfTransition.get('to',[])[0], lang)
1234            # Set Properties.
1235            self.setObjProperty('work_uid',str(REQUEST.get('AUTHENTICATED_USER')),lang)
1236            self.setObjProperty('work_dt',_globals.getDateTime( time.time()),lang)
1237            break
1238
1239
1240    ############################################################################
1241    #  VersionManagerContainer.manage_wfTransition:
1242    #
1243    #  Workflow transition.
1244    ############################################################################
1245    def manage_wfTransition(self, lang, custom, REQUEST, RESPONSE):
1246      """ WorkflowContainer.manage_wfTransition """
1247      _globals.writeBlock( self, "[manage_wfTransition]")
1248      wfTransitions = self.getWfTransitions()
1249      for wfTransition in filter(lambda x: x['name']==custom, wfTransitions):
1250        dtml = wfTransition.get('dtml','')
1251        if len(dtml) > 0:
1252          return _globals.dt_html(self, dtml, REQUEST)
1253        else:
1254          return self.manage_wfTransitionFinalize(lang, custom, REQUEST, RESPONSE)
1255
1256
1257    ############################################################################
1258    #  VersionManagerContainer.manage_wfTransitionFinalize:
1259    #
1260    #  Workflow transition finalize.
1261    ############################################################################
1262    def manage_wfTransitionFinalize(self, lang, custom, REQUEST, RESPONSE=None):
1263      """ WorkflowContainer.manage_wfTransitionFinalize """
1264      _globals.writeBlock( self, "[manage_wfTransitionFinalize]")
1265      url = ''
1266      message = ''
1267      wfTransitions = self.getWfTransitions()
1268      _globals.writeBlock( self, "[manage_wfTransition]: wfTransitions.0=%s"%str(map(lambda x: x['id'],wfTransitions)))
1269      wfTransitions = filter(lambda x: x['name']==custom, wfTransitions)
1270      _globals.writeBlock( self, "[manage_wfTransition]: wfTransitions.1=%s"%str(map(lambda x: x['id'],wfTransitions)))
1271      for wfTransition in wfTransitions:
1272        # Delete old state.
1273        wfStates = self.getWfStates(REQUEST)
1274        _globals.writeBlock( self, "[manage_wfTransition]: delObjStates(%s)"%str(wfStates))
1275        self.delObjStates(wfStates, REQUEST)
1276        # Add new state.
1277        for wfState in wfTransition.get('to',[]):
1278          _globals.writeBlock( self, "[manage_wfTransition]: Add %s"%wfState)
1279          self.setObjState(wfState, lang)
1280          message += REQUEST.get('manage_tabs_message', filter(lambda x: x['id']==wfState,self.getWfActivities())[0]['name'])
1281        # Set Properties.
1282        work_dt = _globals.getDateTime( time.time())
1283        work_uid = str(REQUEST.get('AUTHENTICATED_USER'))
1284        work_desc = REQUEST.get('work_desc','')
1285        self.setObjProperty('work_uid',work_uid,lang)
1286        self.setObjProperty('work_dt',work_dt,lang)
1287        # Log Protocol.
1288        self.logWfTransition(wfTransition['id'],work_desc,REQUEST)
1289      self.autoWfTransition(REQUEST)
1290      # Return with message.
1291      if RESPONSE is not None:
1292        return RESPONSE.redirect('%s/manage_main?lang=%s&manage_tabs_message=%s'%(self.absolute_url(),lang,message))
1293
1294
1295    """
1296    ############################################################################
1297    #  Tasks
1298    ############################################################################
1299    """
1300
1301    # Management Interface.
1302    # ---------------------
1303    manage_tasks = HTMLFile('dtml/versionmanager/manage_tasks', globals())
1304    task_wf = HTMLFile('dtml/versionmanager/tasklist0', globals())
1305    task_zmsnote = HTMLFile('dtml/versionmanager/tasklist1', globals())
1306    task_untranslated = HTMLFile('dtml/versionmanager/tasklist2', globals())
1307    task_changed_by_date = HTMLFile('dtml/versionmanager/tasklist3', globals())
1308
1309
1310    """
1311    ############################################################################
1312    #  Commit
1313    ############################################################################
1314    """
1315
1316    # --------------------------------------------------------------------------
1317    #  VersionManagerContainer.commitObj:
1318    #
1319    #  Commit container.
1320    # --------------------------------------------------------------------------
1321    def commitObj(self, REQUEST={}, forced=False, do_history=True):
1322      _globals.writeLog( self, "[commitObj]: forced=%s, do_history=%s"%(str(forced),str(do_history)))
1323      prim_lang = self.getPrimaryLanguage()
1324      lang = REQUEST.get('lang',prim_lang)
1325     
1326      ##### ZMS.Title ####
1327      if self.getLevel()==0:
1328        self.getHome().title = self.getTitle(REQUEST)
1329     
1330      ##### Version ####
1331      if (lang == prim_lang or self.getDCCoverage(REQUEST).find('.%s'%lang) > 0) and (self.getHistory() and do_history):
1332        version_items = self.getVersionItems( REQUEST, recursive=True)
1333        is_modified = self.isObjModified( REQUEST)
1334        has_modified_children = self.hasObjModifiedChildren( REQUEST)
1335        forced = forced or not is_modified and has_modified_children
1336        if is_modified or has_modified_children:
1337          change_history = self.getObjProperty( 'change_history', REQUEST)
1338          if type( change_history) is list:
1339            if len( change_history) == 0:
1340              version_dt = self.getObjProperty( 'change_dt', REQUEST)
1341              for version_item in version_items:
1342                change_dt = version_item.getObjProperty( 'change_dt', REQUEST)
1343                if version_dt is None or version_dt < change_dt:
1344                  change_dt = version_dt
1345              record = {}
1346              record[ 'version_dt'] = version_dt
1347              record[ 'version_uid'] = self.getObjProperty( 'change_uid', REQUEST)
1348              record[ 'master_version'] = self.getObjProperty( 'master_version', REQUEST)
1349              record[ 'major_version'] = self.getObjProperty( 'major_version', REQUEST)
1350              change_history.append( record)
1351            record = {}
1352            record[ 'version_dt'] = _globals.getDateTime( time.time())
1353            record[ 'version_uid'] = str( REQUEST.get( 'AUTHENTICATED_USER', None))
1354            record[ 'master_version'] = self.getObjProperty( 'master_version', REQUEST)
1355            record[ 'major_version'] = self.getObjProperty( 'major_version', REQUEST) + 1
1356            change_history.append( record)
1357            self.setObjProperty( 'change_history', change_history)
1358     
1359      ##### Self ####
1360      if REQUEST.has_key('lang'):
1361        self.resetWfStates(REQUEST)
1362      parent = self.getParentNode()
1363      delete = self.commitObjChanges(parent,REQUEST,forced,do_history)
1364      url = self.absolute_url()
1365      if delete:
1366        url = parent.absolute_url()
1367        try: REQUEST.set('ZMS_REDIRECT_PARENT',True)
1368        except: REQUEST['ZMS_REDIRECT_PARENT'] = True
1369       
1370      # Return new URL.
1371      _globals.writeLog( self, "[commitObj]: Finished!")
1372      return url
1373
1374
1375    """
1376    ############################################################################
1377    #  Rollback
1378    ############################################################################
1379    """
1380
1381    # --------------------------------------------------------------------------
1382    #  VersionManagerContainer.rollbackObj
1383    # --------------------------------------------------------------------------
1384    def rollbackObj(self, REQUEST):
1385      _globals.writeBlock( self, "[rollbackObj]")
1386       
1387      ##### Self ####
1388      if REQUEST.has_key('lang'): self.resetWfStates(REQUEST)
1389      parent = self.getParentNode()
1390      delete = self.rollbackObjChanges(parent,REQUEST)
1391      url = self.absolute_url()
1392      if delete:
1393        url = parent.absolute_url()
1394        try: REQUEST.set('ZMS_REDIRECT_PARENT',True)
1395        except: REQUEST['ZMS_REDIRECT_PARENT'] = True
1396       
1397      _globals.writeLog( self, "[rollbackObj]: Finished!")
1398      # Return new URL.
1399      return url
1400
1401
1402# call this to initialize framework classes, which
1403# does the right thing with the security assertions.
1404Globals.InitializeClass(VersionItem)
1405
1406################################################################################
Note: See TracBrowser for help on using the repository browser.