Back to index

plone3  3.1.7
historyaware.py
Go to the documentation of this file.
00001 #  ATContentTypes http://plone.org/products/atcontenttypes/
00002 #  Archetypes reimplementation of the CMF core types
00003 #  Copyright (c) 2003-2006 AT Content Types development team
00004 #
00005 #  This program is free software; you can redistribute it and/or modify
00006 #  it under the terms of the GNU General Public License as published by
00007 #  the Free Software Foundation; either version 2 of the License, or
00008 #  (at your option) any later version.
00009 #
00010 #  This program is distributed in the hope that it will be useful,
00011 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 #  GNU General Public License for more details.
00014 #
00015 #  You should have received a copy of the GNU General Public License
00016 #  along with this program; if not, write to the Free Software
00017 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 #
00019 """History awareness
00020 
00021 
00022 """
00023 __author__  = 'Christian Heimes <tiran@cheimes.de>, Christian Theune'
00024 __docformat__ = 'restructuredtext'
00025 
00026 import difflib
00027 
00028 from DocumentTemplate.DT_Util import html_quote
00029 from Globals import InitializeClass
00030 
00031 from Products.CMFCore.utils import getToolByName
00032 from Products.CMFCore.permissions import View
00033 from AccessControl import ClassSecurityInfo
00034 
00035 from Products.Archetypes.atapi import ATHistoryAwareMixin
00036 from Products.ATContentTypes import permission as ATCTPermissions
00037 from Products.ATContentTypes.interfaces import IHistoryAware
00038 
00039 class HistoryAwareMixin(ATHistoryAwareMixin):
00040     """History aware mixin class
00041 
00042     Shows a unified diff history of the content
00043 
00044     This mixin is using some low level functions of the ZODB to get the last
00045     transaction states (versions) of the current object. Older histories will
00046     disapear after packing the database so DO NOT rely on the history
00047     functionality. It's more a gimmick and nice helper to reviewers and site
00048     managers.
00049     """
00050 
00051     __implements__ = (IHistoryAware ,)
00052 
00053     security       = ClassSecurityInfo()
00054 
00055     actions = ({
00056         'id'          : 'history',
00057         'name'        : 'History',
00058         'action'      : 'string:${object_url}/atct_history',
00059         'permissions' : (ATCTPermissions.ViewHistory, ),
00060         'visible' : False,
00061          },
00062     )
00063 
00064     security.declarePrivate('getHistorySource')
00065     def getHistorySource(self):
00066         """get source for HistoryAwareMixin
00067 
00068         Must return a (raw) string
00069         """
00070         primary = self.getPrimaryField()
00071         if primary:
00072             return primary.getRaw(self)
00073         else:
00074             return ''
00075 
00076     security.declareProtected(View, 'getLastEditor')
00077     def getLastEditor(self):
00078         """Returns the user name of the last editor.
00079 
00080         Returns None if no last editor is known.
00081         """
00082         histories = list(self.getHistories(1))
00083         if not histories:
00084             return None
00085         user = histories[0][3].split(" ")[-1].strip()
00086         return  user
00087 
00088     security.declareProtected(ATCTPermissions.ViewHistory, 'getDocumentComparisons')
00089     def getDocumentComparisons(self, max=10, filterComment=0):
00090         """Get history as unified diff
00091         """
00092         mTool = getToolByName(self, 'portal_membership')
00093 
00094         histories = list(self.getHistories())
00095         if max > len(histories):
00096             max = len(histories)
00097 
00098         lst = []
00099 
00100         for revisivon in range(1, max):
00101 
00102             oldObj, oldTime, oldDesc, oldUser = histories[revisivon]
00103             newObj, newTime, newDesc, newUser = histories[revisivon-1]
00104 
00105             oldText  = oldObj.getHistorySource().split("\n")
00106             newText  = newObj.getHistorySource().split("\n")
00107             # newUser is a string 'user' or 'folders to acl_users user'
00108             member   = mTool.getMemberById(newUser.split(' ')[-1])
00109 
00110             lines = [
00111                      html_quote(line)
00112                      for line in difflib.unified_diff(oldText, newText)
00113                     ][3:]
00114 
00115             description = newDesc
00116             if filterComment:
00117                 relativUrl = self.absolute_url(1)
00118                 description = '<br />\n'.join(
00119                               [line
00120                                for line in description.split('\n')
00121                                if line.find(relativUrl) != -1]
00122                               )
00123             else:
00124                 description.replace('\n', '<br />\n')
00125 
00126             if lines:
00127                 lst.append({
00128                             'lines'       : lines,
00129                             'oldTime'     : oldTime,
00130                             'newTime'     : newTime,
00131                             'description' : description,
00132                             'user'        : newUser,
00133                             'member'      : member
00134                            })
00135         return lst
00136 
00137 InitializeClass(HistoryAwareMixin)