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: docinfo['textURL'] = textUrl
344:
345: docinfo = self.getBibinfoFromIndexMeta(url,docinfo=docinfo,dom=dom)
346: docinfo = self.getAuthinfoFromIndexMeta(url,docinfo=docinfo,dom=dom)
347: return docinfo
348:
349:
350: def getDocinfoFromImagePath(self,path,docinfo=None):
351: """path ist the path to the images it assumes that the index.meta file is one level higher."""
352: zLOG.LOG("documentViewer (getdocinfofromimagepath)", zLOG.INFO,"path: %s"%(path))
353: if docinfo is None:
354: docinfo = {}
355: path=path.replace("/mpiwg/online","")
356: docinfo['imagePath'] = path
357: docinfo=self.getDirinfoFromDigilib(path,docinfo=docinfo)
358: imageUrl=self.digilibBaseUrl+"/servlet/Scaler?fn="+path
359: docinfo['imageURL'] = imageUrl
360:
361: docinfo = self.getBibinfoFromIndexMeta(path,docinfo=docinfo)
362: docinfo = self.getAuthinfoFromIndexMeta(path,docinfo=docinfo)
363: return docinfo
364:
365:
366: def getDocinfo(self, mode, url):
367: """returns docinfo depending on mode"""
368: zLOG.LOG("documentViewer (getdocinfo)", zLOG.INFO,"mode: %s, url: %s"%(mode,url))
369: # look for cached docinfo in session
370: if self.REQUEST.SESSION.has_key('docinfo'):
371: docinfo = self.REQUEST.SESSION['docinfo']
372: # check if its still current
373: if docinfo is not None and docinfo.get('mode') == mode and docinfo.get('url') == url:
374: zLOG.LOG("documentViewer (getdocinfo)", zLOG.INFO,"docinfo in session: %s"%docinfo)
375: return docinfo
376: # new docinfo
377: docinfo = {'mode': mode, 'url': url}
378: if mode=="texttool": #index.meta with texttool information
379: docinfo = self.getDocinfoFromTextTool(url, docinfo=docinfo)
380: elif mode=="imagepath":
381: docinfo = self.getDocinfoFromImagePath(url, docinfo=docinfo)
382: else:
383: zLOG.LOG("documentViewer (getdocinfo)", zLOG.ERROR,"unknown mode!")
384: raise ValueError("Unknown mode %s"%(mode))
385:
386: zLOG.LOG("documentViewer (getdocinfo)", zLOG.INFO,"docinfo: %s"%docinfo)
387: self.REQUEST.SESSION['docinfo'] = docinfo
388: return docinfo
389:
390:
391: def getPageinfo(self, current, start=None, rows=None, cols=None, docinfo=None):
392: """returns pageinfo with the given parameters"""
393: pageinfo = {}
394: current = getInt(current)
395: pageinfo['current'] = current
396: rows = int(rows or self.thumbrows)
397: pageinfo['rows'] = rows
398: cols = int(cols or self.thumbcols)
399: pageinfo['cols'] = cols
400: grpsize = cols * rows
401: pageinfo['groupsize'] = grpsize
402: start = getInt(start, default=(int(current / grpsize) * grpsize +1))
403: pageinfo['start'] = start
404: pageinfo['end'] = start + grpsize
405: if docinfo is not None:
406: np = int(docinfo['numPages'])
407: pageinfo['end'] = min(pageinfo['end'], np)
408: pageinfo['numgroups'] = int(np / grpsize)
409: if np % grpsize > 0:
410: pageinfo['numgroups'] += 1
411:
412: return pageinfo
413:
414: def text(self,mode,url,pn):
415: """give text"""
416: if mode=="texttool": #index.meta with texttool information
417: (viewerUrl,imagepath,textpath)=parseUrlTextTool(url)
418:
419: #print textpath
420: try:
421: dom = NonvalidatingReader.parseUri(textpath)
422: except:
423: return None
424:
425: list=[]
426: nodes=dom.xpath("//pb")
427:
428: node=nodes[int(pn)-1]
429:
430: p=node
431:
432: while p.tagName!="p":
433: p=p.parentNode
434:
435:
436: endNode=nodes[int(pn)]
437:
438:
439: e=endNode
440:
441: while e.tagName!="p":
442: e=e.parentNode
443:
444:
445: next=node.parentNode
446:
447: #sammle s
448: while next and (next!=endNode.parentNode):
449: list.append(next)
450: next=next.nextSibling
451: list.append(endNode.parentNode)
452:
453: if p==e:# beide im selben paragraphen
454: pass
455: # else:
456: # next=p
457: # while next!=e:
458: # print next,e
459: # list.append(next)
460: # next=next.nextSibling
461: #
462: # for x in list:
463: # PrettyPrint(x)
464: #
465: # return list
466: #
467:
468: def findDigilibUrl(self):
469: """try to get the digilib URL from zogilib"""
470: url = self.imageViewerUrl[:-1] + "/getScalerUrl"
471: print urlparse.urlparse(url)[0]
472: print urlparse.urljoin(self.absolute_url(),url)
473: try:
474: if urlparse.urlparse(url)[0]=='': #relative path
475: url=urlparse.urljoin(self.absolute_url()+"/",url)
476:
477: scaler = urlopen(url).read()
478: return scaler.replace("/servlet/Scaler?", "")
479: except:
480: return None
481:
482: def changeDocumentViewer(self,imageViewerUrl,textViewerUrl,title="",digilibBaseUrl=None,thumbrows=2,thumbcols=10,authgroups='mpiwg',RESPONSE=None):
483: """init document viewer"""
484: self.title=title
485: self.imageViewerUrl=imageViewerUrl
486: self.textViewerUrl=textViewerUrl
487: self.digilibBaseUrl = digilibBaseUrl
488: self.thumbrows = thumbrows
489: self.thumbcols = thumbcols
490: self.authgroups = [s.strip().lower() for s in authgroups.split(',')]
491: if RESPONSE is not None:
492: RESPONSE.redirect('manage_main')
493:
494:
495:
496:
497: # security.declareProtected('View management screens','renameImageForm')
498:
499: def manage_AddDocumentViewerForm(self):
500: """add the viewer form"""
501: pt=PageTemplateFile('zpt/addDocumentViewer', globals()).__of__(self)
502: return pt()
503:
504: def manage_AddDocumentViewer(self,id,imageViewerUrl="",textViewerUrl="",title="",RESPONSE=None):
505: """add the viewer"""
506: newObj=documentViewer(id,imageViewerUrl,title=title,textViewerUrl=textViewerUrl)
507: self._setObject(id,newObj)
508:
509: if RESPONSE is not None:
510: RESPONSE.redirect('manage_main')
511:
512:
513: ##
514: ## DocumentViewerTemplate class
515: ##
516: class DocumentViewerTemplate(ZopePageTemplate):
517: """Template for document viewer"""
518: meta_type="DocumentViewer Template"
519:
520:
521: def manage_addDocumentViewerTemplateForm(self):
522: """Form for adding"""
523: pt=PageTemplateFile('zpt/addDocumentViewerTemplate', globals()).__of__(self)
524: return pt()
525:
526: def manage_addDocumentViewerTemplate(self, id='viewer_main', title=None, text=None,
527: REQUEST=None, submit=None):
528: "Add a Page Template with optional file content."
529:
530: self._setObject(id, DocumentViewerTemplate(id))
531: ob = getattr(self, id)
532: ob.pt_edit(open(os.path.join(package_home(globals()),'zpt/viewer_main.zpt')).read(),None)
533: if title:
534: ob.pt_setTitle(title)
535: try:
536: u = self.DestinationURL()
537: except AttributeError:
538: u = REQUEST['URL1']
539:
540: u = "%s/%s" % (u, urllib.quote(id))
541: REQUEST.RESPONSE.redirect(u+'/manage_main')
542: return ''
543:
544:
545:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>