File:  [Repository] / versionedFile / extVersionedFile.py
Revision 1.38: download - view: text, annotated - select for diffs - revision graph
Mon Dec 5 07:42:38 2011 UTC (12 years, 4 months ago) by dwinter
Branches: MAIN
CVS tags: HEAD
minor

"""actual version of the versioned file folder with external filestorage, 
using the ExtFile Product, this version replaces externaVersionedFile.py
DW 11.10.2006
"""

import email
from OFS.Folder import Folder
from OFS.Image import File
from OFS.Image import cookId
from Globals import DTMLFile, InitializeClass,package_home
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from AccessControl import getSecurityManager
from Products.PageTemplates.PageTemplate import PageTemplate
from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
from AccessControl import ClassSecurityInfo
from difflib import Differ
from pprint import pprint
from Products.ExtFile.ExtFile import * 
from Products.ZCatalog.CatalogPathAwareness import CatalogAware

try:
    from Products.ImageArchive.ImageArchive import manage_AddImageZogiLib
except:
    print "no images"

from threading import Thread
import shutil
import tempfile
import os.path
import urllib
import time
import logging
import types

try:
    from Products.ECHO_content.ECHO_collection import ECHO_basis
except:
    print "ECHO Elements not imported"
    class ECHO_basis:
        """leer"""
        manage_options=()

	
def sortv(x,y):
    return cmp(x[0],y[0])

tdir = "/tmp/downloadVersionedFiles"

class generateDownloadZip:
    """generateDownloadSet"""

    def __init__(self,folderObject,url):
        """init downloadzip"""
        self.folder=folderObject
        self.done=None
        self.response=""
        self.url=url
        
    def __call__(self):
        """call generate download zip"""
        storeTempDir=tempfile.tempdir
        tempfile.tempdir=tdir

        tmpPath=tempfile.mktemp()
        tmpZip=tempfile.mktemp()+".tgz"
        tmpFn=os.path.split(tmpZip)[1]
        
        if not os.path.exists(tempfile.tempdir):
            os.mkdir(tempfile.tempdir) 

        if not os.path.exists(tmpPath):
            os.mkdir(tmpPath) 
	    
        self.response="<h3>1. step: getting the files</h3>"

        for files in self.folder.ZopeFind(self.folder,obj_metatypes=['extVersionedFile']):
            lastV=files[1].getContentObject()
            self.response+=str("<p>Get File: %s<br>\n"%lastV.title)

            savePath=os.path.join(tmpPath,lastV.title)
            fh=file(savePath,"w")
            fh.write(lastV.getData())
            fh.close()

        self.response+="<h3>2. step: creating the downloadable file</h3>"
        self.response+="<p>Create gtar<br>"
        self.response+="<p>This can take a while....<br>\n"

        fh=os.popen2("tar zcvf %s %s/*"%(tmpZip,tmpPath),1)[1]
        self.response+="<br>"
        for c in fh.read():
            self.response+=c
            if c==")":
                self.response+="<br>\n"
        
        shutil.rmtree(tmpPath)

        self.response+="<p>finished<br>\n"

        len=os.stat(tmpZip)[6]
        downloadUrl=self.url+"/downloadSet"
        self.response+="""<h1><a href="downloadSet?fn=%s">Click here for download ( %i Byte)</a></h1>\n"""%(tmpFn,len)
        self.response+="""<p>The file you receive is a tar (gnutar) compressed file, after unpacking you will find a new folder <emph>tmp</emph> where the files are stored in.</p>"""
        self.response+="""<p>The file will be stored for a while, you can download it later, the URL is:</p>
		    <p><a href="downloadSet?fn=%s">%s?fn=%s</a></h1>\n"""%(tmpFn,downloadUrl,tmpFn)

        self.done=True

        
    def getResult(self):
        """get result"""
        return self.response

    def isDone(self):
        if self.done:
            return True
        else:
            return False
        

