1:
2:
3: from OFS.Folder import Folder
4: from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
5: from Products.PageTemplates.PageTemplateFile import PageTemplateFile
6: from AccessControl import ClassSecurityInfo
7: from AccessControl import getSecurityManager
8: from Globals import package_home
9:
10: from Ft.Xml.Domlette import NonvalidatingReader
11: from Ft.Xml.Domlette import PrettyPrint, Print
12: from Ft.Xml import EMPTY_NAMESPACE, Parse
13:
14: import Ft.Xml.XPath
15:
16: import os.path
17: import sys
18: import cgi
19: import urllib
20: import zLOG
21: import urlparse
22:
23: def getInt(number, default=0):
24: """returns always an int (0 in case of problems)"""
25: try:
26: return int(number)
27: except:
28: return default
29:
30: def getTextFromNode(nodename):
31: """get the cdata content of a node"""
32: if nodename is None:
33: return ""
34: nodelist=nodename.childNodes
35: rc = ""
36: for node in nodelist:
37: if node.nodeType == node.TEXT_NODE:
38: rc = rc + node.data
39: return rc
40:
41:
42: def getParentDir(path):
43: """returns pathname shortened by one"""
44: return '/'.join(path.split('/')[0:-1])
45:
46:
47: import socket
48:
49: def urlopen(url,timeout=2):
50: """urlopen mit timeout"""
51: socket.setdefaulttimeout(timeout)
52: ret=urllib.urlopen(url)
53: socket.setdefaulttimeout(5)
54: return ret
55:
56:
57: ##
58: ## documentViewer class
59: ##
60: class documentViewer(Folder):
61: """document viewer"""
62: textViewerUrl="http://127.0.0.1:8080/HFQP/testXSLT/getPage?"
63:
64: meta_type="Document viewer"
65:
66: security=ClassSecurityInfo()
67: manage_options=Folder.manage_options+(
68: {'label':'main config','action':'changeDocumentViewerForm'},
69: )
70:
71: # templates and forms
72: viewer_main = PageTemplateFile('zpt/viewer_main', globals())
73: thumbs_main = PageTemplateFile('zpt/thumbs_main', globals())
74: image_main = PageTemplateFile('zpt/image_main', globals())
75: head_main = PageTemplateFile('zpt/head_main', globals())
76: docuviewer_css = PageTemplateFile('css/docuviewer.css', globals())
77:
78: security.declareProtected('View management screens','changeDocumentViewerForm')
79: changeDocumentViewerForm = PageTemplateFile('zpt/changeDocumentViewer', globals())
80:
81:
82: def __init__(self,id,imageViewerUrl,textViewerUrl=None,title="",digilibBaseUrl=None,thumbcols=2,thumbrows=10,authgroups="mpiwg"):
83: """init document viewer"""
84: self.id=id
85: self.title=title
86: self.imageViewerUrl=imageViewerUrl
87: self.textViewerUrl=textViewerUrl
88:
89: if not digilibBaseUrl:
90: self.digilibBaseUrl = self.findDigilibUrl()
91: else:
92: self.digilibBaseUrl = digilibBaseUrl
93: self.thumbcols = thumbcols
94: self.thumbrows = thumbrows
95: # authgroups is list of authorized groups (delimited by ,)
96: self.authgroups = [s.strip().lower() for s in authgroups.split(',')]
97: # add template folder so we can always use template.something
98: self.manage_addFolder('template')
99:
100:
101: security.declareProtected('View','index_html')
102: def index_html(self,mode,url,viewMode="images",start=None,pn=1):
103: '''
104: view it
105: @param mode: defines which type of document is behind url
106: @param url: url which contains display information
107: @param viewMode: if images display images, if text display text, default is images
108:
109: '''
110:
111: zLOG.LOG("documentViewer (index)", zLOG.INFO, "mode: %s url:%s start:%s pn:%s"%(mode,url,start,pn))
112:
113: if not hasattr(self, 'template'):
114: # create template folder if it doesn't exist
115: self.manage_addFolder('template')
116:
117: if not self.digilibBaseUrl:
118: self.digilibBaseUrl = self.findDigilibUrl() or "http://nausikaa.mpiwg-berlin.mpg.de/digitallibrary"
119:
120: docinfo = self.getDocinfo(mode=mode,url=url)
121: pageinfo = self.getPageinfo(start=start,current=pn,docinfo=docinfo)
122: pt = getattr(self.template, 'viewer_main')
123: return pt(docinfo=docinfo,pageinfo=pageinfo,viewMode=viewMode)
124:
125:
126: def getLink(self,param=None,val=None):
127: """link to documentviewer with parameter param set to val"""
128: params=self.REQUEST.form.copy()
129: if param is not None:
130: if val is None:
131: if params.has_key(param):
132: del params[param]
133: else:
134: params[param] = str(val)
135:
136: # quote values and assemble into query string
137: ps = "&".join(["%s=%s"%(k,urllib.quote(v)) for (k, v) in params.items()])
138: url=self.REQUEST['URL1']+"?"+ps
139: return url
140:
141:
142: def getStyle(self, idx, selected, style=""):
143: """returns a string with the given style and append 'sel' if path == selected."""
144: #zLOG.LOG("documentViewer (getstyle)", zLOG.INFO, "idx: %s selected: %s style: %s"%(idx,selected,style))
145: if idx == selected:
146: return style + 'sel'
147: else:
148: return style
149:
150:
151: def isAccessible(self, docinfo):
152: """returns if access to the resource is granted"""
153: access = docinfo.get('accessType', None)
154: zLOG.LOG("documentViewer (accessOK)", zLOG.INFO, "access type %s"%access)
155: if access is not None and access == 'free':
156: zLOG.LOG("documentViewer (accessOK)", zLOG.INFO, "access is free")
157: return True
158: elif access is None or access in self.authgroups:
159: # only local access -- only logged in users
160: user = getSecurityManager().getUser()
161: if user is not None:
162: #print "user: ", user
163: return (user.getUserName() != "Anonymous User")
164: else:
165: return False
166:
167: zLOG.LOG("documentViewer (accessOK)", zLOG.INFO, "unknown access type %s"%access)
168: return False
169:
170:
171: def getDirinfoFromDigilib(self,path,docinfo=None):
172: """gibt param von dlInfo aus"""
173: num_retries = 3
174: if docinfo is None:
175: docinfo = {}
176:
177: infoUrl=self.digilibBaseUrl+"/dirInfo-xml.jsp?mo=dir&fn="+path
178:
179: zLOG.LOG("documentViewer (getparamfromdigilib)", zLOG.INFO, "dirInfo from %s"%(infoUrl))
180:
181: for cnt in range(num_retries):
182: try:
183: # dom = NonvalidatingReader.parseUri(imageUrl)
184: txt=urllib.urlopen(infoUrl).read()
185: dom = Parse(txt)
186: break
187: except:
188: zLOG.LOG("documentViewer (getdirinfofromdigilib)", zLOG.ERROR, "error reading %s (try %d)"%(infoUrl,cnt))
189: else:
190: raise IOError("Unable to get dir-info from %s"%(infoUrl))
191:
192: sizes=dom.xpath("//dir/size")
193: zLOG.LOG("documentViewer (getparamfromdigilib)", zLOG.INFO, "dirInfo:size"%sizes)
194:
195: if sizes:
196: docinfo['numPages'] = int(getTextFromNode(sizes[0]))
197: else:
198: docinfo['numPages'] = 0
199:
200: return docinfo
201:
202:
203: def getIndexMeta(self, url):
204: """returns dom of index.meta document at url"""
205: num_retries = 3
206: dom = None
207: metaUrl = None
208: if url.startswith("http://"):
209: # real URL
210: metaUrl = url
211: else:
212: # online path
213: server=self.digilibBaseUrl+"/servlet/Texter?fn="
214: metaUrl=server+url.replace("/mpiwg/online","")
215: if not metaUrl.endswith("index.meta"):
216: metaUrl += "/index.meta"
217: print metaUrl
218: for cnt in range(num_retries):
219: try:
220: # patch dirk encoding fehler treten dann nicht mehr auf
221: # dom = NonvalidatingReader.parseUri(metaUrl)
222: txt=urllib.urlopen(metaUrl).read()
223: dom = Parse(txt)
224: break
225: except:
226: zLOG.LOG("ERROR documentViewer (getIndexMata)", zLOG.INFO,"%s (%s)"%sys.exc_info()[0:2])
227:
228: if dom is None:
229: raise IOError("Unable to read index meta from %s"%(url))
230:
231: return dom
232:
233:
234: def getAuthinfoFromIndexMeta(self,path,docinfo=None,dom=None):
235: """gets authorization info from the index.meta file at path or given by dom"""
236: zLOG.LOG("documentViewer (getauthinfofromindexmeta)", zLOG.INFO,"path: %s"%(path))
237:
238: access = None
239:
240: if docinfo is None:
241: docinfo = {}
242:
243: if dom is None:
244: dom = self.getIndexMeta(getParentDir(path))
245:
246: acctype = dom.xpath("//access-conditions/access/@type")
247: if acctype and (len(acctype)>0):
248: access=acctype[0].value
249: if access in ['group', 'institution']:
250: access = getTextFromNode(dom.xpath("//access-conditions/access/name")[0]).lower()
251:
252: docinfo['accessType'] = access
253: return docinfo
254:
255:
256: def getBibinfoFromIndexMeta(self,path,docinfo=None,dom=None):
257: """gets bibliographical info from the index.meta file at path or given by dom"""
258: zLOG.LOG("documentViewer (getbibinfofromindexmeta)", zLOG.INFO,"path: %s"%(path))
259:
260: if docinfo is None:
261: docinfo = {}
262:
263: if dom is None:
264: dom = self.getIndexMeta(getParentDir(path))
265:
266: metaData=self.metadata.main.meta.bib
267: bibtype=dom.xpath("//bib/@type")
268: if bibtype and (len(bibtype)>0):
269: bibtype=bibtype[0].value
270: else:
271: bibtype="generic"
272: bibtype=bibtype.replace("-"," ") # wrong typesiin index meta "-" instead of " " (not wrong! ROC)
273: bibmap=metaData.generateMappingForType(bibtype)
274: #print "bibmap: ", bibmap, " for: ", bibtype
275: # if there is no mapping bibmap is empty (mapping sometimes has empty fields)
276: if len(bibmap) > 0 and len(bibmap['author'][0]) > 0:
277: docinfo['author']=getTextFromNode(dom.xpath("//bib/%s"%bibmap['author'][0])[0])
278: docinfo['title']=getTextFromNode(dom.xpath("//bib/%s"%bibmap['title'][0])[0])
279: docinfo['year']=getTextFromNode(dom.xpath("//bib/%s"%bibmap['year'][0])[0])
280:
281: return docinfo
282:
283:
284: def getDocinfoFromTextTool(self,url,dom=None,docinfo=None):
285: """parse texttool tag in index meta"""
286: zLOG.LOG("documentViewer (getdocinfofromtexttool)", zLOG.INFO,"url: %s"%(url))
287: if docinfo is None:
288: docinfo = {}
289:
290: if dom is None:
291: dom = self.getIndexMeta(url)
292:
293: archivePath = None
294: archiveName = None
295:
296: archiveNames=dom.xpath("//resource/name")
297: if archiveNames and (len(archiveNames)>0):
298: archiveName=getTextFromNode(archiveNames[0])
299: else:
300: zLOG.LOG("documentViewer (getdocinfofromtexttool)", zLOG.WARNING,"resource/name missing in: %s"%(url))
301:
302: archivePaths=dom.xpath("//resource/archive-path")
303: if archivePaths and (len(archivePaths)>0):
304: archivePath=getTextFromNode(archivePaths[0])
305: # clean up archive path
306: if archivePath[0] != '/':
307: archivePath = '/' + archivePath
308: if archiveName and (not archivePath.endswith(archiveName)):
309: archivePath += "/" + archiveName
310: else:
311: # try to get archive-path from url
312: zLOG.LOG("documentViewer (getdocinfofromtexttool)", zLOG.WARNING,"resource/archive-path missing in: %s"%(url))
313: if (not url.startswith('http')):
314: archivePath = url.replace('index.meta', '')
315:
316: if archivePath is None:
317: # we balk without archive-path
318: raise IOError("Missing archive-path (for text-tool) in %s"%(url))
319:
320: imageDirs=dom.xpath("//texttool/image")
321: if imageDirs and (len(imageDirs)>0):
322: imageDir=getTextFromNode(imageDirs[0])
323: else:
324: # we balk with no image tag
325: raise IOError("No text-tool info in %s"%(url))
326:
327: if imageDir and archivePath:
328: #print "image: ", imageDir, " archivepath: ", archivePath
329: imageDir=os.path.join(archivePath,imageDir)
330: imageDir=imageDir.replace("/mpiwg/online",'')
331: docinfo=self.getDirinfoFromDigilib(imageDir,docinfo=docinfo)
332: docinfo['imagePath'] = imageDir
333: docinfo['imageURL'] = self.digilibBaseUrl+"/servlet/Scaler?fn="+imageDir
334:
335: viewerUrls=dom.xpath("//texttool/digiliburlprefix")
336: if viewerUrls and (len(viewerUrls)>0):
337: viewerUrl=getTextFromNode(viewerUrls[0])
338: docinfo['viewerURL'] = viewerUrl
339:
340: textUrls=dom.xpath("//texttool/text")
341: if textUrls and (len(textUrls)>0):
342: textUrl=getTextFromNode(textUrls[0])
343: if urlparse.urlparse(textUrl)[0]=="": #keine url
344: textUrl=os.path.join(archivePath,textUrl)
345:
346: docinfo['textURL'] = textUrl
347:
348: docinfo = self.getBibinfoFromIndexMeta(url,docinfo=docinfo,dom=dom)
349: docinfo = self.getAuthinfoFromIndexMeta(url,docinfo=docinfo,dom=dom)
350: return docinfo
351:
352:
353: def getDocinfoFromImagePath(self,path,docinfo=None):
354: """path ist the path to the images it assumes that the index.meta file is one level higher."""
355: zLOG.LOG("documentViewer (getdocinfofromimagepath)", zLOG.INFO,"path: %s"%(path))
356: if docinfo is None:
357: docinfo = {}
358: path=path.replace("/mpiwg/online","")
359: docinfo['imagePath'] = path
360: docinfo=self.getDirinfoFromDigilib(path,docinfo=docinfo)
361: imageUrl=self.digilibBaseUrl+"/servlet/Scaler?fn="+path
362: docinfo['imageURL'] = imageUrl
363:
364: docinfo = self.getBibinfoFromIndexMeta(path,docinfo=docinfo)
365: docinfo = self.getAuthinfoFromIndexMeta(path,docinfo=docinfo)
366: return docinfo
367:
368:
369: def getDocinfo(self, mode, url):
370: """returns docinfo depending on mode"""
371: zLOG.LOG("documentViewer (getdocinfo)", zLOG.INFO,"mode: %s, url: %s"%(mode,url))
372: # look for cached docinfo in session
373: if self.REQUEST.SESSION.has_key('docinfo'):
374: docinfo = self.REQUEST.SESSION['docinfo']
375: # check if its still current
376: if docinfo is not None and docinfo.get('mode') == mode and docinfo.get('url') == url:
377: zLOG.LOG("documentViewer (getdocinfo)", zLOG.INFO,"docinfo in session: %s"%docinfo)
378: return docinfo
379: # new docinfo
380: docinfo = {'mode': mode, 'url': url}
381: if mode=="texttool": #index.meta with texttool information
382: docinfo = self.getDocinfoFromTextTool(url, docinfo=docinfo)
383: elif mode=="imagepath":
384: docinfo = self.getDocinfoFromImagePath(url, docinfo=docinfo)
385: else:
386: zLOG.LOG("documentViewer (getdocinfo)", zLOG.ERROR,"unknown mode!")
387: raise ValueError("Unknown mode %s"%(mode))
388:
389: zLOG.LOG("documentViewer (getdocinfo)", zLOG.INFO,"docinfo: %s"%docinfo)
390: self.REQUEST.SESSION['docinfo'] = docinfo
391: return docinfo
392:
393:
394: def getPageinfo(self, current, start=None, rows=None, cols=None, docinfo=None):
395: """returns pageinfo with the given parameters"""
396: pageinfo = {}
397: current = getInt(current)
398: pageinfo['current'] = current
399: rows = int(rows or self.thumbrows)
400: pageinfo['rows'] = rows
401: cols = int(cols or self.thumbcols)
402: pageinfo['cols'] = cols
403: grpsize = cols * rows
404: pageinfo['groupsize'] = grpsize
405: start = getInt(start, default=(int(current / grpsize) * grpsize +1))
406: pageinfo['start'] = start
407: pageinfo['end'] = start + grpsize
408: if docinfo is not None:
409: np = int(docinfo['numPages'])
410: pageinfo['end'] = min(pageinfo['end'], np)
411: pageinfo['numgroups'] = int(np / grpsize)
412: if np % grpsize > 0:
413: pageinfo['numgroups'] += 1
414:
415: return pageinfo
416:
417: def text(self,mode,url,pn):
418: """give text"""
419: if mode=="texttool": #index.meta with texttool information
420: (viewerUrl,imagepath,textpath)=parseUrlTextTool(url)
421:
422: #print textpath
423: try:
424: dom = NonvalidatingReader.parseUri(textpath)
425: except:
426: return None
427:
428: list=[]
429: nodes=dom.xpath("//pb")
430:
431: node=nodes[int(pn)-1]
432:
433: p=node
434:
435: while p.tagName!="p":
436: p=p.parentNode
437:
438:
439: endNode=nodes[int(pn)]
440:
441:
442: e=endNode
443:
444: while e.tagName!="p":
445: e=e.parentNode
446:
447:
448: next=node.parentNode
449:
450: #sammle s
451: while next and (next!=endNode.parentNode):
452: list.append(next)
453: next=next.nextSibling
454: list.append(endNode.parentNode)
455:
456: if p==e:# beide im selben paragraphen
457: pass
458: # else:
459: # next=p
460: # while next!=e:
461: # print next,e
462: # list.append(next)
463: # next=next.nextSibling
464: #
465: # for x in list:
466: # PrettyPrint(x)
467: #
468: # return list
469: #
470:
471: def findDigilibUrl(self):
472: """try to get the digilib URL from zogilib"""
473: url = self.imageViewerUrl[:-1] + "/getScalerUrl"
474: print urlparse.urlparse(url)[0]
475: print urlparse.urljoin(self.absolute_url(),url)
476: try:
477: if urlparse.urlparse(url)[0]=='': #relative path
478: url=urlparse.urljoin(self.absolute_url()+"/",url)
479:
480: scaler = urlopen(url).read()
481: return scaler.replace("/servlet/Scaler?", "")
482: except:
483: return None
484:
485: def changeDocumentViewer(self,imageViewerUrl,textViewerUrl,title="",digilibBaseUrl=None,thumbrows=2,thumbcols=10,authgroups='mpiwg',RESPONSE=None):
486: """init document viewer"""
487: self.title=title
488: self.imageViewerUrl=imageViewerUrl
489: self.textViewerUrl=textViewerUrl
490: self.digilibBaseUrl = digilibBaseUrl
491: self.thumbrows = thumbrows
492: self.thumbcols = thumbcols
493: self.authgroups = [s.strip().lower() for s in authgroups.split(',')]
494: if RESPONSE is not None:
495: RESPONSE.redirect('manage_main')
496:
497:
498:
499:
500: # security.declareProtected('View management screens','renameImageForm')
501:
502: def manage_AddDocumentViewerForm(self):
503: """add the viewer form"""
504: pt=PageTemplateFile('zpt/addDocumentViewer', globals()).__of__(self)
505: return pt()
506:
507: def manage_AddDocumentViewer(self,id,imageViewerUrl="",textViewerUrl="",title="",RESPONSE=None):
508: """add the viewer"""
509: newObj=documentViewer(id,imageViewerUrl,title=title,textViewerUrl=textViewerUrl)
510: self._setObject(id,newObj)
511:
512: if RESPONSE is not None:
513: RESPONSE.redirect('manage_main')
514:
515:
516: ##
517: ## DocumentViewerTemplate class
518: ##
519: class DocumentViewerTemplate(ZopePageTemplate):
520: """Template for document viewer"""
521: meta_type="DocumentViewer Template"
522:
523:
524: def manage_addDocumentViewerTemplateForm(self):
525: """Form for adding"""
526: pt=PageTemplateFile('zpt/addDocumentViewerTemplate', globals()).__of__(self)
527: return pt()
528:
529: def manage_addDocumentViewerTemplate(self, id='viewer_main', title=None, text=None,
530: REQUEST=None, submit=None):
531: "Add a Page Template with optional file content."
532:
533: self._setObject(id, DocumentViewerTemplate(id))
534: ob = getattr(self, id)
535: ob.pt_edit(open(os.path.join(package_home(globals()),'zpt/viewer_main.zpt')).read(),None)
536: if title:
537: ob.pt_setTitle(title)
538: try:
539: u = self.DestinationURL()
540: except AttributeError:
541: u = REQUEST['URL1']
542:
543: u = "%s/%s" % (u, urllib.quote(id))
544: REQUEST.RESPONSE.redirect(u+'/manage_main')
545: return ''
546:
547:
548:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>