Annotation of versionedFile/extVersionedFile.py, revision 1.11
1.3 dwinter 1: """actual version of the versioned file folder with external filestorage,
2: using the ExtFile Product, this version replaces externaVersionedFile.py
3: DW 11.10.2006
4: """
5:
1.1 dwinter 6: from OFS.Folder import Folder
7: from OFS.Image import File
8: from OFS.Image import cookId
9: from Globals import DTMLFile, InitializeClass,package_home
10: from Products.PageTemplates.PageTemplateFile import PageTemplateFile
11: from AccessControl import getSecurityManager
12: from Products.PageTemplates.PageTemplate import PageTemplate
13: from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
14: from AccessControl import ClassSecurityInfo
15: from difflib import Differ
16: from pprint import pprint
17: from Products.ExtFile.ExtFile import *
18: from Products.ZCatalog.CatalogPathAwareness import CatalogAware
19:
20: try:
1.6 casties 21: from Products.ImageArchive.ImageArchive import manage_AddImageZogiLib
1.1 dwinter 22: except:
1.6 casties 23: print "no images"
1.1 dwinter 24:
25: from threading import Thread
26: import shutil
27: import tempfile
28: import os.path
29: import urllib
1.5 casties 30: import time
31: import logging
1.9 casties 32: import types
1.1 dwinter 33:
34: try:
35: from Products.ECHO_content.ECHO_collection import ECHO_basis
36: except:
37: print "ECHO Elements not imported"
38: class ECHO_basis:
1.6 casties 39: """leer"""
40: manage_options=()
1.1 dwinter 41:
42:
43: def sortv(x,y):
44: return cmp(x[0],y[0])
1.7 casties 45:
1.1 dwinter 46: tdir = "/tmp/downloadVersionedFiles"
47:
48: class generateDownloadZip:
49: """generateDownloadSet"""
50:
51: def __init__(self,folderObject,url):
52: """init downloadzip"""
53: self.folder=folderObject
54: self.done=None
55: self.response=""
56: self.url=url
57:
58: def __call__(self):
59: """call generate download zip"""
60: storeTempDir=tempfile.tempdir
1.6 casties 61: tempfile.tempdir=tdir
1.1 dwinter 62:
63: tmpPath=tempfile.mktemp()
1.6 casties 64: tmpZip=tempfile.mktemp()+".tgz"
1.1 dwinter 65: tmpFn=os.path.split(tmpZip)[1]
66:
67: if not os.path.exists(tempfile.tempdir):
68: os.mkdir(tempfile.tempdir)
69:
70: if not os.path.exists(tmpPath):
1.6 casties 71: os.mkdir(tmpPath)
1.1 dwinter 72:
1.6 casties 73: self.response="<h3>1. step: getting the files</h3>"
1.1 dwinter 74:
75: for files in self.folder.ZopeFind(self.folder,obj_metatypes=['extVersionedFile']):
1.7 casties 76: lastV=files[1].getContentObject()
1.1 dwinter 77: self.response+=str("<p>Get File: %s<br>\n"%lastV.title)
78:
79: savePath=os.path.join(tmpPath,lastV.title)
80: fh=file(savePath,"w")
1.2 dwinter 81: fh.write(lastV.getData())
1.1 dwinter 82: fh.close()
83:
84: self.response+="<h3>2. step: creating the downloadable file</h3>"
1.6 casties 85: self.response+="<p>Create gtar<br>"
1.1 dwinter 86: self.response+="<p>This can take a while....<br>\n"
87:
88: fh=os.popen2("tar zcvf %s %s/*"%(tmpZip,tmpPath),1)[1]
89: self.response+="<br>"
90: for c in fh.read():
91: self.response+=c
92: if c==")":
93: self.response+="<br>\n"
94:
95: shutil.rmtree(tmpPath)
96:
97: self.response+="<p>finished<br>\n"
98:
99: len=os.stat(tmpZip)[6]
100: downloadUrl=self.url+"/downloadSet"
101: self.response+="""<h1><a href="downloadSet?fn=%s">Click here for download ( %i Byte)</a></h1>\n"""%(tmpFn,len)
102: 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>"""
103: self.response+="""<p>The file will be stored for a while, you can download it later, the URL is:</p>
104: <p><a href="downloadSet?fn=%s">%s?fn=%s</a></h1>\n"""%(tmpFn,downloadUrl,tmpFn)
105:
106: self.done=True
107:
1.6 casties 108:
1.1 dwinter 109: def getResult(self):
110: """get result"""
111: return self.response
112:
113: def isDone(self):
114: if self.done:
115: return True
116: else:
117: return False
118:
119:
120: class extVersionedFileFolder(Folder,ECHO_basis):
121: """Folder with versioned files"""
122: meta_type = "extVersionedFileFolder"
123:
124: security= ClassSecurityInfo()
125: security.declareProtected('AUTHENTICATED_USER','addFileForm')
1.6 casties 126:
1.7 casties 127: file_meta_type=['extVersionedFile']
1.6 casties 128:
1.1 dwinter 129: if ECHO_basis:
130: optTMP= Folder.manage_options+ECHO_basis.manage_options
131: else:
132: optTMP= Folder.manage_options
133:
134: manage_options =optTMP+(
1.6 casties 135: {'label':'Generate Index.html','action':'generateIndexHTML'},
136: {'label':'Generate Image Index.html','action':'generateIndexHTML_image'},
137: {'label':'Generate history_template.html','action':'generateHistoryHTML'},
138: {'label':'Import Folder','action':'importFolderForm'},
139: {'label':'Export Folder','action':'exportFolder'},
140: {'label':'Position of version number','action':'changeHistoryFileNamesForm'},
141: )
1.1 dwinter 142:
1.6 casties 143:
1.1 dwinter 144: def changeHistoryFileNamesForm(self):
145: """change position of version num"""
146: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','changeHistoryFileNamesForm.zpt')).__of__(self)
147: return pt()
148:
149:
150: def changeHistoryFileNames(self,positionVersionNum="front",RESPONSE=None):
151: """change position of version num"""
152: versions=self.ZopeFind(self,obj_metatypes=['extVersionedFileObject'],search_sub=1)
153:
154: if not (getattr(self,'positionVersionNum','front')==positionVersionNum):
155:
156: for version in versions:
1.6 casties 157:
1.1 dwinter 158: if positionVersionNum=="front":
1.6 casties 159:
1.1 dwinter 160: titleTmp=os.path.splitext(version[1].title)
161: titleTmp2="_".join(titleTmp[0].split("_")[0:-1])
162: if len(titleTmp)>1:
163: id=titleTmp[0].split("_")[-1]+"_"+titleTmp2+"."+titleTmp[1]
164: else:
165: id=titleTmp[0].split("_")[-1]+"_"+titleTmp2
166:
167: else:
168: titleTmp="_".join(version[1].getId().split("_")[1:])
169: tmp=os.path.splitext(titleTmp)
170: if len(tmp)>1:
171: id=tmp[0]+"_"+version[1].getId().split("_")[0]+tmp[1]
172: else:
173: id=tmp[0]+"_"+version[1].getId().split("_")[0]
174:
175: version[1].aq_parent.manage_renameObjects(ids=[version[1].getId()],new_ids=[id])
176: version[1].title=id
177:
178: self.positionVersionNum=positionVersionNum
179: if RESPONSE:
180: RESPONSE.redirect("manage_main")
181:
182:
183:
184: def importFolderForm(self):
185: """form fuer folder import"""
186: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','importFolderForm.zpt')).__of__(self)
187: return pt()
1.6 casties 188:
1.1 dwinter 189: def importFolder(self,path,comment="",author=None,lockedBy=None,RESPONSE=None):
1.8 casties 190: """import contents of a folder on the server"""
1.1 dwinter 191: for fileName in os.listdir(path):
1.8 casties 192: fn = os.path.join(path,fileName)
193: if os.path.isfile(fn):
194: f = file(fn)
195: self.addFile(vC=comment, file=f, author=author)
1.1 dwinter 196:
197: if RESPONSE:
198: RESPONSE.redirect(self.REQUEST['URL1'])
199:
1.10 casties 200: def importVersionedFileFolderForm(self):
201: """form fuer versionedFileFolder import"""
202: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','importVersionedFileFolderForm.zpt')).__of__(self)
203: return pt()
204:
205: def importVersionedFileFolder(self,path,RESPONSE=None):
206: """import contents of a versionedFileFolder on the server"""
207: vff = getattr(self.aq_parent, path, None)
208: if vff is None:
209: return "SORRY, unable to import %s"%path
210:
211: tmpPath=tempfile.mktemp()
212: if not os.path.exists(tempfile.tempdir):
213: os.mkdir(tempfile.tempdir)
214:
215: if not os.path.exists(tmpPath):
216: os.mkdir(tmpPath)
217:
218: for (vfn, vf) in vff.getVersionedFiles():
219: if vf.meta_type == 'versionedFile':
1.11 ! casties 220: logging.error("importvff: importing %s of type %s!"%(vfn,vf.meta_type))
1.10 casties 221: title = vf.title
1.11 ! casties 222: fob = vf.getLastVersion()
! 223: author = fob.getLastEditor()
! 224: vc = fob.getVersionComment()
1.10 casties 225: # save file to filesystem
226: savePath=os.path.join(tmpPath,title)
227: fh=file(savePath,"w")
1.11 ! casties 228: data = vf.getLastVersion().data
! 229: if isinstance(data, str):
! 230: # simple data object
! 231: fh.write(data)
! 232: else:
! 233: # chained data objects
! 234: while data is not None:
! 235: fh.write(data.data)
! 236: data = data.next
1.10 casties 237: fh.close()
238: # and read in again
239: fh = file(savePath)
1.11 ! casties 240: logging.error("importvff: comment=%s author=%s!"%(vc,author))
1.10 casties 241: self.addFile(vC=vc, file=fh, author=author)
1.11 ! casties 242: # copy more fields
! 243: newfob = getattr(self, vfn).getContentObject()
! 244: newfob.vComment = fob.vComment
! 245: newfob.time = fob.time
! 246: logging.error("importvff: vc=%s time=%s of %s!"%(fob.vComment,fob.time,fob.getId()))
1.10 casties 247:
248: else:
249: logging.error("importvff: unable to import %s of type %s!"%(vfn,vf.meta_type))
250:
251: shutil.rmtree(tmpPath)
252:
253: if RESPONSE:
254: RESPONSE.redirect(self.REQUEST['URL1'])
255:
1.1 dwinter 256: zipThreads={}
257: zipThreads2={}
258:
259: def refreshTxt(self):
260: """txt fuer refresh"""
261: tn=self.REQUEST.SESSION['threadName']
262: return """ 2;url=%s?repeat=%s """%(self.absolute_url()+"/exportFolder",tn)
263:
264: def exportFolder(self,repeat=None):
265: """exportiert alle akutellen files des folders"""
266: threadName=repeat
267:
268: downloadZip=generateDownloadZip(self,self.absolute_url())
269: downloadZip()
270: return downloadZip.getResult()
1.8 casties 271:
1.1 dwinter 272: ## if not threadName or threadName=="":
273: ## threadStart=generateDownloadZip(self,self.absolute_url())
274: ## thread=Thread(target=threadStart)
1.6 casties 275:
1.1 dwinter 276: ## thread.start()
277:
1.6 casties 278:
1.1 dwinter 279: ## self.zipThreads[thread.getName()[0:]]=threadStart
280: ## self.zipThreads2[thread.getName()[0:]]=thread
281: ## self.REQUEST.SESSION['threadName']=thread.getName()[0:]
282: ## wait_template=self.aq_parent.ZopeFind(self.aq_parent,obj_ids=['zip_wait_template'])
283: ## if wait_template:
284: ## return wait_template[0][1]()
285: ## pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','zip_wait.zpt')).__of__(self)
286: ## return pt()
1.6 casties 287:
1.1 dwinter 288: ## else:
289: ## self.REQUEST.SESSION['threadName']=threadName
290:
291: ## if (self.zipThreads[threadName].getResult()==None):
292:
293: ## wait_template=self.aq_parent.ZopeFind(self.aq_parent,obj_ids=['wait_template'])
294: ## if wait_template:
295: ## return wait_template[0][1]()
296:
297: ## pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','zip_wait.zpt')).__of__(self)
298: ## return pt()
299: ## else:
300: ## if self.zipThreads[threadName].isDone():
301: ## self.REQUEST.SESSION['result']=self.zipThreads[threadName].getResult()
302: ## self.zipThreads2[threadName].join()
303: ## del(self.zipThreads2[threadName])
304: ## del(self.zipThreads[threadName])
305: ## pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','zip_result.zpt')).__of__(self)
306: ## return pt()
307:
308: ## else:
309: ## self.REQUEST.SESSION['result']=self.zipThreads[threadName].getResult()
310: ## self.REQUEST.SESSION['threadName']=threadName
311: ## pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','zip_wait_result.zpt')).__of__(self)
312: ## return pt()
313:
314: def downloadSet(self,fn):
1.6 casties 315: """download prepared set"""
316: filename=os.path.join(tdir,fn)
1.1 dwinter 317:
1.6 casties 318:
319: self.REQUEST.RESPONSE.setHeader("Content-Disposition","""attachement; filename="%s" """%"downloadFileFolder.tgz")
320: self.REQUEST.RESPONSE.setHeader("Content-Type","application/octet-stream")
321: len=os.stat(filename)[6]
322: self.REQUEST.RESPONSE.setHeader("Content-Length",len)
323: images=file(filename).read()
324: self.REQUEST.RESPONSE.write(images)
325: self.REQUEST.RESPONSE.close()
1.1 dwinter 326:
327:
328:
329: def helpDownload(self):
330: """download help"""
331:
332: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','helpDownload')).__of__(self)
333: return pt()
334:
335: def generateIndexHTML_image(self,RESPONSE=None):
336: """lege standard index.html an"""
337:
338:
339: if not self.ZopeFind(self,obj_ids=['index.html']):
340: zt=ZopePageTemplate('index.html')
341: self._setObject('index.html',zt)
342: default_content_fn = os.path.join(package_home(globals()),
1.6 casties 343: 'zpt/versionFileFolderMain_image.zpt')
1.1 dwinter 344: text = open(default_content_fn).read()
345: zt.pt_edit(text, 'text/html')
346:
347: else:
348: return "already exists!"
349:
350: if RESPONSE is not None:
351: RESPONSE.redirect('manage_main')
352:
353:
354: def generateAddFileForm(self,RESPONSE=None):
355: """lege standard addfileform an"""
356: #TODO: write generateaddfileform only a dummy at them moment
357:
358: if not self.ZopeFind(self,obj_ids=['addFileForm.dtml']):
359: zt=ZopePageTemplate('index.html')
360: self._setObject('index.html',zt)
361: default_content_fn = os.path.join(package_home(globals()),
1.6 casties 362: 'zpt/versionFileFolderMain.zpt')
1.1 dwinter 363: text = open(default_content_fn).read()
364: zt.pt_edit(text, 'text/html')
365:
366: else:
367: return "already exists!"
368:
369: if RESPONSE is not None:
370: RESPONSE.redirect('manage_main')
371:
372:
373: def generateIndexHTML(self,RESPONSE=None):
374: """lege standard index.html an"""
375: if not self.ZopeFind(self,obj_ids=['index.html']):
376: zt=ZopePageTemplate('index.html')
377: self._setObject('index.html',zt)
378: default_content_fn = os.path.join(package_home(globals()),
1.6 casties 379: 'zpt/versionFileFolderMain.zpt')
1.1 dwinter 380: text = open(default_content_fn).read()
381: zt.pt_edit(text, 'text/html')
382:
383: else:
384: return "already exists!"
385:
386: if RESPONSE is not None:
387: RESPONSE.redirect('manage_main')
388:
389:
390: def generateHistoryHTML(self,RESPONSE=None):
391: """lege standard index.html an"""
392: if not self.ZopeFind(self,obj_ids=['history_template.html']):
393: zt=ZopePageTemplate('history_template.html')
394: self._setObject('history_template.html',zt)
395: default_content_fn = os.path.join(package_home(globals()),
1.6 casties 396: 'zpt/versionHistory.zpt')
1.1 dwinter 397: text = open(default_content_fn).read()
398: zt.pt_edit(text, 'text/html')
399:
400: else:
401: return "already exists!"
402:
403: if RESPONSE is not None:
404: RESPONSE.redirect('manage_main')
1.6 casties 405:
1.1 dwinter 406:
407: def getVersionedFiles(self,sortField='title'):
408: """get all versioned files"""
409:
410: def sortName(x,y):
411: return cmp(x[1].title.lower(),y[1].title.lower())
412:
413: def sortDate(x,y):
1.7 casties 414: return cmp(y[1].getContentObject().getTime(),x[1].getContentObject().getTime())
1.1 dwinter 415:
416: def sortComment(x,y):
1.6 casties 417: try:
418: xc=getattr(x[1],'comment','ZZZZZZZZZZZZZ').lower()
419: except:
420: xc='ZZZZZZZZZZZZZ'.lower()
421:
422: try:
423: yc=getattr(y[1],'comment','ZZZZZZZZZZZZZ').lower()
424: except:
425: yc='ZZZZZZZZZZZZZ'.lower()
426:
427: if (xc=='') or (xc=='ZZZZZZZZZZZZZ'.lower()):
428: try:
1.7 casties 429: xc=x[1].getContentObject().getVComment().lower()
1.6 casties 430: except:
431: xc='ZZZZZZZZZZZZZ'.lower()
432:
433: if (yc=='') or (yc=='ZZZZZZZZZZZZZ'.lower()):
434: try:
1.7 casties 435: yc=y[1].getContentObject().getVComment().lower()
1.6 casties 436: except:
437: yc='ZZZZZZZZZZZZZ'.lower()
438:
439: return cmp(xc,yc)
1.1 dwinter 440:
441: def sortAuthor(x,y):
442:
1.7 casties 443: return cmp(x[1].getContentObject().lastEditor().lower(),y[1].getContentObject().lastEditor().lower())
1.1 dwinter 444:
1.7 casties 445: versionedFiles=self.objectItems(self.file_meta_type)
446: logging.debug("versionedfiles: %s of type %s"%(repr(versionedFiles),repr(self.file_meta_type)))
1.1 dwinter 447:
448: if sortField=='title':
449: versionedFiles.sort(sortName)
450: elif sortField=='date':
451: versionedFiles.sort(sortDate)
452: elif sortField=='author':
453: versionedFiles.sort(sortAuthor)
454: elif sortField=='comment':
455: versionedFiles.sort(sortComment)
456:
457: return versionedFiles
458:
459:
460: def header_html(self):
1.5 casties 461: """zusaetzlicher header"""
1.1 dwinter 462: ext=self.ZopeFind(self,obj_ids=["header.html"])
463: if ext:
464: return ext[0][1]()
465: else:
466: return ""
467:
468:
469: security.declareProtected('View','index_html')
470: def index_html(self):
471: """main"""
472: ext=self.ZopeFind(self,obj_ids=["index.html"])
473: if ext:
474: return ext[0][1]()
475:
476: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','versionFileFolderMain')).__of__(self)
477: return pt()
478:
479:
480:
481: def addFileForm(self):
482: """add a file"""
483: ext=self.ZopeFind(self,obj_ids=["addFileForm.dtml"])
484: if ext:
485: return ext[0][1]('',globals(),version='1',AUTHENTICATED_USER=self.REQUEST.AUTHENTICATED_USER)
486:
487: out=DTMLFile('dtml/newFileAdd', globals(),Kind='versionedFileObject',kind='versionedFileObject',version='1').__of__(self)
488: return out()
489:
490:
1.8 casties 491: def addFile(self,vC,file,author='',newName='',content_type='',RESPONSE=None):
1.1 dwinter 492: """ add a new file"""
1.9 casties 493: # is file is a real file or a zope download object?
494: isRealFile = type(file) is types.FileType
495:
1.1 dwinter 496: if newName=='':
1.9 casties 497: logging.debug("fileobject: %s real:%s"%(repr(file),repr(isRealFile)))
498: if isRealFile:
499: filename = file.name
500: else:
501: filename=file.filename
502:
1.1 dwinter 503: id=filename[max(filename.rfind('/'),
1.6 casties 504: filename.rfind('\\'),
505: filename.rfind(':'),
506: )+1:]
1.1 dwinter 507:
508: else:
509: id=newName
510:
1.11 ! casties 511: if vC is None:
1.9 casties 512: vC=self.REQUEST.form['vC']
1.8 casties 513:
514: # get new extVersionedFile
515: vf = self._newVersionedFile(id,title=id)
1.1 dwinter 516: #if (getattr(self,'commentNonEmpty',0)==1) and vC.strip()=="":
1.8 casties 517: # add file to this folder
518: self._setObject(id,vf)
519: # add its content
520: logging.info("ADD: %s"%repr(vf))
1.9 casties 521: obj=vf.addContentObject(id,vC,author=author,file=file,content_type=content_type,from_tmp=isRealFile)
1.1 dwinter 522:
1.8 casties 523: self.REQUEST.SESSION['objID']=vf.getId()
1.1 dwinter 524: self.REQUEST.SESSION['objID_parent']=None
525:
526: if obj.getSize()==0:
527: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','errorUploadFile')).__of__(self)
528: return pt()
529:
1.9 casties 530: if RESPONSE is not None:
531: RESPONSE.redirect(self.REQUEST['URL1'])
1.1 dwinter 532:
533:
1.8 casties 534: def _newVersionedFile(self, id, title='', lockedBy=None, author=None):
535: """factory for versioned files. to be overridden in derived classes."""
536: return extVersionedFile(id, title, lockedBy=lockedBy, author=author)
537:
538:
1.1 dwinter 539: def deleteEmptyObject(self,submit,RESPONSE=None):
540: """deleteemptyobject"""
541: if submit=="delete it":
542: if self.REQUEST.SESSION['objID_parent']:
543: obj=getattr(self,self.REQUEST.SESSION['objID_parent'])
544:
545: else:
546: obj=self
547: obj.manage_delObjects([self.REQUEST.SESSION['objID']])
548:
549: RESPONSE.redirect(self.REQUEST['URL1'])
550:
1.7 casties 551:
552: security.declareProtected('AUTHENTICATED_USER','fixVersionNumbers')
553: def fixVersionNumbers(self):
554: """fix last version number of all files"""
555: for (id,vf) in self.getVersionedFiles():
556: vf.fixVersionNumbers()
1.1 dwinter 557:
1.8 casties 558:
1.1 dwinter 559: manage_addextVersionedFileFolderForm=DTMLFile('dtml/extfolderAdd', globals())
560:
561:
562: def manage_addextVersionedFileFolder(self, id, title='',
1.6 casties 563: createPublic=0,
564: createUserF=0,
565: REQUEST=None):
1.1 dwinter 566: """Add a new Folder object with id *id*.
567:
568: If the 'createPublic' and 'createUserF' parameters are set to any true
569: value, an 'index_html' and a 'UserFolder' objects are created respectively
570: in the new folder.
571: """
572: ob=extVersionedFileFolder()
573: ob.id=str(id)
574: ob.title=title
575: self._setObject(id, ob)
576: ob=self._getOb(id)
577:
578: checkPermission=getSecurityManager().checkPermission
579:
580: if createUserF:
581: if not checkPermission('Add User Folders', ob):
582: raise Unauthorized, (
1.6 casties 583: 'You are not authorized to add User Folders.'
584: )
1.1 dwinter 585: ob.manage_addUserFolder()
586:
1.6 casties 587:
1.1 dwinter 588: if REQUEST is not None:
589: return self.manage_main(self, REQUEST, update_menu=1)
590:
591:
592:
593: class extVersionedFileObject(ExtFile):
594: """File Object im Folder"""
595: security= ClassSecurityInfo()
596: meta_type = "extVersionedFileObject"
597:
1.7 casties 598: manage_editForm=DTMLFile('dtml/fileEdit',globals(),
1.1 dwinter 599: Kind='File',kind='file')
600: manage_editForm._setName('manage_editForm')
601:
1.7 casties 602: def __init__(self, id, title='', versionNumber=0, versionComment=None, time=None, author=None):
603: """Initialize a new instance of extVersionedFileObject (taken from ExtFile)"""
604: ExtFile.__init__(self,id,title)
605: self.versionNumber = versionNumber
606: self.versionComment= versionComment
607: self.time = time
608: self.author = author
609:
610:
1.1 dwinter 611: security.declarePublic('getTitle')
612: def getTitle(self):
613: """get title"""
614: return self.title
1.6 casties 615:
616: def getData(self):
617: """returns object content (calls ExtFile.index_html)"""
618: return ExtFile.index_html(self)
619:
1.1 dwinter 620: security.declarePublic('getVComment')
621: def getVComment(self):
622: """get the comment of this file"""
623: if not hasattr(self,'vComment') or (not self.vComment) or (self.vComment.lstrip()==""):
624: return "Add comment"
625:
626: else:
627: return self.vComment
1.6 casties 628:
1.1 dwinter 629: def manageVCommentForm(self):
630: """add a comment"""
631: self.REQUEST.SESSION['refer']=self.REQUEST['HTTP_REFERER']
632: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addVComment')).__of__(self)
633: return pt()
634:
635: def manageVComment(self,text,comment_author,submit,REQUEST=None):
636: """manage comments"""
637: if submit =='change':
638: if text=='':
639: self.vComment=None
640: else:
641: self.vComment=text
642: self.vComment_author=comment_author
643:
644: self.vComment_date=time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())
645:
646: if self.REQUEST.SESSION.has_key('refer'):
647:
648: return REQUEST.RESPONSE.redirect(self.REQUEST.SESSION['refer'])
649: return REQUEST.RESPONSE.redirect(self.aq_parent.absolute_url()+"/history")
650:
651:
652: security.declarePublic('getVersionComment')
653: def getVersionComment(self):
654: """getversioncomment"""
655: return self.versionComment
656:
657: security.declarePublic('getTime')
658: def getTime(self):
659: """getTime"""
660: #return self.bobobase_modification_time().ISO()
661: if hasattr(self,'time'):
662: return time.strftime("%Y-%m-%d %H:%M:%S",self.time)
663: elif hasattr(self,'timefixed'):
1.6 casties 664: return self.timefixed
1.1 dwinter 665: else:
666: setattr(self,'timefixed',self.bobobase_modification_time().ISO())
667: return self.bobobase_modification_time().ISO()
668:
669: def download(self,REQUEST=None,RESPONSE=None):
670: """download and lock"""
671:
672: self.REQUEST.RESPONSE.setHeader("Content-Disposition","""attachement; filename=%s"""%self.getId())
673: self.REQUEST.RESPONSE.setHeader("Content-Type","application/octet-stream")
674: #try:
675: # txt=self.index_html()
676: #except:
677: # txt=self.index_html(REQUEST,RESPONSE)
678: #
679: #self.REQUEST.RESPONSE.setHeader("Content-Length","str(len(txt)+1000)")
680:
681: self.content_type="application/octet-stream"
682: self.REQUEST.RESPONSE.redirect(self.absolute_url())
683: #txt=urllib.urlopen(self.absolute_url()).read()
684: #self.REQUEST.RESPONSE.write(txt)
685:
686:
687: #self.REQUEST.close()
688:
689: security.declareProtected('AUTHENTICATED_USER','downloadLocked')
690: def downloadLocked(self):
691: """download and lock"""
692:
693:
694: if repr(self.REQUEST['AUTHENTICATED_USER'])=='Anonymous User':
695: return "please login first"
696: if not self.aq_parent.lockedBy=="":
697: return "cannot be locked because is already locked by %s"%self.lockedBy
698: self.aq_parent.lockedBy=self.REQUEST['AUTHENTICATED_USER']
699:
700: self.content_type="application/octet-stream"
701: self.REQUEST.RESPONSE.redirect(self.absolute_url())
702:
703: security.declarePublic('getVersionNumber')
704: def getVersionNumber(self):
705: """get version"""
706: return self.versionNumber
707:
708: security.declarePublic('getVersionComment')
709: def getVersionComment(self):
710: """get version"""
711: return self.versionComment
712:
713: security.declarePublic('lastEditor')
714: def lastEditor(self):
715: """last Editor"""
716: if hasattr(self,'author'):
717: try:
718: ret=self.author.replace("-","\n")
719: except:#old version of versionded file sometimes stored the user object and not only the name the following corrects this
720: ret=str(self.author).replace("-","\n")
721: ret=ret.replace("\r","\n")
722: return ret.lstrip().rstrip()
723:
724: else:
725: jar=self._p_jar
726: oid=self._p_oid
727:
728: if jar is None or oid is None: return None
729:
730: return jar.db().history(oid)[0]['user_name']
731:
732:
733: manage_addextVersionedFileObjectForm=DTMLFile('dtml/fileAdd', globals(),Kind='extVersionedFileObject',kind='extVersionedFileObject', version='1')
734:
1.7 casties 735: def manage_addextVersionedFileObject(self,id,vC='',author='', file='',title='',versionNumber=0,
736: precondition='', content_type='', REQUEST=None):
1.1 dwinter 737: """Add a new File object.
738:
739: Creates a new File object 'id' with the contents of 'file'"""
740:
741: id=str(id)
742: title=str(title)
743: content_type=str(content_type)
744: precondition=str(precondition)
745:
746: id, title = cookId(id, title, file)
747:
748: self=self.this()
749:
750: # First, we create the file without data:
1.7 casties 751: self._setObject(id, extVersionedFileObject(id,title,versionNumber=versionNumber,versionComment=str(vC),author=author))
752: fob = self._getOb(id)
1.1 dwinter 753:
754: # Now we "upload" the data. By doing this in two steps, we
755: # can use a database trick to make the upload more efficient.
756: if file:
1.7 casties 757: fob.manage_upload(file)
1.1 dwinter 758: if content_type:
1.7 casties 759: fob.content_type=content_type
1.1 dwinter 760:
761: if REQUEST is not None:
762: REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main')
763:
764:
765:
766: class extVersionedFile(CatalogAware,Folder):
767: """Versioniertes File"""
768:
1.7 casties 769: meta_type = 'extVersionedFile'
770: # meta_type of contained objects
771: content_meta_type = ['extVersionedFileObject']
772: default_catalog = 'fileCatalog'
1.1 dwinter 773:
1.7 casties 774: security=ClassSecurityInfo()
1.1 dwinter 775:
1.7 casties 776: def __init__(self, id, title, lockedBy,author):
777: """init"""
778: self.id=id
779: self.title=title
780: self.lockedBy=lockedBy
781: self.author=author
782: self.lastVersionNumber=0
783: self.lastVersionId=None
784:
1.1 dwinter 785: security.declarePublic('getTitle')
786: def getTitle(self):
787: """get title"""
788: return self.title
789:
790: def PrincipiaSearchSource(self):
1.6 casties 791: """Return cataloguable key for ourselves."""
792: return str(self)
1.1 dwinter 793:
794: def manageImagesForm(self):
795: """manage Images attached to the file"""
796:
797: self.REQUEST.SESSION['refer']=self.REQUEST['HTTP_REFERER']
798:
799: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','manageImage')).__of__(self)
800: return pt()
801:
802: def manageImages(self,imageUrl=None,caption=None,REQUEST=None):
803: """manage URL"""
804: if imageUrl and (not imageUrl==""):
805: manage_AddImageZogiLib(self,libPath=imageUrl,caption=caption)
806:
807: if self.REQUEST.SESSION.has_key('refer'):
808:
809: return REQUEST.RESPONSE.redirect(self.REQUEST.SESSION['refer'])
810: return REQUEST.RESPONSE.redirect(self.aq_parent.absolute_url())
811:
812: def changeImages(self,caption=None,submit=None,id=None,REQUEST=None):
813: """manage URL"""
814: if submit=="change caption":
815: image=self.ZopeFind(self,obj_ids=[id])
816: if image:
817: image[0][1].caption=caption[0:]
818:
819: elif submit=="delete":
820: image=self.ZopeFind(self,obj_ids=[id])
821: if image:
822: self.manage_delObjects([image[0][1].getId()])
823:
824: if self.REQUEST.SESSION.has_key('refer'):
1.7 casties 825: return REQUEST.RESPONSE.redirect(self.REQUEST.SESSION['refer'])
1.1 dwinter 826:
827: return REQUEST.RESPONSE.redirect(self.aq_parent.absolute_url())
828:
829: def getImages(self):
830: """get Images"""
831: images=self.ZopeFind(self,obj_metatypes=["ImageZogiLib"])
832: if not images:
833: return None
834: else:
835: return images
1.6 casties 836:
1.1 dwinter 837: security.declarePublic('getComment')
838: def getComment(self):
839: """get the comment of this file"""
840: if not hasattr(self,'comment') or (not self.comment) or (self.comment.lstrip()==""):
841: return "Add comment"
842: else:
843: return self.comment
844:
845: def manageCommentForm(self):
846: """add a comment"""
847: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addComment')).__of__(self)
848: return pt()
849:
850: def manageComment(self,text,comment_author,submit,REQUEST=None):
851: """manage comments"""
852: if submit =='change':
853: if text=='':
854: self.comment=None
855: else:
856: self.comment=text
857: self.comment_author=comment_author
858:
859: self.comment_date=time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())
860:
861: return REQUEST.RESPONSE.redirect(self.aq_parent.absolute_url())
1.6 casties 862:
1.1 dwinter 863: security.declarePublic('getLastChangeDate')
864: def getLastChangeDate(self):
865: """get last change date"""
1.7 casties 866: lv=self.getContentObject()
1.1 dwinter 867: time=lv.getTime()
868: return time
869:
870: def getLastEditor(self):
871: """get last change date"""
1.7 casties 872: lv=self.getContentObject()
1.1 dwinter 873: le=lv.lastEditor()
874: return le
875:
876: def getLockedBy(self):
877: """get locked by"""
878: return str(self.lockedBy)
1.6 casties 879:
1.7 casties 880: def getLastVersionNumber(self):
881: """returns the highest version number of all included objects"""
882: lv = self.findLastVersion()
883: if lv:
884: return lv.getVersionNumber()
885: else:
886: return 0
887:
888: def findLastVersion(self):
889: """finds and returns the object with the highest version number"""
890: lvn=0
891: lv=None
892:
893: for v in self.objectValues(self.content_meta_type):
894: logging.debug("findlastversion: check %s"%v.getId())
895: if v.getVersionNumber() > lvn:
896: lvn=v.getVersionNumber()
897: lv=v
898:
899: if lv:
900: logging.debug("findlastversion: got %s"%lv.getId())
901: return lv
902:
1.1 dwinter 903: security.declarePublic('getLastVersion')
904: def getLastVersion(self):
1.7 casties 905: """Last Version (old)"""
1.1 dwinter 906: tmp=0
1.7 casties 907: lv=None
1.1 dwinter 908:
1.7 casties 909: for v in self.objectValues(self.content_meta_type):
910: logging.debug("getlastversion: check %s"%v.getId())
911: if v.getVersionNumber() > tmp:
912: tmp=v.getVersionNumber()
913: lv=v
914:
915: logging.debug("getlastversion: got %s"%lv.getId())
916: return lv
917:
918: def getContentObject(self):
919: """returns the last version object"""
920: if not self.lastVersionId:
921: lv = self.findLastVersion()
922: if lv is None:
923: return None
924: self.lastVersionNumber = lv.getVersionNumber()
925: self.lastVersionId = lv.getId()
1.1 dwinter 926:
1.7 casties 927: return getattr(self, self.lastVersionId)
928:
929: security.declarePublic('getData')
930: def getData(self):
931: """Returns the content of the last version"""
932: ob = self.getContentObject()
933: if ob is not None:
934: return ob.getData()
935: else:
936: return None
1.1 dwinter 937:
938: def diff(self,data):
939: """differenz between lastversion and data"""
940: d=Differ()
1.7 casties 941: tmp=self.getData()
1.1 dwinter 942: #print "XX",data,tmp
943: try:
1.6 casties 944: l=list(d.compare(data.splitlines(1),tmp.splitlines(1)))
1.1 dwinter 945: except:
946: return 0,""
947: plus=0
948: minus=0
949: for a in l:
950: if a[0]=='+':
951: plus+=1
952: if a[0]=='-':
953: minus+=1
954:
955: return max([plus,minus]),l
1.6 casties 956:
957:
1.1 dwinter 958: security.declarePublic('index_html')
959: def index_html(self):
960: """main view"""
1.7 casties 961: #lastVersion=self.getContentObject()
1.1 dwinter 962: #return "File:"+self.title+" Version:%i"%lastVersion.versionNumber," modified:",lastVersion.bobobase_modification_time()," size:",lastVersion.getSize(),"modified by:",lastVersion.lastEditor()
1.4 dwinter 963: #return "File: %s Version:%i modified:%s size:%s modified by:%s"%(self.title,lastVersion.versionNumber,lastVersion.getTime(),lastVersion.getSize(),lastVersion.lastEditor())
964: return self.history()
1.1 dwinter 965:
1.6 casties 966:
1.1 dwinter 967: security.declarePublic('getVersion')
968: def getVersion(self):
1.7 casties 969: # TODO: this is ugly and it returns the next version number
1.1 dwinter 970: tmp=0
971: for version in self.ZopeFind(self):
972:
973: if hasattr(version[1],'versionNumber'):
974:
975: if int(version[1].versionNumber) > tmp:
976: tmp=int(version[1].versionNumber,)
1.7 casties 977: return tmp+1
1.1 dwinter 978:
979: def history(self):
980: """history"""
981: ext=self.ZopeFind(self.aq_parent,obj_ids=["history_template.html"])
982: if ext:
983: return getattr(self,ext[0][1].getId())()
984:
985: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','versionHistory')).__of__(self)
986: return pt()
987:
988: def getVersions(self):
989: """get all versions"""
990: ret=[]
991: for version in self.ZopeFind(self):
992: if hasattr(version[1],'versionNumber'):
993: ret.append((version[1].versionNumber,version[1]))
994: ret.sort(sortv)
995: return ret
996:
997: security.declareProtected('AUTHENTICATED_USER','forceunlock')
998: def forceunlock(self,RESPONSE=None):
999: """unlock"""
1000: #safe who had the lock
1001: if self.lockedBy:
1002: self.brokenLock=str(self.lockedBy)
1003: else:
1004: self.brokenLock=""
1005: self.lockedBy=''
1006: return self.brokenLock
1007:
1008: security.declareProtected('AUTHENTICATED_USER','unlock')
1009: def unlock(self,RESPONSE):
1010: """unlock"""
1011: if str(self.lockedBy) in [str(self.REQUEST['AUTHENTICATED_USER'])]:
1012: self.lockedBy=''
1013: RESPONSE.redirect(self.REQUEST['HTTP_REFERER'])
1014: else:
1015: return "Sorry, not locked by you! (%s,%s)"%(self.lockedBy,self.REQUEST['AUTHENTICATED_USER'])
1016:
1.7 casties 1017:
1018: def _newContentObject(self, id, title='', versionNumber=0, versionComment=None, time=None, author=None):
1019: """factory for content objects. to be overridden in derived classes."""
1020: return extVersionedFileObject(id,title,versionNumber=versionNumber,versionComment=versionComment,time=time,author=author)
1021:
1022:
1023: def addContentObject(self,id,vC,author=None,file=None,title='',changeName='no',newName='',from_tmp=False,
1024: precondition='', content_type=''):
1025: """add"""
1026:
1027: if changeName=="yes":
1028: filename=file.filename
1029: self.title=filename[max(filename.rfind('/'),
1030: filename.rfind('\\'),
1031: filename.rfind(':'),
1032: )+1:]
1033:
1034: if not newName=='':
1035: self.title=newName[0:]
1036:
1037: posVersNum=getattr(self,'positionVersionNum','front')
1038:
1039: versNum = self.getLastVersionNumber() + 1
1040:
1041: if posVersNum=='front':
1042: id="V%i_%s"%(versNum,self.title)
1043: else:
1044: fn=os.path.splitext(self.title)
1045: if len(fn)>1:
1046: id=fn[0]+"_V%i%s"%(versNum,fn[1])
1047: else:
1048: id=fn[0]+"_V%i"%versNum
1.1 dwinter 1049:
1.7 casties 1050: # what does this do?
1051: id, title = cookId(id, title, file)
1052: self=self.this()
1053:
1054: # First, we create the file without data:
1055: self._setObject(id, self._newContentObject(id,title,versionNumber=versNum,versionComment=str(vC),
1056: time=time.localtime(),author=author))
1057: fob = self._getOb(id)
1058:
1059: # Now we "upload" the data. By doing this in two steps, we
1060: # can use a database trick to make the upload more efficient.
1061: if file and not from_tmp:
1062: fob.manage_upload(file)
1063: elif file and from_tmp:
1064: fob.manage_file_upload(file) # manage_upload_from_tmp doesn't exist in ExtFile2
1065: # fob.manage_upload_from_tmp(file) # manage_upload_from_tmp doesn't exist in ExtFile2
1066: fob.content_type=content_type
1067:
1068: self.lastVersionNumber = versNum
1069: self.lastVersionId = id
1070:
1.9 casties 1071: #logging.debug("addcontentobject: lastversion=%s"%self.getData())
1.7 casties 1072: logging.debug("reindex1: %s in %s"%(repr(self),repr(self.default_catalog)))
1073: self.reindex_object()
1.9 casties 1074: #logging.debug("addcontentobject: fob_data=%s"%fob.getData())
1.7 casties 1075:
1076: return fob
1077:
1.1 dwinter 1078:
1079: security.declareProtected('AUTHENTICATED_USER','addVersionedFileObjectForm')
1080: def addVersionedFileObjectForm(self):
1081: """add a new version"""
1082:
1083: if str(self.REQUEST['AUTHENTICATED_USER']) in ["Anonymous User"]:
1084: return "please login first"
1085: if (self.lockedBy==self.REQUEST['AUTHENTICATED_USER']) or (self.lockedBy==''):
1086: ext=self.ZopeFind(self.aq_parent,obj_ids=["addNewVersion.dtml"])
1087: if ext:
1.7 casties 1088: return ext[0][1]('',globals(),version=self.getVersion(),lastComment=self.getContentObject().getVersionComment(),AUTHENTICATED_USER=self.REQUEST.AUTHENTICATED_USER)
1.1 dwinter 1089: else:
1090: out=DTMLFile('dtml/fileAdd', globals(),Kind='VersionedFileObject',kind='versionedFileObject',version=self.getVersion()).__of__(self)
1091: return out()
1092: else:
1093: return "Sorry file is locked by somebody else"
1.7 casties 1094:
1.1 dwinter 1095:
1.7 casties 1096: def manage_addVersionedFileObject(self,id,vC,author,file='',title='',precondition='', content_type='',changeName='no',newName='', from_tmp=False, RESPONSE=None):
1.1 dwinter 1097: """add"""
1098: try: #der ganze vC unsinn muss ueberarbeitet werden
1099: vC=self.REQUEST['vC']
1100: except:
1101: pass
1102:
1103: author=self.REQUEST['author']
1104:
1.7 casties 1105: ob = self.addContentObject(id, vC, author, file, title, changeName=changeName, newName=newName, from_tmp=from_tmp,
1106: precondition=precondition, content_type=content_type)
1107:
1.1 dwinter 1108: self.REQUEST.SESSION['objID_parent']=self.getId()
1109:
1110: if RESPONSE:
1.7 casties 1111: if ob.getSize()==0:
1112: self.REQUEST.SESSION['objID']=ob.getId()
1.1 dwinter 1113: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','errorUploadFile')).__of__(self)
1114: return pt()
1115:
1116: else:
1117: RESPONSE.redirect(self.REQUEST['URL2'])
1118: else:
1.7 casties 1119: return ob
1.6 casties 1120:
1.1 dwinter 1121:
1122: def download(self):
1123: """download and lock"""
1.7 casties 1124: self.REQUEST.RESPONSE.setHeader("Content-Disposition","""attachement; filename=%s"""%self.getContentObject().getId())
1.1 dwinter 1125: self.REQUEST.RESPONSE.setHeader("Content-Type","application/octet-stream")
1126: self.content_type="application/octet-stream"
1.7 casties 1127: self.REQUEST.RESPONSE.redirect(self.REQUEST['URL1']+'/'+self.getId()+'/'+self.getContentObject().getId())
1.1 dwinter 1128:
1129: security.declareProtected('AUTHENTICATED_USER','downloadLocked')
1130: def downloadLocked(self):
1131: """download and lock"""
1132:
1133: if repr(self.REQUEST['AUTHENTICATED_USER'])=='Anonymous User':
1134: return "please login first"
1135: if not self.lockedBy=="":
1136: return "cannot be locked because is already locked by %s"%self.lockedBy
1137: self.lockedBy=self.REQUEST['AUTHENTICATED_USER']
1.7 casties 1138: self.getContentObject().content_type="application/octet-stream"
1139: self.REQUEST.RESPONSE.redirect(self.REQUEST['URL1']+'/'+self.getId()+'/'+self.getContentObject().getId())
1140:
1141:
1142: security.declareProtected('AUTHENTICATED_USER','fixVersionNumbers')
1143: def fixVersionNumbers(self):
1144: """check last version number and id"""
1145: if not hasattr(self, 'lastVersionId'):
1146: self.lastVersionNumber = 0
1147: self.lastVersionId = None
1148:
1149: lv = self.getContentObject()
1150: if lv is not None:
1151: lvn = lv.getVersionNumber()
1152: if lvn == 0:
1153: lvn = 1
1154: lv.versionNumber = 1
1155: self.lastVersionNumber = lvn
1156: self.lastVersionId = lv.getId()
1157: else:
1158: self.lastVersionNumber = 0
1159: self.lastVersionId = None
1160: logging.debug("fixing last version number of %s to %s (%s)"%(self.getId(),self.lastVersionNumber,self.lastVersionId))
1161:
1.1 dwinter 1162:
1163: def manage_addextVersionedFileForm(self):
1164: """interface for adding the OSAS_root"""
1165: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addextVersionedFile.zpt')).__of__(self)
1166: return pt()
1167:
1168: def manage_addextVersionedFile(self,id,title,lockedBy, author=None, RESPONSE=None):
1169: """add the OSAS_root"""
1170: newObj=extVersionedFile(id,title,lockedBy,author)
1171: self._setObject(id,newObj)
1.6 casties 1172:
1.1 dwinter 1173: if RESPONSE is not None:
1174: RESPONSE.redirect('manage_main')
1175:
1176:
1177: InitializeClass(extVersionedFile)
1178: InitializeClass(extVersionedFileFolder)
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>