class extVersionedFileFolder(Folder,ECHO_basis):
    """Folder with versioned files"""
    meta_type = "extVersionedFileFolder"

    security= ClassSecurityInfo()
    security.declareProtected('AUTHENTICATED_USER','addFileForm')

    file_meta_type=['extVersionedFile']

    if ECHO_basis:
        optTMP= Folder.manage_options+ECHO_basis.manage_options
    else:
        optTMP= Folder.manage_options

    manage_options =optTMP+(
        {'label':'Generate Index.html','action':'generateIndexHTML'},
        {'label':'Generate Image Index.html','action':'generateIndexHTML_image'},
        {'label':'Generate history_template.html','action':'generateHistoryHTML'},
        {'label':'Import directory','action':'importFolderForm'},
        {'label':'Export as file','action':'exportFolder'},
        {'label':'Import versionedFileFolder','action':'importVersionedFileFolderForm'},
        {'label':'Position of version number','action':'changeHistoryFileNamesForm'},
        )

    
    def redirect(self,RESPONSE,url):
        """mache ein redirect mit einem angehaengten time stamp um ein reload zu erzwingen"""
        
        timeStamp=time.time()
        
        if url.find("?")>-1: #giebt es schon parameter
            addStr="&time=%s"
        else:
            addStr="?time=%s"
            
        RESPONSE.setHeader('Last-Modified',email.Utils.formatdate().split("-")[0]+'GMT')
        logging.error(email.Utils.formatdate()+' GMT')
        RESPONSE.redirect(url+addStr%timeStamp)
        
    def changeHistoryFileNamesForm(self):
        """change position of version num"""
        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','changeHistoryFileNamesForm.zpt')).__of__(self)
        return pt()
    
    
    def changeHistoryFileNames(self,positionVersionNum="front",RESPONSE=None):
        """change position of version num"""
        versions=self.ZopeFind(self,obj_metatypes=['extVersionedFileObject'],search_sub=1)
        
        if not (getattr(self,'positionVersionNum','front')==positionVersionNum):

            for version in versions:
                
                if positionVersionNum=="front":
                    
                    titleTmp=os.path.splitext(version[1].title)
                    titleTmp2="_".join(titleTmp[0].split("_")[0:-1])
                    if len(titleTmp)>1:
                        id=titleTmp[0].split("_")[-1]+"_"+titleTmp2+"."+titleTmp[1]
                    else:
                        id=titleTmp[0].split("_")[-1]+"_"+titleTmp2

                else:
                    titleTmp="_".join(version[1].getId().split("_")[1:])
                    tmp=os.path.splitext(titleTmp)
                    if len(tmp)>1:
                        id=tmp[0]+"_"+version[1].getId().split("_")[0]+tmp[1]
                    else:
                        id=tmp[0]+"_"+version[1].getId().split("_")[0]
                
                version[1].aq_parent.manage_renameObjects(ids=[version[1].getId()],new_ids=[id])
                version[1].title=id
                
        self.positionVersionNum=positionVersionNum        
        if RESPONSE:
            RESPONSE.redirect("manage_main")
        
        
        
    def importFolderForm(self):
        """form fuer folder import"""
        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','importFolderForm.zpt')).__of__(self)
        return pt()
    
    def importFolder(self,path,comment="",author=None,lockedBy=None,RESPONSE=None):
        """import contents of a folder on the server"""
        for fileName in os.listdir(path):
            fn = os.path.join(path,fileName)
            if os.path.isfile(fn):
                f = file(fn)
                self.addFile(vC=comment, file=f, author=author)
        
        if RESPONSE:
            RESPONSE.redirect(self.REQUEST['URL1'])

    def importVersionedFileFolderForm(self):
        """form fuer versionedFileFolder import"""
        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','importVersionedFileFolderForm.zpt')).__of__(self)
        return pt()
    
    def importVersionedFileFolder(self,path,RESPONSE=None):
        """import contents of a versionedFileFolder on the server"""
        vff = getattr(self.aq_parent, path, None)
        if vff is None:
            return "SORRY, unable to import %s"%path
        
        tmpPath=tempfile.mktemp()
        if not os.path.exists(tempfile.tempdir):
            os.mkdir(tempfile.tempdir) 

        if not os.path.exists(tmpPath):
            os.mkdir(tmpPath) 

        for (vfn, vf) in vff.getVersionedFiles():
            if vf.meta_type == 'versionedFile':
                logging.error("importvff: importing %s of type %s!"%(vfn,vf.meta_type))
                title = vf.title
                fob = vf.getLastVersion()
                author = fob.getLastEditor()
                vc = fob.getVersionComment()
                # save file to filesystem
                savePath=os.path.join(tmpPath,title)
                fh=file(savePath,"w")
                data = vf.getLastVersion().data
                if isinstance(data, str):
                    # simple data object
                    fh.write(data)
                else:
                    # chained data objects
                    while data is not None:
                        fh.write(data.data)
                        data = data.next
                fh.close()
                # and read in again
                fh = file(savePath)
                logging.error("importvff: comment=%s author=%s!"%(vc,author))
                self.addFile(vC=vc, file=fh, author=author)
                # copy more fields
                newfob = getattr(self, vfn).getContentObject()
                newfob.vComment = fob.vComment
                newfob.time = fob.time
                logging.error("importvff: vc=%s time=%s of %s!"%(fob.vComment,fob.time,fob.getId()))
                
            else:
                logging.error("importvff: unable to import %s of type %s!"%(vfn,vf.meta_type))
        
        shutil.rmtree(tmpPath)

        if RESPONSE:
            RESPONSE.redirect(self.REQUEST['URL1'])

    zipThreads={}
    zipThreads2={}

    def refreshTxt(self):
        """txt fuer refresh"""
        tn=self.REQUEST.SESSION['threadName']
        return """ 2;url=%s?repeat=%s """%(self.absolute_url()+"/exportFolder",tn)

    def exportFolder(self,repeat=None):
        """exportiert alle akutellen files des folders"""
        threadName=repeat
        
        downloadZip=generateDownloadZip(self,self.absolute_url())
        downloadZip()
        return downloadZip.getResult()
    
       ##  if not threadName or threadName=="":
##             threadStart=generateDownloadZip(self,self.absolute_url())
##             thread=Thread(target=threadStart)
    
##             thread.start()

    
##             self.zipThreads[thread.getName()[0:]]=threadStart
##             self.zipThreads2[thread.getName()[0:]]=thread
##             self.REQUEST.SESSION['threadName']=thread.getName()[0:]
##             wait_template=self.aq_parent.ZopeFind(self.aq_parent,obj_ids=['zip_wait_template'])
##             if wait_template:
##                 return wait_template[0][1]()
##             pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','zip_wait.zpt')).__of__(self)
##             return pt()
    
##         else:
##             self.REQUEST.SESSION['threadName']=threadName

##             if (self.zipThreads[threadName].getResult()==None):

##                 wait_template=self.aq_parent.ZopeFind(self.aq_parent,obj_ids=['wait_template'])
##                 if wait_template:
##                     return wait_template[0][1]()

