Annotation of versionedFile/extVersionedFile.py, revision 1.9
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:
200: zipThreads={}
201: zipThreads2={}
202:
203: def refreshTxt(self):
204: """txt fuer refresh"""
205: tn=self.REQUEST.SESSION['threadName']
206: return """ 2;url=%s?repeat=%s """%(self.absolute_url()+"/exportFolder",tn)
207:
208: def exportFolder(self,repeat=None):
209: """exportiert alle akutellen files des folders"""
210: threadName=repeat
211:
212: downloadZip=generateDownloadZip(self,self.absolute_url())
213: downloadZip()
214: return downloadZip.getResult()
1.8 casties 215:
1.1 dwinter 216: ## if not threadName or threadName=="":
217: ## threadStart=generateDownloadZip(self,self.absolute_url())
218: ## thread=Thread(target=threadStart)
1.6 casties 219:
1.1 dwinter 220: ## thread.start()
221:
1.6 casties 222:
1.1 dwinter 223: ## self.zipThreads[thread.getName()[0:]]=threadStart
224: ## self.zipThreads2[thread.getName()[0:]]=thread
225: ## self.REQUEST.SESSION['threadName']=thread.getName()[0:]
226: ## wait_template=self.aq_parent.ZopeFind(self.aq_parent,obj_ids=['zip_wait_template'])
227: ## if wait_template:
228: ## return wait_template[0][1]()
229: ## pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','zip_wait.zpt')).__of__(self)
230: ## return pt()
1.6 casties 231:
1.1 dwinter 232: ## else:
233: ## self.REQUEST.SESSION['threadName']=threadName
234:
235: ## if (self.zipThreads[threadName].getResult()==None):
236:
237: ## wait_template=self.aq_parent.ZopeFind(self.aq_parent,obj_ids=['wait_template'])
238: ## if wait_template:
239: ## return wait_template[0][1]()
240:
241: ## pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','zip_wait.zpt')).__of__(self)
242: ## return pt()
243: ## else:
244: ## if self.zipThreads[threadName].isDone():
245: ## self.REQUEST.SESSION['result']=self.zipThreads[threadName].getResult()
246: ## self.zipThreads2[threadName].join()
247: ## del(self.zipThreads2[threadName])
248: ## del(self.zipThreads[threadName])
249: ## pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','zip_result.zpt')).__of__(self)
250: ## return pt()
251:
252: ## else:
253: ## self.REQUEST.SESSION['result']=self.zipThreads[threadName].getResult()
254: ## self.REQUEST.SESSION['threadName']=threadName
255: ## pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','zip_wait_result.zpt')).__of__(self)
256: ## return pt()
257:
258: def downloadSet(self,fn):
1.6 casties 259: """download prepared set"""
260: filename=os.path.join(tdir,fn)
1.1 dwinter 261:
1.6 casties 262:
263: self.REQUEST.RESPONSE.setHeader("Content-Disposition","""attachement; filename="%s" """%"downloadFileFolder.tgz")
264: self.REQUEST.RESPONSE.setHeader("Content-Type","application/octet-stream")
265: len=os.stat(filename)[6]
266: self.REQUEST.RESPONSE.setHeader("Content-Length",len)
267: images=file(filename).read()
268: self.REQUEST.RESPONSE.write(images)
269: self.REQUEST.RESPONSE.close()
1.1 dwinter 270:
271:
272:
273: def helpDownload(self):
274: """download help"""
275:
276: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','helpDownload')).__of__(self)
277: return pt()
278:
279: def generateIndexHTML_image(self,RESPONSE=None):
280: """lege standard index.html an"""
281:
282:
283: if not self.ZopeFind(self,obj_ids=['index.html']):
284: zt=ZopePageTemplate('index.html')
285: self._setObject('index.html',zt)
286: default_content_fn = os.path.join(package_home(globals()),
1.6 casties 287: 'zpt/versionFileFolderMain_image.zpt')
1.1 dwinter 288: text = open(default_content_fn).read()
289: zt.pt_edit(text, 'text/html')
290:
291: else:
292: return "already exists!"
293:
294: if RESPONSE is not None:
295: RESPONSE.redirect('manage_main')
296:
297:
298: def generateAddFileForm(self,RESPONSE=None):
299: """lege standard addfileform an"""
300: #TODO: write generateaddfileform only a dummy at them moment
301:
302: if not self.ZopeFind(self,obj_ids=['addFileForm.dtml']):
303: zt=ZopePageTemplate('index.html')
304: self._setObject('index.html',zt)
305: default_content_fn = os.path.join(package_home(globals()),
1.6 casties 306: 'zpt/versionFileFolderMain.zpt')
1.1 dwinter 307: text = open(default_content_fn).read()
308: zt.pt_edit(text, 'text/html')
309:
310: else:
311: return "already exists!"
312:
313: if RESPONSE is not None:
314: RESPONSE.redirect('manage_main')
315:
316:
317: def generateIndexHTML(self,RESPONSE=None):
318: """lege standard index.html an"""
319: if not self.ZopeFind(self,obj_ids=['index.html']):
320: zt=ZopePageTemplate('index.html')
321: self._setObject('index.html',zt)
322: default_content_fn = os.path.join(package_home(globals()),
1.6 casties 323: 'zpt/versionFileFolderMain.zpt')
1.1 dwinter 324: text = open(default_content_fn).read()
325: zt.pt_edit(text, 'text/html')
326:
327: else:
328: return "already exists!"
329:
330: if RESPONSE is not None:
331: RESPONSE.redirect('manage_main')
332:
333:
334: def generateHistoryHTML(self,RESPONSE=None):
335: """lege standard index.html an"""
336: if not self.ZopeFind(self,obj_ids=['history_template.html']):
337: zt=ZopePageTemplate('history_template.html')
338: self._setObject('history_template.html',zt)
339: default_content_fn = os.path.join(package_home(globals()),
1.6 casties 340: 'zpt/versionHistory.zpt')
1.1 dwinter 341: text = open(default_content_fn).read()
342: zt.pt_edit(text, 'text/html')
343:
344: else:
345: return "already exists!"
346:
347: if RESPONSE is not None:
348: RESPONSE.redirect('manage_main')
1.6 casties 349:
1.1 dwinter 350:
351: def getVersionedFiles(self,sortField='title'):
352: """get all versioned files"""
353:
354: def sortName(x,y):
355: return cmp(x[1].title.lower(),y[1].title.lower())
356:
357: def sortDate(x,y):
1.7 casties 358: return cmp(y[1].getContentObject().getTime(),x[1].getContentObject().getTime())
1.1 dwinter 359:
360: def sortComment(x,y):
1.6 casties 361: try:
362: xc=getattr(x[1],'comment','ZZZZZZZZZZZZZ').lower()
363: except:
364: xc='ZZZZZZZZZZZZZ'.lower()
365:
366: try:
367: yc=getattr(y[1],'comment','ZZZZZZZZZZZZZ').lower()
368: except:
369: yc='ZZZZZZZZZZZZZ'.lower()
370:
371: if (xc=='') or (xc=='ZZZZZZZZZZZZZ'.lower()):
372: try:
1.7 casties 373: xc=x[1].getContentObject().getVComment().lower()
1.6 casties 374: except:
375: xc='ZZZZZZZZZZZZZ'.lower()
376:
377: if (yc=='') or (yc=='ZZZZZZZZZZZZZ'.lower()):
378: try:
1.7 casties 379: yc=y[1].getContentObject().getVComment().lower()
1.6 casties 380: except:
381: yc='ZZZZZZZZZZZZZ'.lower()
382:
383: return cmp(xc,yc)
1.1 dwinter 384:
385: def sortAuthor(x,y):
386:
1.7 casties 387: return cmp(x[1].getContentObject().lastEditor().lower(),y[1].getContentObject().lastEditor().lower())
1.1 dwinter 388:
1.7 casties 389: versionedFiles=self.objectItems(self.file_meta_type)
390: logging.debug("versionedfiles: %s of type %s"%(repr(versionedFiles),repr(self.file_meta_type)))
1.1 dwinter 391:
392: if sortField=='title':
393: versionedFiles.sort(sortName)
394: elif sortField=='date':
395: versionedFiles.sort(sortDate)
396: elif sortField=='author':
397: versionedFiles.sort(sortAuthor)
398: elif sortField=='comment':
399: versionedFiles.sort(sortComment)
400:
401: return versionedFiles
402:
403:
404: def header_html(self):
1.5 casties 405: """zusaetzlicher header"""
1.1 dwinter 406: ext=self.ZopeFind(self,obj_ids=["header.html"])
407: if ext:
408: return ext[0][1]()
409: else:
410: return ""
411:
412:
413: security.declareProtected('View','index_html')
414: def index_html(self):
415: """main"""
416: ext=self.ZopeFind(self,obj_ids=["index.html"])
417: if ext:
418: return ext[0][1]()
419:
420: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','versionFileFolderMain')).__of__(self)
421: return pt()
422:
423:
424:
425: def addFileForm(self):
426: """add a file"""
427: ext=self.ZopeFind(self,obj_ids=["addFileForm.dtml"])
428: if ext:
429: return ext[0][1]('',globals(),version='1',AUTHENTICATED_USER=self.REQUEST.AUTHENTICATED_USER)
430:
431: out=DTMLFile('dtml/newFileAdd', globals(),Kind='versionedFileObject',kind='versionedFileObject',version='1').__of__(self)
432: return out()
433:
434:
1.8 casties 435: def addFile(self,vC,file,author='',newName='',content_type='',RESPONSE=None):
1.1 dwinter 436: """ add a new file"""
1.9 ! casties 437: # is file is a real file or a zope download object?
! 438: isRealFile = type(file) is types.FileType
! 439:
1.1 dwinter 440: if newName=='':
1.9 ! casties 441: logging.debug("fileobject: %s real:%s"%(repr(file),repr(isRealFile)))
! 442: if isRealFile:
! 443: filename = file.name
! 444: else:
! 445: filename=file.filename
! 446:
1.1 dwinter 447: id=filename[max(filename.rfind('/'),
1.6 casties 448: filename.rfind('\\'),
449: filename.rfind(':'),
450: )+1:]
1.1 dwinter 451:
452: else:
453: id=newName
454:
1.9 ! casties 455: if not vC:
! 456: vC=self.REQUEST.form['vC']
1.8 casties 457:
458: # get new extVersionedFile
459: vf = self._newVersionedFile(id,title=id)
1.1 dwinter 460: #if (getattr(self,'commentNonEmpty',0)==1) and vC.strip()=="":
1.8 casties 461: # add file to this folder
462: self._setObject(id,vf)
463: # add its content
464: logging.info("ADD: %s"%repr(vf))
1.9 ! casties 465: obj=vf.addContentObject(id,vC,author=author,file=file,content_type=content_type,from_tmp=isRealFile)
1.1 dwinter 466:
1.8 casties 467: self.REQUEST.SESSION['objID']=vf.getId()
1.1 dwinter 468: self.REQUEST.SESSION['objID_parent']=None
469:
470: if obj.getSize()==0:
471: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','errorUploadFile')).__of__(self)
472: return pt()
473:
1.9 ! casties 474: if RESPONSE is not None:
! 475: RESPONSE.redirect(self.REQUEST['URL1'])
1.1 dwinter 476:
477:
1.8 casties 478: def _newVersionedFile(self, id, title='', lockedBy=None, author=None):
479: """factory for versioned files. to be overridden in derived classes."""
480: return extVersionedFile(id, title, lockedBy=lockedBy, author=author)
481:
482:
1.1 dwinter 483: def deleteEmptyObject(self,submit,RESPONSE=None):
484: """deleteemptyobject"""
485: if submit=="delete it":
486: if self.REQUEST.SESSION['objID_parent']:
487: obj=getattr(self,self.REQUEST.SESSION['objID_parent'])
488:
489: else:
490: obj=self
491: obj.manage_delObjects([self.REQUEST.SESSION['objID']])
492:
493: RESPONSE.redirect(self.REQUEST['URL1'])
494:
1.7 casties 495:
496: security.declareProtected('AUTHENTICATED_USER','fixVersionNumbers')
497: def fixVersionNumbers(self):
498: """fix last version number of all files"""
499: for (id,vf) in self.getVersionedFiles():
500: vf.fixVersionNumbers()
1.1 dwinter 501:
1.8 casties 502:
1.1 dwinter 503: manage_addextVersionedFileFolderForm=DTMLFile('dtml/extfolderAdd', globals())
504:
505:
506: def manage_addextVersionedFileFolder(self, id, title='',
1.6 casties 507: createPublic=0,
508: createUserF=0,
509: REQUEST=None):
1.1 dwinter 510: """Add a new Folder object with id *id*.
511:
512: If the 'createPublic' and 'createUserF' parameters are set to any true
513: value, an 'index_html' and a 'UserFolder' objects are created respectively
514: in the new folder.
515: """
516: ob=extVersionedFileFolder()
517: ob.id=str(id)
518: ob.title=title
519: self._setObject(id, ob)
520: ob=self._getOb(id)
521:
522: checkPermission=getSecurityManager().checkPermission
523:
524: if createUserF:
525: if not checkPermission('Add User Folders', ob):
526: raise Unauthorized, (
1.6 casties 527: 'You are not authorized to add User Folders.'
528: )
1.1 dwinter 529: ob.manage_addUserFolder()
530:
1.6 casties 531:
1.1 dwinter 532: if REQUEST is not None:
533: return self.manage_main(self, REQUEST, update_menu=1)
534:
535:
536:
537: class extVersionedFileObject(ExtFile):
538: """File Object im Folder"""
539: security= ClassSecurityInfo()
540: meta_type = "extVersionedFileObject"
541:
1.7 casties 542: manage_editForm=DTMLFile('dtml/fileEdit',globals(),
1.1 dwinter 543: Kind='File',kind='file')
544: manage_editForm._setName('manage_editForm')
545:
1.7 casties 546: def __init__(self, id, title='', versionNumber=0, versionComment=None, time=None, author=None):
547: """Initialize a new instance of extVersionedFileObject (taken from ExtFile)"""
548: ExtFile.__init__(self,id,title)
549: self.versionNumber = versionNumber
550: self.versionComment= versionComment
551: self.time = time
552: self.author = author
553:
554:
1.1 dwinter 555: security.declarePublic('getTitle')
556: def getTitle(self):
557: """get title"""
558: return self.title
1.6 casties 559:
560: def getData(self):
561: """returns object content (calls ExtFile.index_html)"""
562: return ExtFile.index_html(self)
563:
1.1 dwinter 564: security.declarePublic('getVComment')
565: def getVComment(self):
566: """get the comment of this file"""
567: if not hasattr(self,'vComment') or (not self.vComment) or (self.vComment.lstrip()==""):
568: return "Add comment"
569:
570: else:
571: return self.vComment
1.6 casties 572:
1.1 dwinter 573: def manageVCommentForm(self):
574: """add a comment"""
575: self.REQUEST.SESSION['refer']=self.REQUEST['HTTP_REFERER']
576: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addVComment')).__of__(self)
577: return pt()
578:
579: def manageVComment(self,text,comment_author,submit,REQUEST=None):
580: """manage comments"""
581: if submit =='change':
582: if text=='':
583: self.vComment=None
584: else:
585: self.vComment=text
586: self.vComment_author=comment_author
587:
588: self.vComment_date=time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())
589:
590: if self.REQUEST.SESSION.has_key('refer'):
591:
592: return REQUEST.RESPONSE.redirect(self.REQUEST.SESSION['refer'])
593: return REQUEST.RESPONSE.redirect(self.aq_parent.absolute_url()+"/history")
594:
595:
596: security.declarePublic('getVersionComment')
597: def getVersionComment(self):
598: """getversioncomment"""
599: return self.versionComment
600:
601: security.declarePublic('getTime')
602: def getTime(self):
603: """getTime"""
604: #return self.bobobase_modification_time().ISO()
605: if hasattr(self,'time'):
606: return time.strftime("%Y-%m-%d %H:%M:%S",self.time)
607: elif hasattr(self,'timefixed'):
1.6 casties 608: return self.timefixed
1.1 dwinter 609: else:
610: setattr(self,'timefixed',self.bobobase_modification_time().ISO())
611: return self.bobobase_modification_time().ISO()
612:
613: def download(self,REQUEST=None,RESPONSE=None):
614: """download and lock"""
615:
616: self.REQUEST.RESPONSE.setHeader("Content-Disposition","""attachement; filename=%s"""%self.getId())
617: self.REQUEST.RESPONSE.setHeader("Content-Type","application/octet-stream")
618: #try:
619: # txt=self.index_html()
620: #except:
621: # txt=self.index_html(REQUEST,RESPONSE)
622: #
623: #self.REQUEST.RESPONSE.setHeader("Content-Length","str(len(txt)+1000)")
624:
625: self.content_type="application/octet-stream"
626: self.REQUEST.RESPONSE.redirect(self.absolute_url())
627: #txt=urllib.urlopen(self.absolute_url()).read()
628: #self.REQUEST.RESPONSE.write(txt)
629:
630:
631: #self.REQUEST.close()
632:
633: security.declareProtected('AUTHENTICATED_USER','downloadLocked')
634: def downloadLocked(self):
635: """download and lock"""
636:
637:
638: if repr(self.REQUEST['AUTHENTICATED_USER'])=='Anonymous User':
639: return "please login first"
640: if not self.aq_parent.lockedBy=="":
641: return "cannot be locked because is already locked by %s"%self.lockedBy
642: self.aq_parent.lockedBy=self.REQUEST['AUTHENTICATED_USER']
643:
644: self.content_type="application/octet-stream"
645: self.REQUEST.RESPONSE.redirect(self.absolute_url())
646:
647: security.declarePublic('getVersionNumber')
648: def getVersionNumber(self):
649: """get version"""
650: return self.versionNumber
651:
652: security.declarePublic('getVersionComment')
653: def getVersionComment(self):
654: """get version"""
655: return self.versionComment
656:
657: security.declarePublic('lastEditor')
658: def lastEditor(self):
659: """last Editor"""
660: if hasattr(self,'author'):
661: try:
662: ret=self.author.replace("-","\n")
663: except:#old version of versionded file sometimes stored the user object and not only the name the following corrects this
664: ret=str(self.author).replace("-","\n")
665: ret=ret.replace("\r","\n")
666: return ret.lstrip().rstrip()
667:
668: else:
669: jar=self._p_jar
670: oid=self._p_oid
671:
672: if jar is None or oid is None: return None
673:
674: return jar.db().history(oid)[0]['user_name']
675:
676:
677: manage_addextVersionedFileObjectForm=DTMLFile('dtml/fileAdd', globals(),Kind='extVersionedFileObject',kind='extVersionedFileObject', version='1')
678:
1.7 casties 679: def manage_addextVersionedFileObject(self,id,vC='',author='', file='',title='',versionNumber=0,
680: precondition='', content_type='', REQUEST=None):
1.1 dwinter 681: """Add a new File object.
682:
683: Creates a new File object 'id' with the contents of 'file'"""
684:
685: id=str(id)
686: title=str(title)
687: content_type=str(content_type)
688: precondition=str(precondition)
689:
690: id, title = cookId(id, title, file)
691:
692: self=self.this()
693:
694: # First, we create the file without data:
1.7 casties 695: self._setObject(id, extVersionedFileObject(id,title,versionNumber=versionNumber,versionComment=str(vC),author=author))
696: fob = self._getOb(id)
1.1 dwinter 697:
698: # Now we "upload" the data. By doing this in two steps, we
699: # can use a database trick to make the upload more efficient.
700: if file:
1.7 casties 701: fob.manage_upload(file)
1.1 dwinter 702: if content_type:
1.7 casties 703: fob.content_type=content_type
1.1 dwinter 704:
705: if REQUEST is not None:
706: REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main')
707:
708:
709:
710: class extVersionedFile(CatalogAware,Folder):
711: """Versioniertes File"""
712:
1.7 casties 713: meta_type = 'extVersionedFile'
714: # meta_type of contained objects
715: content_meta_type = ['extVersionedFileObject']
716: default_catalog = 'fileCatalog'
1.1 dwinter 717:
1.7 casties 718: security=ClassSecurityInfo()
1.1 dwinter 719:
1.7 casties 720: def __init__(self, id, title, lockedBy,author):
721: """init"""
722: self.id=id
723: self.title=title
724: self.lockedBy=lockedBy
725: self.author=author
726: self.lastVersionNumber=0
727: self.lastVersionId=None
728:
1.1 dwinter 729: security.declarePublic('getTitle')
730: def getTitle(self):
731: """get title"""
732: return self.title
733:
734: def PrincipiaSearchSource(self):
1.6 casties 735: """Return cataloguable key for ourselves."""
736: return str(self)
1.1 dwinter 737:
738: def manageImagesForm(self):
739: """manage Images attached to the file"""
740:
741: self.REQUEST.SESSION['refer']=self.REQUEST['HTTP_REFERER']
742:
743: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','manageImage')).__of__(self)
744: return pt()
745:
746: def manageImages(self,imageUrl=None,caption=None,REQUEST=None):
747: """manage URL"""
748: if imageUrl and (not imageUrl==""):
749: manage_AddImageZogiLib(self,libPath=imageUrl,caption=caption)
750:
751: if self.REQUEST.SESSION.has_key('refer'):
752:
753: return REQUEST.RESPONSE.redirect(self.REQUEST.SESSION['refer'])
754: return REQUEST.RESPONSE.redirect(self.aq_parent.absolute_url())
755:
756: def changeImages(self,caption=None,submit=None,id=None,REQUEST=None):
757: """manage URL"""
758: if submit=="change caption":
759: image=self.ZopeFind(self,obj_ids=[id])
760: if image:
761: image[0][1].caption=caption[0:]
762:
763: elif submit=="delete":
764: image=self.ZopeFind(self,obj_ids=[id])
765: if image:
766: self.manage_delObjects([image[0][1].getId()])
767:
768: if self.REQUEST.SESSION.has_key('refer'):
1.7 casties 769: return REQUEST.RESPONSE.redirect(self.REQUEST.SESSION['refer'])
1.1 dwinter 770:
771: return REQUEST.RESPONSE.redirect(self.aq_parent.absolute_url())
772:
773: def getImages(self):
774: """get Images"""
775: images=self.ZopeFind(self,obj_metatypes=["ImageZogiLib"])
776: if not images:
777: return None
778: else:
779: return images
1.6 casties 780:
1.1 dwinter 781: security.declarePublic('getComment')
782: def getComment(self):
783: """get the comment of this file"""
784: if not hasattr(self,'comment') or (not self.comment) or (self.comment.lstrip()==""):
785: return "Add comment"
786: else:
787: return self.comment
788:
789: def manageCommentForm(self):
790: """add a comment"""
791: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addComment')).__of__(self)
792: return pt()
793:
794: def manageComment(self,text,comment_author,submit,REQUEST=None):
795: """manage comments"""
796: if submit =='change':
797: if text=='':
798: self.comment=None
799: else:
800: self.comment=text
801: self.comment_author=comment_author
802:
803: self.comment_date=time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())
804:
805: return REQUEST.RESPONSE.redirect(self.aq_parent.absolute_url())
1.6 casties 806:
1.1 dwinter 807: security.declarePublic('getLastChangeDate')
808: def getLastChangeDate(self):
809: """get last change date"""
1.7 casties 810: lv=self.getContentObject()
1.1 dwinter 811: time=lv.getTime()
812: return time
813:
814: def getLastEditor(self):
815: """get last change date"""
1.7 casties 816: lv=self.getContentObject()
1.1 dwinter 817: le=lv.lastEditor()
818: return le
819:
820: def getLockedBy(self):
821: """get locked by"""
822: return str(self.lockedBy)
1.6 casties 823:
1.7 casties 824: def getLastVersionNumber(self):
825: """returns the highest version number of all included objects"""
826: lv = self.findLastVersion()
827: if lv:
828: return lv.getVersionNumber()
829: else:
830: return 0
831:
832: def findLastVersion(self):
833: """finds and returns the object with the highest version number"""
834: lvn=0
835: lv=None
836:
837: for v in self.objectValues(self.content_meta_type):
838: logging.debug("findlastversion: check %s"%v.getId())
839: if v.getVersionNumber() > lvn:
840: lvn=v.getVersionNumber()
841: lv=v
842:
843: if lv:
844: logging.debug("findlastversion: got %s"%lv.getId())
845: return lv
846:
1.1 dwinter 847: security.declarePublic('getLastVersion')
848: def getLastVersion(self):
1.7 casties 849: """Last Version (old)"""
1.1 dwinter 850: tmp=0
1.7 casties 851: lv=None
1.1 dwinter 852:
1.7 casties 853: for v in self.objectValues(self.content_meta_type):
854: logging.debug("getlastversion: check %s"%v.getId())
855: if v.getVersionNumber() > tmp:
856: tmp=v.getVersionNumber()
857: lv=v
858:
859: logging.debug("getlastversion: got %s"%lv.getId())
860: return lv
861:
862: def getContentObject(self):
863: """returns the last version object"""
864: if not self.lastVersionId:
865: lv = self.findLastVersion()
866: if lv is None:
867: return None
868: self.lastVersionNumber = lv.getVersionNumber()
869: self.lastVersionId = lv.getId()
1.1 dwinter 870:
1.7 casties 871: return getattr(self, self.lastVersionId)
872:
873: security.declarePublic('getData')
874: def getData(self):
875: """Returns the content of the last version"""
876: ob = self.getContentObject()
877: if ob is not None:
878: return ob.getData()
879: else:
880: return None
1.1 dwinter 881:
882: def diff(self,data):
883: """differenz between lastversion and data"""
884: d=Differ()
1.7 casties 885: tmp=self.getData()
1.1 dwinter 886: #print "XX",data,tmp
887: try:
1.6 casties 888: l=list(d.compare(data.splitlines(1),tmp.splitlines(1)))
1.1 dwinter 889: except:
890: return 0,""
891: plus=0
892: minus=0
893: for a in l:
894: if a[0]=='+':
895: plus+=1
896: if a[0]=='-':
897: minus+=1
898:
899: return max([plus,minus]),l
1.6 casties 900:
901:
1.1 dwinter 902: security.declarePublic('index_html')
903: def index_html(self):
904: """main view"""
1.7 casties 905: #lastVersion=self.getContentObject()
1.1 dwinter 906: #return "File:"+self.title+" Version:%i"%lastVersion.versionNumber," modified:",lastVersion.bobobase_modification_time()," size:",lastVersion.getSize(),"modified by:",lastVersion.lastEditor()
1.4 dwinter 907: #return "File: %s Version:%i modified:%s size:%s modified by:%s"%(self.title,lastVersion.versionNumber,lastVersion.getTime(),lastVersion.getSize(),lastVersion.lastEditor())
908: return self.history()
1.1 dwinter 909:
1.6 casties 910:
1.1 dwinter 911: security.declarePublic('getVersion')
912: def getVersion(self):
1.7 casties 913: # TODO: this is ugly and it returns the next version number
1.1 dwinter 914: tmp=0
915: for version in self.ZopeFind(self):
916:
917: if hasattr(version[1],'versionNumber'):
918:
919: if int(version[1].versionNumber) > tmp:
920: tmp=int(version[1].versionNumber,)
1.7 casties 921: return tmp+1
1.1 dwinter 922:
923: def history(self):
924: """history"""
925: ext=self.ZopeFind(self.aq_parent,obj_ids=["history_template.html"])
926: if ext:
927: return getattr(self,ext[0][1].getId())()
928:
929: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','versionHistory')).__of__(self)
930: return pt()
931:
932: def getVersions(self):
933: """get all versions"""
934: ret=[]
935: for version in self.ZopeFind(self):
936: if hasattr(version[1],'versionNumber'):
937: ret.append((version[1].versionNumber,version[1]))
938: ret.sort(sortv)
939: return ret
940:
941: security.declareProtected('AUTHENTICATED_USER','forceunlock')
942: def forceunlock(self,RESPONSE=None):
943: """unlock"""
944: #safe who had the lock
945: if self.lockedBy:
946: self.brokenLock=str(self.lockedBy)
947: else:
948: self.brokenLock=""
949: self.lockedBy=''
950: return self.brokenLock
951:
952: security.declareProtected('AUTHENTICATED_USER','unlock')
953: def unlock(self,RESPONSE):
954: """unlock"""
955: if str(self.lockedBy) in [str(self.REQUEST['AUTHENTICATED_USER'])]:
956: self.lockedBy=''
957: RESPONSE.redirect(self.REQUEST['HTTP_REFERER'])
958: else:
959: return "Sorry, not locked by you! (%s,%s)"%(self.lockedBy,self.REQUEST['AUTHENTICATED_USER'])
960:
1.7 casties 961:
962: def _newContentObject(self, id, title='', versionNumber=0, versionComment=None, time=None, author=None):
963: """factory for content objects. to be overridden in derived classes."""
964: return extVersionedFileObject(id,title,versionNumber=versionNumber,versionComment=versionComment,time=time,author=author)
965:
966:
967: def addContentObject(self,id,vC,author=None,file=None,title='',changeName='no',newName='',from_tmp=False,
968: precondition='', content_type=''):
969: """add"""
970:
971: if changeName=="yes":
972: filename=file.filename
973: self.title=filename[max(filename.rfind('/'),
974: filename.rfind('\\'),
975: filename.rfind(':'),
976: )+1:]
977:
978: if not newName=='':
979: self.title=newName[0:]
980:
981: posVersNum=getattr(self,'positionVersionNum','front')
982:
983: versNum = self.getLastVersionNumber() + 1
984:
985: if posVersNum=='front':
986: id="V%i_%s"%(versNum,self.title)
987: else:
988: fn=os.path.splitext(self.title)
989: if len(fn)>1:
990: id=fn[0]+"_V%i%s"%(versNum,fn[1])
991: else:
992: id=fn[0]+"_V%i"%versNum
1.1 dwinter 993:
1.7 casties 994: # what does this do?
995: id, title = cookId(id, title, file)
996: self=self.this()
997:
998: # First, we create the file without data:
999: self._setObject(id, self._newContentObject(id,title,versionNumber=versNum,versionComment=str(vC),
1000: time=time.localtime(),author=author))
1001: fob = self._getOb(id)
1002:
1003: # Now we "upload" the data. By doing this in two steps, we
1004: # can use a database trick to make the upload more efficient.
1005: if file and not from_tmp:
1006: fob.manage_upload(file)
1007: elif file and from_tmp:
1008: fob.manage_file_upload(file) # manage_upload_from_tmp doesn't exist in ExtFile2
1009: # fob.manage_upload_from_tmp(file) # manage_upload_from_tmp doesn't exist in ExtFile2
1010: fob.content_type=content_type
1011:
1012: self.lastVersionNumber = versNum
1013: self.lastVersionId = id
1014:
1.9 ! casties 1015: #logging.debug("addcontentobject: lastversion=%s"%self.getData())
1.7 casties 1016: logging.debug("reindex1: %s in %s"%(repr(self),repr(self.default_catalog)))
1017: self.reindex_object()
1.9 ! casties 1018: #logging.debug("addcontentobject: fob_data=%s"%fob.getData())
1.7 casties 1019:
1020: return fob
1021:
1.1 dwinter 1022:
1023: security.declareProtected('AUTHENTICATED_USER','addVersionedFileObjectForm')
1024: def addVersionedFileObjectForm(self):
1025: """add a new version"""
1026:
1027: if str(self.REQUEST['AUTHENTICATED_USER']) in ["Anonymous User"]:
1028: return "please login first"
1029: if (self.lockedBy==self.REQUEST['AUTHENTICATED_USER']) or (self.lockedBy==''):
1030: ext=self.ZopeFind(self.aq_parent,obj_ids=["addNewVersion.dtml"])
1031: if ext:
1.7 casties 1032: return ext[0][1]('',globals(),version=self.getVersion(),lastComment=self.getContentObject().getVersionComment(),AUTHENTICATED_USER=self.REQUEST.AUTHENTICATED_USER)
1.1 dwinter 1033: else:
1034: out=DTMLFile('dtml/fileAdd', globals(),Kind='VersionedFileObject',kind='versionedFileObject',version=self.getVersion()).__of__(self)
1035: return out()
1036: else:
1037: return "Sorry file is locked by somebody else"
1.7 casties 1038:
1.1 dwinter 1039:
1.7 casties 1040: def manage_addVersionedFileObject(self,id,vC,author,file='',title='',precondition='', content_type='',changeName='no',newName='', from_tmp=False, RESPONSE=None):
1.1 dwinter 1041: """add"""
1042: try: #der ganze vC unsinn muss ueberarbeitet werden
1043: vC=self.REQUEST['vC']
1044: except:
1045: pass
1046:
1047: author=self.REQUEST['author']
1048:
1.7 casties 1049: ob = self.addContentObject(id, vC, author, file, title, changeName=changeName, newName=newName, from_tmp=from_tmp,
1050: precondition=precondition, content_type=content_type)
1051:
1.1 dwinter 1052: self.REQUEST.SESSION['objID_parent']=self.getId()
1053:
1054: if RESPONSE:
1.7 casties 1055: if ob.getSize()==0:
1056: self.REQUEST.SESSION['objID']=ob.getId()
1.1 dwinter 1057: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','errorUploadFile')).__of__(self)
1058: return pt()
1059:
1060: else:
1061: RESPONSE.redirect(self.REQUEST['URL2'])
1062: else:
1.7 casties 1063: return ob
1.6 casties 1064:
1.1 dwinter 1065:
1066: def download(self):
1067: """download and lock"""
1.7 casties 1068: self.REQUEST.RESPONSE.setHeader("Content-Disposition","""attachement; filename=%s"""%self.getContentObject().getId())
1.1 dwinter 1069: self.REQUEST.RESPONSE.setHeader("Content-Type","application/octet-stream")
1070: self.content_type="application/octet-stream"
1.7 casties 1071: self.REQUEST.RESPONSE.redirect(self.REQUEST['URL1']+'/'+self.getId()+'/'+self.getContentObject().getId())
1.1 dwinter 1072:
1073: security.declareProtected('AUTHENTICATED_USER','downloadLocked')
1074: def downloadLocked(self):
1075: """download and lock"""
1076:
1077: if repr(self.REQUEST['AUTHENTICATED_USER'])=='Anonymous User':
1078: return "please login first"
1079: if not self.lockedBy=="":
1080: return "cannot be locked because is already locked by %s"%self.lockedBy
1081: self.lockedBy=self.REQUEST['AUTHENTICATED_USER']
1.7 casties 1082: self.getContentObject().content_type="application/octet-stream"
1083: self.REQUEST.RESPONSE.redirect(self.REQUEST['URL1']+'/'+self.getId()+'/'+self.getContentObject().getId())
1084:
1085:
1086: security.declareProtected('AUTHENTICATED_USER','fixVersionNumbers')
1087: def fixVersionNumbers(self):
1088: """check last version number and id"""
1089: if not hasattr(self, 'lastVersionId'):
1090: self.lastVersionNumber = 0
1091: self.lastVersionId = None
1092:
1093: lv = self.getContentObject()
1094: if lv is not None:
1095: lvn = lv.getVersionNumber()
1096: if lvn == 0:
1097: lvn = 1
1098: lv.versionNumber = 1
1099: self.lastVersionNumber = lvn
1100: self.lastVersionId = lv.getId()
1101: else:
1102: self.lastVersionNumber = 0
1103: self.lastVersionId = None
1104: logging.debug("fixing last version number of %s to %s (%s)"%(self.getId(),self.lastVersionNumber,self.lastVersionId))
1105:
1.1 dwinter 1106:
1107: def manage_addextVersionedFileForm(self):
1108: """interface for adding the OSAS_root"""
1109: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addextVersionedFile.zpt')).__of__(self)
1110: return pt()
1111:
1112: def manage_addextVersionedFile(self,id,title,lockedBy, author=None, RESPONSE=None):
1113: """add the OSAS_root"""
1114: newObj=extVersionedFile(id,title,lockedBy,author)
1115: self._setObject(id,newObj)
1.6 casties 1116:
1.1 dwinter 1117: if RESPONSE is not None:
1118: RESPONSE.redirect('manage_main')
1119:
1120:
1121: InitializeClass(extVersionedFile)
1122: InitializeClass(extVersionedFileFolder)
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>