##                 pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','zip_wait.zpt')).__of__(self)
##                 return pt()
##             else:
##                 if self.zipThreads[threadName].isDone():
##                     self.REQUEST.SESSION['result']=self.zipThreads[threadName].getResult()
##                     self.zipThreads2[threadName].join()
##                     del(self.zipThreads2[threadName])
##                     del(self.zipThreads[threadName])
##                     pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','zip_result.zpt')).__of__(self)
##                     return pt()

##                 else:
##                     self.REQUEST.SESSION['result']=self.zipThreads[threadName].getResult()
##                     self.REQUEST.SESSION['threadName']=threadName
##                     pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','zip_wait_result.zpt')).__of__(self)
##                     return pt()

    def downloadSet(self,fn):
        """download prepared set"""
        filename=os.path.join(tdir,fn)

        
        self.REQUEST.RESPONSE.setHeader("Content-Disposition","""attachement; filename="%s" """%"downloadFileFolder.tgz")
        self.REQUEST.RESPONSE.setHeader("Content-Type","application/octet-stream")
        len=os.stat(filename)[6]
        self.REQUEST.RESPONSE.setHeader("Content-Length",len)
        images=file(filename).read()
        self.REQUEST.RESPONSE.write(images)
        self.REQUEST.RESPONSE.close()

	

    def helpDownload(self):
        """download help"""
        
        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','helpDownload')).__of__(self)
        return pt()
    
    def generateIndexHTML_image(self,RESPONSE=None):
        """lege standard index.html an"""


        if not self.ZopeFind(self,obj_ids=['index.html']):
            zt=ZopePageTemplate('index.html')
            self._setObject('index.html',zt)
            default_content_fn = os.path.join(package_home(globals()),
                                              'zpt/versionFileFolderMain_image.zpt')
            text = open(default_content_fn).read()
            zt.pt_edit(text, 'text/html')

        else:
            return "already exists!"
        
        if RESPONSE is not None:
            RESPONSE.redirect('manage_main')

    
    def generateAddFileForm(self,RESPONSE=None):
        """lege standard addfileform an"""
        #TODO: write generateaddfileform only a dummy at them moment

        if not self.ZopeFind(self,obj_ids=['addFileForm.dtml']):
            zt=ZopePageTemplate('index.html')
            self._setObject('index.html',zt)
            default_content_fn = os.path.join(package_home(globals()),
                                              'zpt/versionFileFolderMain.zpt')
            text = open(default_content_fn).read()
            zt.pt_edit(text, 'text/html')

        else:
            return "already exists!"
        
        if RESPONSE is not None:
            RESPONSE.redirect('manage_main')


    def generateIndexHTML(self,RESPONSE=None):
        """lege standard index.html an"""
        if not self.ZopeFind(self,obj_ids=['index.html']):
            zt=ZopePageTemplate('index.html')
            self._setObject('index.html',zt)
            default_content_fn = os.path.join(package_home(globals()),
                                              'zpt/versionFileFolderMain.zpt')
            text = open(default_content_fn).read()
            zt.pt_edit(text, 'text/html')

        else:
            return "already exists!"
        
        if RESPONSE is not None:
            RESPONSE.redirect('manage_main')


    def generateHistoryHTML(self,RESPONSE=None):
        """lege standard index.html an"""
        if not self.ZopeFind(self,obj_ids=['history_template.html']):
            zt=ZopePageTemplate('history_template.html')
            self._setObject('history_template.html',zt)
            default_content_fn = os.path.join(package_home(globals()),
                                              'zpt/versionHistory.zpt')
            text = open(default_content_fn).read()
            zt.pt_edit(text, 'text/html')

        else:
            return "already exists!"
        
        if RESPONSE is not None:
            RESPONSE.redirect('manage_main')
            

    def getVersionedFiles(self,sortField='title'):
        """get all versioned files"""

        def sortName(x,y):
            return cmp(x[1].title.lower(),y[1].title.lower())

        def sortDate(x,y):
    
                return cmp(y[1].getContentObject().getTime(),x[1].getContentObject().getTime())
           
        def sortComment(x,y):
            try:
                xc=getattr(x[1],'comment','ZZZZZZZZZZZZZ').lower()
            except:
                xc='ZZZZZZZZZZZZZ'.lower()
                
            try:
                yc=getattr(y[1],'comment','ZZZZZZZZZZZZZ').lower()
            except:
                yc='ZZZZZZZZZZZZZ'.lower()

            if (xc=='') or (xc=='ZZZZZZZZZZZZZ'.lower()):
                try:
                    xc=x[1].getContentObject().getVComment().lower()
                except:
                    xc='ZZZZZZZZZZZZZ'.lower()
                   
                            
            if (yc=='') or (yc=='ZZZZZZZZZZZZZ'.lower()):
                try:
                    yc=y[1].getContentObject().getVComment().lower()
                except:
                    yc='ZZZZZZZZZZZZZ'.lower()
                  
                                    
            return cmp(xc,yc)

        def sortAuthor(x,y):
           
                return cmp(x[1].getContentObject().lastEditor().lower(),y[1].getContentObject().lastEditor().lower())
           
            
        def sortVersionComment(x,y):
         
                return cmp(x[1].getContentObject().getVersionComment().lower(),y[1].getContentObject().getVersionComment().lower())
          
        versionedFiles=self.objectItems(self.file_meta_type)
        logging.debug("versionedfiles: %s of type %s"%(repr(versionedFiles),repr(self.file_meta_type)))
        
        if sortField=='title':
            versionedFiles.sort(sortName)
        elif sortField=='date':
            versionedFiles.sort(sortDate)
        elif sortField=='author':
            versionedFiles.sort(sortAuthor)
        elif sortField=='versioncomment':
            versionedFiles.sort(sortVersionComment)
        elif sortField=='comment':
            versionedFiles.sort(sortComment)


        return versionedFiles


    def header_html(self):
        """zusaetzlicher header"""
        ext=self.ZopeFind(self,obj_ids=["header.html"])
        if ext:
            return ext[0][1]()
        else:
            return ""


    security.declareProtected('View','index_html')
    def index_html(self):
        """main"""
        ext=self.ZopeFind(self,obj_ids=["index.html"])
        if ext:
            return ext[0][1]()
        
        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','versionFileFolderMain')).__of__(self)
        return pt()



    def addFileForm(self):
        """add a file"""
        ext=self.ZopeFind(self,obj_ids=["addFileForm.dtml"])
        if ext:
            return ext[0][1]('',globals(),version='1',AUTHENTICATED_USER=self.REQUEST.AUTHENTICATED_USER)
        
        out=DTMLFile('dtml/newFileAdd', globals(),Kind='versionedFileObject',kind='versionedFileObject',version='1').__of__(self)
        return out()


    def addFile(self,vC,file,author='',newName='',content_type='',RESPONSE=None):
        """ add a new file"""
        # is file is a real file or a zope download object?
        isRealFile = type(file) is types.FileType

        if newName=='':
            logging.debug("fileobject: %s real:%s"%(repr(file),repr(isRealFile)))
            if isRealFile:
                filename = file.name
            else:
                filename=file.filename

            id=filename[max(filename.rfind('/'),
                            filename.rfind('\\'),
                            filename.rfind(':'),
                            )+1:]

        else:
            id=newName
        
        if vC is None:
            vC=self.REQUEST.form['vC']
        
        # get new extVersionedFile
        vf = self._newVersionedFile(id,title=id)
        logging.error("addFile id=%s vf=%s of %s"%(repr(id),repr(vf),repr(self)))
        # add its content (and don't index)
        self._setObject(id,vf)
        vf=getattr(self,id)

        obj=vf.addContentObject(id,vC,author=author,file=file,content_type=content_type,from_tmp=isRealFile,index=False)
        # add file to this folder (this should do the indexing)
        #self._setObject(id,vf)
        
        try:
            self.REQUEST.SESSION['objID']=vf.getId()
            self.REQUEST.SESSION['objID_parent']=None
        except:
            pass

        if obj.getSize()==0:
            pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','errorUploadFile')).__of__(self)
            return pt()
        
        if RESPONSE is not None:
            RESPONSE.redirect(self.REQUEST['URL1'])


    def _newVersionedFile(self, id, title='', lockedBy=None, author=None):
        """factory for versioned files. to be overridden in derived classes."""
        return extVersionedFile(id, title, lockedBy=lockedBy, author=author)


    def deleteEmptyObject(self,submit,RESPONSE=None):
        """deleteemptyobject"""
        if submit=="delete it":
            if self.REQUEST.SESSION['objID_parent']:
                obj=getattr(self,self.REQUEST.SESSION['objID_parent'])

            else:
                obj=self
            obj.manage_delObjects([self.REQUEST.SESSION['objID']])

        RESPONSE.redirect(self.REQUEST['URL1'])
        

    security.declareProtected('AUTHENTICATED_USER','fixVersionNumbers')    
    def fixVersionNumbers(self):
        """fix last version number of all files"""
        for (id,vf) in self.getVersionedFiles():
            vf.fixVersionNumbers()
        # recursively
        for (id,vf) in self.objectItems(self.meta_type):
            vf.fixVersionNumbers()
        

manage_addextVersionedFileFolderForm=DTMLFile('dtml/extfolderAdd', globals())


def manage_addextVersionedFileFolder(self, id, title='',
                                     createPublic=0,
                                     createUserF=0,
                                     REQUEST=None):
    """Add a new Folder object with id *id*.

    If the 'createPublic' and 'createUserF' parameters are set to any true
    value, an 'index_html' and a 'UserFolder' objects are created respectively
    in the new folder.
    """
    ob=extVersionedFileFolder()
    ob.id=str(id)
    ob.title=title
    self._setObject(id, ob)
    ob=self._getOb(id)

    checkPermission=getSecurityManager().checkPermission

    if createUserF:
        if not checkPermission('Add User Folders', ob):
            raise Unauthorized, (
                'You are not authorized to add User Folders.'
                )
        ob.manage_addUserFolder()

        
    if REQUEST is not None:
        return self.manage_main(self, REQUEST, update_menu=1)



class extVersionedFileObject(ExtFile):
    """File Object im Folder"""
    security= ClassSecurityInfo()
    meta_type = "extVersionedFileObject"
    
    manage_editForm=DTMLFile('dtml/fileEdit',globals(),
                               Kind='File',kind='file')
    manage_editForm._setName('manage_editForm')

    def __init__(self, id, title='', versionNumber=0, versionComment=None, time=None, author=None):
        """Initialize a new instance of extVersionedFileObject (taken from ExtFile)"""
        ExtFile.__init__(self,id,title)
        self.versionNumber = versionNumber
        self.versionComment= versionComment
        self.time = time
        self.author = author

    security.declareProtected('manage','changeObject')
    def changeObject(self,**args):
        """modify any of the objects attributes"""
        for arg in args:
            if hasattr(self, arg):
                logging.debug("changeObject %s: %s=%s"%(repr(self),arg,args[arg]))
                setattr(self, arg, args[arg])

    security.declarePublic('getTitle')
    def getTitle(self):
        """get title"""
        return self.title
    
    def getData(self):
        """returns object content (calls ExtFile.index_html)"""
        #logging.debug("+++++++getData1:"+repr(self.get_filename()))
        filename = self.get_filename()
        #return ExtFile.index_html(self)
        try:
            logging.info("readfile:"+filename)
            return file(filename).read()
        except:
            logging.info("cannot readfile:"+filename)
            return ExtFile.index_html(self)

    
    def getFileName(self):
        """return filename"""
        return self.get_filename()
    
    def addToFile(self,filehandle):
        filehandle.write(self.getData())
        
    def addToFile2(self,filename):   
         str="cat %s > %s"%(self.get_filename(),filename)
         os.popen(str)
         
    security.declarePublic('getVComment')
    def getVComment(self):
        """get the comment of this file"""
        if not hasattr(self,'vComment') or (not self.vComment) or (self.vComment.lstrip()==""):
            return "Add comment"

        else:
            return self.vComment
        
    def manageVCommentForm(self):
        """add a comment"""
        self.REQUEST.SESSION['refer']=self.REQUEST['HTTP_REFERER']
        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addVComment')).__of__(self)
        return pt()

    def manageVComment(self,text,comment_author,submit,REQUEST=None):
        """manage comments"""
        if submit =='change':
            if text=='':
                self.vComment=None
            else:
                self.vComment=text
                self.vComment_author=comment_author

                self.vComment_date=time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())

        if self.REQUEST.SESSION.has_key('refer'):

            return REQUEST.RESPONSE.redirect(self.REQUEST.SESSION['refer'])
        return REQUEST.RESPONSE.redirect(self.aq_parent.absolute_url()+"/history")
    

    security.declarePublic('getVersionComment')
    def getVersionComment(self):
        """getversioncomment"""
        return self.versionComment
    
    security.declarePublic('getTime')
    def getTime(self):
        """getTime"""
        #return self.bobobase_modification_time().ISO()
        if hasattr(self,'time'):
            return time.strftime("%Y-%m-%d %H:%M:%S",self.time)
        elif hasattr(self,'timefixed'):
            return self.timefixed
        else:
            setattr(self,'timefixed',self.bobobase_modification_time().ISO())
            return self.bobobase_modification_time().ISO()

    def download(self,REQUEST=None,RESPONSE=None):
        """download and lock"""
        
        self.REQUEST.RESPONSE.setHeader("Content-Disposition","""attachement; filename=%s"""%self.getId())
        self.REQUEST.RESPONSE.setHeader("Content-Type","application/octet-stream")
	#try:
	#	txt=self.index_html()
	#except:
	#	txt=self.index_html(REQUEST,RESPONSE)
	#
	#self.REQUEST.RESPONSE.setHeader("Content-Length","str(len(txt)+1000)")
      	
        self.content_type="application/octet-stream"
        return self.getData()
        #self.REQUEST.RESPONSE.redirect(self.absolute_url())
        #txt=urllib.urlopen(self.absolute_url()).read()
        #self.REQUEST.RESPONSE.write(txt)
	

        #self.REQUEST.close()
    
    view = download
    
    security.declareProtected('AUTHENTICATED_USER','downloadLocked')    
    def downloadLocked(self):
        """download and lock"""
        if repr(self.REQUEST['AUTHENTICATED_USER'])=='Anonymous User':
            return "please login first"
        if (not ((self.aq_parent.lockedBy=="") or (self.aq_parent.lockedBy==None))):
            return "cannot be locked because is already locked by %s"%self.lockedBy
        self.aq_parent.lockedBy=self.REQUEST['AUTHENTICATED_USER']

        self.content_type="application/octet-stream"
        self.REQUEST.RESPONSE.redirect(self.absolute_url())
    
    security.declarePublic('getVersionNumber')                                              
    def getVersionNumber(self):
        """get version"""
        return self.versionNumber

    security.declarePublic('getVersionComment')                                              
  

    security.declarePublic('lastEditor')                                              	
    def lastEditor(self):
        """last Editor"""
        if hasattr(self,'author'):
            try:
                ret=self.author.replace("-","\n")
            except:#old version of versionded file sometimes stored the user object and not only the name the following corrects this
                ret=str(self.author).replace("-","\n")
            ret=ret.replace("\r","\n")
            return ret.lstrip().rstrip()

        else:
            jar=self._p_jar
            oid=self._p_oid

            if jar is None or oid is None: return None

            return jar.db().history(oid)[0]['user_name']
    
        
manage_addextVersionedFileObjectForm=DTMLFile('dtml/fileAdd', globals(),Kind='extVersionedFileObject',kind='extVersionedFileObject', version='1')

def manage_addextVersionedFileObject(self,id,vC='',author='', file='',title='',versionNumber=0,
                                     precondition='', content_type='', REQUEST=None):
    """Add a new File object.

    Creates a new File object 'id' with the contents of 'file'"""

    id=str(id)
    title=str(title)
    content_type=str(content_type)
    precondition=str(precondition)
    
    id, title = cookId(id, title, file)

    self=self.this()

    # First, we create the file without data:
    self._setObject(id, extVersionedFileObject(id,title,versionNumber=versionNumber,versionComment=str(vC),author=author))
    fob = self._getOb(id)
    
    # Now we "upload" the data.  By doing this in two steps, we
    # can use a database trick to make the upload more efficient.
    if file:
        fob.manage_upload(file)
    if content_type:
        fob.content_type=content_type

    if REQUEST is not None:
        REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main')



class extVersionedFile(CatalogAware,Folder):
    """Versioniertes File"""

    meta_type = 'extVersionedFile'
    # meta_type of contained objects
    content_meta_type = ['extVersionedFileObject']
    # default catalog for extVersionedFile objects
    default_catalog = 'fileCatalog'
    
    manage_options = Folder.manage_options+({'label':'Main Config','action':'changeVersionedFileForm'},)

    
    security=ClassSecurityInfo()   
    
    def __init__(self, id, title, lockedBy,author,defaultAction='history'):
        """init"""
        self.id=id
        self.title=title
        self.lockedBy=lockedBy
        if self.lockedBy is None:
            self.lockedBy = ''
        self.author=author
        self.lastVersionNumber=0
        self.lastVersionId=None
        self.defaultAction = defaultAction

    security.declarePublic('getTitle')
    def getTitle(self):
        """get title"""
        return self.title
    
    def PrincipiaSearchSource(self):
        """Return cataloguable key for ourselves."""
        return str(self)

    def manageImagesForm(self):
        """manage Images attached to the file"""

        self.REQUEST.SESSION['refer']=self.REQUEST['HTTP_REFERER']
        
        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','manageImage')).__of__(self)
        return pt()

    def manageImages(self,imageUrl=None,caption=None,REQUEST=None):
        """manage URL"""
        if imageUrl and (not imageUrl==""):
            manage_AddImageZogiLib(self,libPath=imageUrl,caption=caption)

        if self.REQUEST.SESSION.has_key('refer'):

            return REQUEST.RESPONSE.redirect(self.REQUEST.SESSION['refer'])
        return REQUEST.RESPONSE.redirect(self.aq_parent.absolute_url())
    
    def changeImages(self,caption=None,submit=None,id=None,REQUEST=None):
        """manage URL"""
        if submit=="change caption":
            image=self.ZopeFind(self,obj_ids=[id])
            if image:
                image[0][1].caption=caption[0:]
        
        elif submit=="delete":
            image=self.ZopeFind(self,obj_ids=[id])
            if image:
                self.manage_delObjects([image[0][1].getId()])

        if self.REQUEST.SESSION.has_key('refer'):
            return REQUEST.RESPONSE.redirect(self.REQUEST.SESSION['refer'])

        return REQUEST.RESPONSE.redirect(self.aq_parent.absolute_url())

    def getImages(self):
        """get Images"""
        images=self.ZopeFind(self,obj_metatypes=["ImageZogiLib"])
        if not images:
            return None
        else:
            return images
        
    security.declarePublic('getComment')
    def getComment(self):
        """get the comment of this file"""
        if not hasattr(self,'comment') or (not self.comment) or (self.comment.lstrip()==""):
            return "Add comment"
        else:
            return self.comment

    def manageCommentForm(self):
        """add a comment"""
        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addComment')).__of__(self)
        return pt()

    def manageComment(self,text,comment_author,submit,REQUEST=None):
        """manage comments"""
        if submit =='change':
            if text=='':
                self.comment=None
            else:
                self.comment=text
                self.comment_author=comment_author

                self.comment_date=time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())

        return REQUEST.RESPONSE.redirect(self.aq_parent.absolute_url())
    
    security.declarePublic('getLastChangeDate')
    def getLastChangeDate(self):
        """get last change date"""
        lv=self.getContentObject()
        if lv:
            time=lv.getTime()
            return time
        return None
    
    def getLastEditor(self):
        """get last change date"""
        lv=self.getContentObject()
        le=lv.lastEditor()
        return le
    
    def getLockedBy(self):
        """get locked by"""
        if self.lockedBy is None:
            self.lockedBy = ''
        return str(self.lockedBy)
    
    def getLastVersionNumber(self):
        """returns the highest version number of all included objects"""
        lv = self.findLastVersion()
        if lv:
            return lv.getVersionNumber()
        else:
            return 0

    def findLastVersion(self):
        """finds and returns the object with the highest version number"""
        lvn=0
        lv=None
        
        for v in self.objectValues(self.content_meta_type):
            logging.debug("findlastversion: check %s"%v.getId())
            if v.getVersionNumber() > lvn:
                    lvn=v.getVersionNumber()
                    lv=v
        
        if lv:
            logging.debug("findlastversion: got %s"%lv.getId())
        return lv

    security.declarePublic('getLastVersion')
    def getLastVersion(self):
        """Last Version (old)"""
#        tmp=0
#        lv=None
#        
#        for v in self.objectValues(self.content_meta_type):
#            #logging.debug("getlastversion: check %s"%v.getId())
#            if v.getVersionNumber() > tmp:
#                    tmp=v.getVersionNumber()
#                    lv=v
#        
#        #ogging.debug("getlastversion: got %s"%lv.getId())
#        return lv
        return self.getContentObject();
     
    def getContentObject(self):
        """returns the last version object"""
        if (not getattr(self, 'lastVersionId', None)) or (not getattr(self, self.lastVersionId, None)):
            # find last version and save it
            lv = self.findLastVersion()
            if lv is None:
                return None
            self.lastVersionNumber = lv.getVersionNumber()
            self.lastVersionId = lv.getId()
        return getattr(self, self.lastVersionId, None)

    security.declarePublic('getData')
    def getData(self):
        """Returns the content of the last version"""
        logging.debug("+++++++getData2")
        ob = self.getContentObject()
        if ob is not None:
            return ob.getData()
        else:
            return None
    
    security.declarePublic('view')
    def view(self,REQUEST=None,RESPONSE=None):
        """Returns the last version's view"""
        ob = self.getContentObject()
        if ob is not None:
            return ob.view(REQUEST=REQUEST,RESPONSE=RESPONSE)
        else:
            return None
    
    def diff(self,data):
        """differenz between lastversion and data"""
        d=Differ()
        tmp=self.getData()
        #print "XX",data,tmp
        try:
            l=list(d.compare(data.splitlines(1),tmp.splitlines(1)))
        except:
            return 0,""
        plus=0
        minus=0
        for a in l:
            if a[0]=='+':
                plus+=1
            if a[0]=='-':
                minus+=1
        
        return max([plus,minus]),l


    security.declarePublic('index_html')
    def index_html(self,REQUEST=None, RESPONSE=None):
        """main view"""
        #lastVersion=self.getContentObject()
        #return "File:"+self.title+"  Version:%i"%lastVersion.versionNumber," modified:",lastVersion.bobobase_modification_time()," size:",lastVersion.getSize(),"modified by:",lastVersion.lastEditor()
        #return "File: %s Version:%i modified:%s size:%s modified by:%s"%(self.title,lastVersion.versionNumber,lastVersion.getTime(),lastVersion.getSize(),lastVersion.lastEditor())
        act = getattr(self, 'defaultAction', 'history')
        if act == 'download':
            return self.getContentObject().download()
        elif act == 'view':
            #return self.getContentObject().download()
            return self.getContentObject().index_html(REQUEST=REQUEST, RESPONSE=RESPONSE)
        else:
            return self.history()

    def getVersionNr(self,nr):
        """get version with number nr"""
        tmp=0
        lastVersion=None
        logging.debug(self.absolute_url())
        for version in self.ZopeFind(self):
            logging.debug("getVersionNr :"+repr(version))
            logging.debug("nr:"+str(nr))
            if hasattr(version[1],'versionNumber'):
                logging.debug("vn:"+repr(version[1].versionNumber))
                if int(version[1].versionNumber) ==nr :
                    return version[1]
        logging.debug("nothing")
        return None
    
    security.declarePublic('getVersion')                                              
    def getVersion(self):
        # TODO: this is ugly and it returns the next version number 
        tmp=0
        for version in self.ZopeFind(self):
            
            if hasattr(version[1],'versionNumber'):
                
                if int(version[1].versionNumber) > tmp:
                    tmp=int(version[1].versionNumber,)
        return tmp+1        

    def history(self):
        """history"""  
        ext=self.ZopeFind(self.aq_parent,obj_ids=["history_template.html"])
        if ext:
            return getattr(self,ext[0][1].getId())()
        
        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','versionHistory')).__of__(self)
        return pt()

    def getVersions(self):
        """get all versions"""
        ret=[]
        for version in self.ZopeFind(self):
            if hasattr(version[1],'versionNumber'):
                ret.append((version[1].versionNumber,version[1]))
        ret.sort(sortv)
        return ret

    def getVersionList(self):
        """get a list of dicts with author, comment, filename, etc, of all versions"""
        vl = []
        for v in self.objectValues(self.content_meta_type):
            vl.append({'versionNumber':getattr(v,'versionNumber',0),
                      'title':v.getTitle(),
                      'id':v.getId(),
                      'date':v.getTime(),
                      'author':getattr(v,'author',''),
                      'comment':getattr(v,'versionComment','')
                      })
        return vl

    security.declareProtected('AUTHENTICATED_USER','forceunlock')   
    def forceunlock(self,RESPONSE=None,user=None):
        """unlock"""
        #safe who had the lock
        logging.debug("extVersionFile: (forceunlock)"+str(user))
        if self.lockedBy:
            if user is not None:
                if str(self.lockedBy)==user:
                    self.brokenLock=str(self.lockedBy)
                    self.lockedBy=''
                else:
                    self.brokenLock=""
            else:
                self.brokenLock=str(self.lockedBy)
                self.lockedBy=''
        else:
            self.brokenLock=""
        
        return self.brokenLock

    security.declareProtected('AUTHENTICATED_USER','unlock')   
    def unlock(self,RESPONSE):
        """unlock"""
        if str(self.lockedBy) in [str(self.REQUEST['AUTHENTICATED_USER'])]:
            self.lockedBy=''
            RESPONSE.redirect(self.REQUEST['HTTP_REFERER'])
        else:
            return "Sorry, not locked by you! (%s,%s)"%(self.lockedBy,self.REQUEST['AUTHENTICATED_USER'])
        
    

    def _newContentObject(self, id, title='', versionNumber=0, versionComment=None, time=None, author=None):
        """factory for content objects. to be overridden in derived classes."""
        return extVersionedFileObject(id,title,versionNumber=versionNumber,versionComment=versionComment,time=time,author=author)


    def addContentObject(self,id,vC,author=None,file=None,title='',changeName='no',newName='',from_tmp=False,index=True,
                         precondition='', content_type=''):
        """add"""
        
        if changeName=="yes":
            filename=file.filename
            self.title=filename[max(filename.rfind('/'),
                                    filename.rfind('\\'),
                                    filename.rfind(':'),
                                    )+1:]

        if not newName=='':
            self.title=newName[0:]
        
        posVersNum=getattr(self,'positionVersionNum','front')
        
        versNum = self.getLastVersionNumber() + 1
        
        if posVersNum=='front':
            id="V%i_%s"%(versNum,self.title)
        else:
            fn=os.path.splitext(self.title)
            if len(fn)>1:
                id=fn[0]+"_V%i%s"%(versNum,fn[1])
            else:
                id=fn[0]+"_V%i"%versNum

        # what does this do?
        id, title = cookId(id, title, file)
        self=self.this()
    
        # First, we create the file without data:
        self._setObject(id, self._newContentObject(id,title,versionNumber=versNum,versionComment=str(vC),
                                              time=time.localtime(),author=author))
        fob = self._getOb(id)
        
        # Now we "upload" the data.  By doing this in two steps, we
        # can use a database trick to make the upload more efficient.
        if file and not from_tmp:
            fob.manage_upload(file)
        elif file and from_tmp:
            fob.manage_file_upload(file) # manage_upload_from_tmp doesn't exist in ExtFile2
        #    fob.manage_upload_from_tmp(file) # manage_upload_from_tmp doesn't exist in ExtFile2
        fob.content_type=content_type
        
        self.lastVersionNumber = versNum
        self.lastVersionId = id
        
        #logging.debug("addcontentobject: lastversion=%s"%self.getData())
        #logging.debug("addcontentobject: fob_data=%s"%fob.getData())
        if index and self.default_catalog:
            logging.debug("reindex1: %s in %s"%(repr(self),repr(self.default_catalog)))
            self.reindex_object()
        
        return fob
            
    
    security.declareProtected('AUTHENTICATED_USER','addVersionedFileObjectForm')
    def addVersionedFileObjectForm(self):
        """add a new version"""
        
        if str(self.REQUEST['AUTHENTICATED_USER']) in ["Anonymous User"]:
            return "please login first"
        if (self.lockedBy==self.REQUEST['AUTHENTICATED_USER']) or (self.lockedBy=='') or (self.lockedBy==None):
            ext=self.ZopeFind(self.aq_parent,obj_ids=["addNewVersion.dtml"])
            if ext:
                return ext[0][1]('',globals(),version=self.getVersion(),lastComment=self.getContentObject().getVersionComment(),AUTHENTICATED_USER=self.REQUEST.AUTHENTICATED_USER)
            else:
                out=DTMLFile('dtml/fileAdd', globals(),Kind='VersionedFileObject',kind='versionedFileObject',version=self.getVersion()).__of__(self)
                return out()
        else:
            return "Sorry file is locked by somebody else"

        
    def manage_addVersionedFileObject(self,id,vC,author,file='',title='',precondition='', content_type='',changeName='no',newName='', from_tmp=False, RESPONSE=None):
        """add"""
        try: #der ganze vC unsinn muss ueberarbeitet werden
            vC=self.REQUEST['vC']
        except:
            pass
        
        author=self.REQUEST['author']

        ob = self.addContentObject(id, vC, author, file, title, changeName=changeName, newName=newName, from_tmp=from_tmp,
                                   precondition=precondition, content_type=content_type)
            
        self.REQUEST.SESSION['objID_parent']=self.getId()

        if RESPONSE:
            if ob.getSize()==0:
                self.REQUEST.SESSION['objID']=ob.getId()
                pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','errorUploadFile')).__of__(self)
                return pt()

            else:
                RESPONSE.redirect(self.absolute_url()+'/history')
        else:
            return ob


    changeVersionedFileForm = PageTemplateFile('zpt/changeVersionedFile', globals())
    
    def manage_changeVersionedFile(self,title,vC,author,comment,defaultAction='history',RESPONSE=None):
        """Change VersionedFile metadata"""
        self.title = title
        self.author = author
        self.defaultAction = defaultAction
        cob = self.getContentObject()
        if cob:
            if vC:
                cob.vComment=vC

            if comment=='':
                cob.versionComment=None
            else:
                cob.versionComment=comment

        if RESPONSE:
            RESPONSE.redirect('manage_main')

        
    def download(self):
        """download"""
    
        txt=self.REQUEST['URL1']+'/'+self.getId()+'/'+self.getContentObject().getId()+'/download'
        
        self.REQUEST.RESPONSE.redirect(txt)

    
    security.declareProtected('AUTHENTICATED_USER','downloadLocked')    
    def downloadLocked(self):
        """download and lock"""

        if repr(self.REQUEST['AUTHENTICATED_USER'])=='Anonymous User':
            return "please login first"
        if not ((self.lockedBy=="") or (self.lockedBy==None)):
            return "cannot be locked because is already locked by %s"%self.lockedBy
        self.lockedBy=self.REQUEST['AUTHENTICATED_USER']
        self.getContentObject().content_type="application/octet-stream"
        self.REQUEST.RESPONSE.redirect(self.REQUEST['URL1']+'/'+self.getId()+'/'+self.getContentObject().getId())
    

    security.declareProtected('AUTHENTICATED_USER','fixVersionNumbers')    
    def fixVersionNumbers(self):
        """check last version number and id"""
        if not hasattr(self, 'lastVersionId'):
            self.lastVersionNumber = 0
            self.lastVersionId = None
            
        lv = self.getContentObject()
        if lv is not None:
            lvn = lv.getVersionNumber()
            if lvn == 0:
                lvn = 1
                lv.versionNumber = 1
            self.lastVersionNumber = lvn
            self.lastVersionId = lv.getId()
        else:
            self.lastVersionNumber = 0
            self.lastVersionId = None
        logging.debug("fixing last version number of %s to %s (%s)"%(self.getId(),self.lastVersionNumber,self.lastVersionId))
    
    
def manage_addextVersionedFileForm(self):
    """interface for adding the OSAS_root"""
    pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addextVersionedFile.zpt')).__of__(self)
    return pt()

def manage_addextVersionedFile(self,id,title,lockedBy, author=None, defaultAction='history', RESPONSE=None):
    """add the OSAS_root"""
    newObj=extVersionedFile(id,title,lockedBy,author,defaultAction=defaultAction)
    self._setObject(id,newObj)
    
    if RESPONSE is not None:
        RESPONSE.redirect('manage_main')


InitializeClass(extVersionedFile)
InitializeClass(extVersionedFileFolder)

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>