root/CPS3/products/CPSOOo/trunk/OOoDocbookDocument.py

Revision 52633, 26.9 kB (checked in by madarche, 1 year ago)

- Factorized the toLatin9 method in CPSUtil.text.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 # -*- coding: ISO-8859-15 -*-
2 # (C) Copyright 2004-2008 Nuxeo SAS <http://nuxeo.com>
3 # Authors:
4 # M.-A. Darche (Nuxeo)
5 # Ruslan Spivak (Nuxeo)
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License version 2 as published
9 # by the Free Software Foundation.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 # 02111-1307, USA.
20 #
21 # $Id$
22
23 import re
24 import os
25 import os.path
26 import shutil
27 import tempfile
28 import xml.dom.minidom
29 import xml.dom.ext
30 from zipfile import ZipFile
31 from zipfile import ZIP_DEFLATED
32 from zipfile import BadZipfile
33 from cStringIO import StringIO
34
35 from Globals import InitializeClass
36 from Acquisition import aq_base
37 from AccessControl import ClassSecurityInfo
38 from OFS.Image import File
39
40 from Products.CMFCore.permissions import View
41 from Products.CPSUtil.text import toLatin9
42 from Products.CPSDocument.CPSDocument import CPSDocument
43
44 from App.Common import rfc1123_date
45
46 # lxml should provide ElementTree API in case ElementTree is not installed
47 # TODO: after dust has settled, remove dependence on ElementTree completely
48 try:
49     from elementtree.ElementTree import XML, ElementTree
50     from elementtree.ElementPath import findall as xpath_findall
51     from elementtree.ElementPath import find as xpath_find
52 except ImportError:
53     from lxml.etree import XML, ElementTree
54     from lxml._elementpath import findall as xpath_findall
55     from lxml._elementpath import find as xpath_find
56
57 from zLOG import LOG, \
58      TRACE, DEBUG, BLATHER, INFO, PROBLEM, WARNING, ERROR, PANIC
59
60 log_key = 'OOoDocbookDocument'
61
62 def toUnicode(s):
63     return unicode(s, 'iso-8859-15')
64
65 def mktempdir():
66     """Make a temporary directory, returns its filename."""
67     fd, filename = tempfile.mkstemp(suffix='dir')
68     os.close(fd)
69     os.unlink(filename)
70     os.mkdir(filename, 0700)
71     return filename
72
73 def findFirstText(inElement, elementName):
74     elts = xpath_findall(inElement, elementName)
75     text = ''
76     for elt in elts:
77         if elt.text:
78             text = toLatin9(elt.text)
79             break
80     return text
81
82 def findText(inElement, elementName):
83     elt = xpath_find(inElement, elementName)
84     if elt is not None:
85         text = toLatin9(elt.text)
86     else:
87         text = ''
88     return text
89
90 def iterDoc(parent_node, func, iter_context):
91     """Iterate on all element nodes of a document
92
93     Calls func for each node, passing it an iteration context.
94     """
95     for node in parent_node.childNodes:
96         #print node.nodeName
97         if node.nodeType != xml.dom.Node.ELEMENT_NODE:
98             continue
99         func(node, iter_context)
100         iterDoc(node, func, iter_context)
101
102 def replaceTextElements(node, iter_context):
103     """Replace text elements."""
104     document = node.ownerDocument
105
106     for nodename, attr, attrval, newval in iter_context['textnodes']:
107 ##         LOG(log_key, DEBUG, "nodename = %s" % repr(nodename))
108 ##         LOG(log_key, DEBUG, "attr = %s" % repr(attr))
109 ##         LOG(log_key, DEBUG, "attrval = %s" % repr(attrval))
110 ##         LOG(log_key, DEBUG, "newval = %s" % repr(newval))
111         if node.nodeName != nodename:
112             continue
113         if node.getAttribute(attr) != toUnicode(attrval):
114             continue
115
116         done = attrval + '_done'
117         if iter_context.get(done):
118             # remove spurious additional element
119             node.parentNode.removeChild(node)
120         else:
121             # replace existing
122             iter_context[done] = 1
123
124             # Remove all children (old text nodes, maybe none)
125             for n in list(node.childNodes):
126                 node.removeChild(n)
127
128             # Add new text child
129             node.appendChild(document.createTextNode(newval))
130
131 def replaceTextElementsByStyleName(node, iter_context):
132     """Replace text elements."""
133     document = node.ownerDocument
134
135     for nodename, attr, style_name, newval in iter_context['textnodes']:
136 ##         LOG(log_key, DEBUG, "nodename = %s" % repr(nodename))
137 ##         LOG(log_key, DEBUG, "attr = %s" % repr(attr))
138 ##         LOG(log_key, DEBUG, "style_name = %s" % repr(style_name))
139 ##         LOG(log_key, DEBUG, "newval = %s" % repr(newval))
140         style_name = toUnicode(style_name)
141         if node.nodeName != nodename:
142             continue
143         node_style_name = node.getAttribute(attr)
144         if not (node_style_name == style_name
145                 or nodeParentStyleNameMatchesStyleName(node, style_name)):
146             continue
147
148         done = style_name + '_done'
149         if iter_context.get(done):
150             # remove spurious additional element
151             node.parentNode.removeChild(node)
152         else:
153             # replace existing
154             iter_context[done] = 1
155
156             # Remove all children (old text nodes, maybe none)
157             for n in list(node.childNodes):
158                 node.removeChild(n)
159
160             # Add new text child
161             node.appendChild(document.createTextNode(newval))
162
163
164 def nodeParentStyleNameMatchesStyleName(node, style_name):
165     document = node.ownerDocument
166     node_style_name = node.getAttribute('text:style-name')
167     automaticStylesElt = document.getElementsByTagName('office:automatic-styles')[0]
168     styleElts = automaticStylesElt.getElementsByTagName('style:style')
169     for styleElt in styleElts:
170         automatic_style_name = styleElt.getAttribute('style:name')
171         parent_style_name = styleElt.getAttribute('style:parent-style-name')
172 ##         LOG(log_key, DEBUG, "node_style_name = %s" % repr(node_style_name))
173 ##         LOG(log_key, DEBUG, "automatic_style_name = %s" % repr(automatic_style_name))
174 ##         LOG(log_key, DEBUG, "parent_style_name = %s" % repr(parent_style_name))
175         if (node_style_name == automatic_style_name
176             and parent_style_name == style_name):
177 ##             LOG(log_key, DEBUG, "True for style_name = %s" % repr(style_name))
178             return True
179     return False
180
181
182 def replaceKeywords(node, iter_context):
183     if node.nodeName != 'text:p':
184         return
185     if node.getAttribute('text:style-name') != toUnicode('Keywords'):
186         return
187
188     document = node.ownerDocument
189
190     # remove existing
191     for n in list(node.childNodes):
192         node.removeChild(n)
193
194     keywords = iter_context['keywords']
195     nb = len(keywords)
196     n = 0
197     for k in keywords:
198         n += 1
199         span_node = document.createElement('text:span')
200         span_node.setAttribute('text:style-name', toUnicode('Keyword'))
201         span_node.appendChild(document.createTextNode(k))
202         node.appendChild(span_node)
203         if n != nb:
204             node.appendChild(document.createTextNode(', '))
205
206
207 def replaceContributors(contributors, document):
208 ##     LOG(log_key, DEBUG, "contributors = %s" % str(contributors))
209     officeBodyElt = document.getElementsByTagName('office:body')[0]
210     paraElts = officeBodyElt.getElementsByTagName('text:p')
211     for elt in paraElts:
212         if elt.getAttribute('text:style-name') == 'Othercredit':
213             officeBodyElt.removeChild(elt)
214         if (elt.getAttribute('text:style-name') == 'Heading'
215             and elt.hasChildNodes()
216             and elt.childNodes[0].nodeValue == 'Othercredit'):
217             officeBodyElt.removeChild(elt)
218
219     contributorsCount = len(contributors)
220     if contributorsCount == 0:
221         return
222
223     # Then let's add the new Othercredit elements after the Title, Author or
224     # Authorblurb elements if we find any.
225     officeBodyEltElts = officeBodyElt.childNodes
226     whereElt = None
227     for elt in officeBodyEltElts:
228         if elt.getAttribute('text:style-name') == 'Title':
229             whereElt = elt
230         if elt.getAttribute('text:style-name') == 'Author':
231             whereElt = elt
232         if elt.getAttribute('text:style-name') == 'Authorblurb':
233             whereElt = elt
234         if elt.getAttribute('text:style-name') == 'Bibliosource':
235             whereElt = elt
236         if elt.getAttribute('text:style-name') == 'Bibliorelation':
237             whereElt = elt
238             break
239
240     headingCreditElt = document.createElement('text:p')
241     headingCreditElt.setAttribute('text:style-name', 'Heading')
242     headingCreditElt.appendChild(document.createTextNode("Othercredit"))
243     if whereElt is None:
244         officeBodyElt.appendChild(headingCreditElt)
245     else:
246         # In insertBefore(Node newChild, Node refChild) if refChild is null,
247         # it inserts newChild at the end of the list of children.
248         officeBodyElt.insertBefore(headingCreditElt, whereElt.nextSibling)
249
250     # It is needed to reverse the list so that the insertion in the DOM keeps
251     # the contributors in the same order as they were specified in the
252     # OOo document.
253     contributors.reverse()
254     for k in contributors:
255         pElt = document.createElement('text:p')
256         pElt.setAttribute('text:style-name', 'Othercredit')
257         officeBodyElt.insertBefore(pElt, headingCreditElt.nextSibling)
258
259         # Here we only want to split the contributor's fullname in 2 parts
260         fullname = k.split(None, 1)
261 ##         LOG(log_key, DEBUG, "fullname = %s" % str(fullname))
262         if fullname:
263             if len(fullname) == 2:
264                 firstname = fullname[0]
265                 surname = fullname[1]
266             else:
267                 firstname = ""
268                 surname = fullname[0]
269
270 ##             LOG(log_key, DEBUG, "firstname = %s" % firstname)
271 ##             LOG(log_key, DEBUG, "surname = %s" % surname)
272             if firstname:
273                 spanElt = document.createElement('text:span')
274                 spanElt.setAttribute('text:style-name', 'Firstname')
275                 spanElt.appendChild(document.createTextNode(firstname))
276                 pElt.appendChild(spanElt)
277                 pElt.appendChild(document.createTextNode(' '))
278             if surname:
279                 spanElt = document.createElement('text:span')
280                 spanElt.setAttribute('text:style-name', 'Surname')
281                 spanElt.appendChild(document.createTextNode(surname))
282                 pElt.appendChild(spanElt)
283
284
285 def replaceBiblio(node, iter_context):
286     if node.nodeName != 'text:p':
287         return
288     if node.getAttribute('text:style-name') != 'Bibliorelation':
289         return
290
291     document = node.ownerDocument
292
293     # remove existing
294     for n in list(node.childNodes):
295         node.removeChild(n)
296
297     urls = iter_context['bibliorelation']
298     n = 0
299     for url in urls:
300         n += 1
301         span_node = document.createElement('text:span')
302         span_node.setAttribute('text:style-name', 'Text body') # XXX
303         span_node.appendChild(document.createTextNode(url))
304         node.appendChild(span_node)
305
306 def replaceCopyright(node, iter_context):
307     if node.nodeName != 'text:p':
308         return
309     if node.getAttribute('text:style-name') != 'Copyright':
310         return
311
312     document = node.ownerDocument
313
314     # remove existing
315     for n in list(node.childNodes):
316         node.removeChild(n)
317
318     copyright = iter_context['copyright']
319     year = iter_context['year']
320     holder = iter_context['holder']
321
322     if copyright:
323         if year or holder:
324             copyright += ' '
325         node.appendChild(document.createTextNode(copyright))
326     if year:
327         span_node = document.createElement('text:span')
328         span_node.setAttribute('text:style-name', 'Year')
329         span_node.appendChild(document.createTextNode(year))
330         node.appendChild(span_node)
331     if year and holder:
332         node.appendChild(document.createTextNode(' '))
333     if holder:
334         span_node = document.createElement('text:span')
335         span_node.setAttribute('text:style-name', 'Holder')
336         span_node.appendChild(document.createTextNode(holder))
337         node.appendChild(span_node)
338
339 def parseCopyright(s):
340     """Parse a copyright string.
341
342     Returns the copyright, year and holder.
343     """
344     m = re.match('([^\d]*)([-\d\s,]*)(.*)', s)
345     if m is None:
346         return s, '', ''
347
348     groups = m.groups()
349     if len(groups) != 3:
350         return s, '', ''
351
352     copyright, year, holder = groups
353     copyright = copyright.strip()
354     year = year.strip()
355     holder = holder.strip()
356     return copyright, year, holder
357
358
359 # factory_type_information is useless for a class that fits in
360 # the CPSDocument framework.
361 ## factory_type_information = (
362 ##     )
363
364 class OOoDocbookDocument(CPSDocument):
365     """A CPSDocument that holds many information and especially many metadata
366     about enclosed files.
367     """
368
369     # Too ease debugging
370     meta_type = 'OOoDocbookDocument'
371     portal_type = meta_type
372
373     security = ClassSecurityInfo()
374
375     #top_element_name = 'article'
376     top_element_name = 'book'
377     metainfo_element_name = top_element_name + 'info'
378
379     security.declareProtected(View, 'exportXmlDocbook')
380     def exportXmlDocbook(self):
381         """Export XML, in the Docbook XML format, for this document.
382         """
383         tmpDirName = tempfile.mktemp()
384         tmpDirPath = os.path.join(tempfile.tempdir, tmpDirName)
385         os.mkdir(tmpDirPath)
386
387         filePaths = []
388
389         # Regexp to replace "xxx.sxw" by "xxx.docb.xml"
390         dbFileName = re.sub('\..+?$', '.docb.xml', self.file.title)
391         dbFileName = re.sub('\s', '_', dbFileName)
392         dbFilePath = os.path.join(tmpDirPath, dbFileName)
393         LOG(log_key, DEBUG, "DocBook file path = %s" % dbFilePath)
394         filePaths.append(dbFilePath)
395         dbFile = open(dbFilePath, 'w+c')
396         dbFile.write(str(self.file_xml))
397         dbFile.flush()
398
399         imageFileNames = self.file_xml_subfiles
400         for imageFileName in imageFileNames:
401             imageFilePath = os.path.join(tmpDirPath, imageFileName)
402             LOG(log_key, DEBUG, "Image file path = %s" % imageFilePath)
403             filePaths.append(imageFilePath)
404             imageFile = open(imageFilePath, 'wb')
405             imageFile.write(str(getattr(self, imageFileName)))
406             imageFile.close()
407
408         # Regexp to replace "xxx.sxw" by "xxx.zip"
409         archiveFileName = re.sub('\..+?$', '.zip', self.file.title)
410         archiveFileName = re.sub('\s', '_', archiveFileName)
411         archiveFilePath = os.path.join(tmpDirPath, archiveFileName)
412         LOG(log_key, DEBUG, "Archive file path = %s" % archiveFilePath)
413         # Create a ZipFile object to write into
414         archiveFile = ZipFile(archiveFilePath, 'w', ZIP_DEFLATED)
415         archiveInternalSubDirName = dbFileName.split('.')[0]
416         for filePath in filePaths:
417             LOG(log_key, DEBUG, "adding file to archive = %s" % filePath)
418             if filePath != dbFilePath:
419                 filePathInTheArchive = os.path.join(archiveInternalSubDirName,
420                                                     'images', os.path.split(filePath)[1])
421             else:
422                 filePathInTheArchive = os.path.join(archiveInternalSubDirName,
423                                                     os.path.split(filePath)[1])
424
425             # The second parameter is to specify another path than the given
426             # file path. This has effect on the tree structures produced when
427             # the archived is uncompressed later on.
428             archiveFile.write(filePath, filePathInTheArchive)
429         archiveFile.close()
430         dbFile.close()
431
432         archiveFile = open(archiveFilePath, 'rb')
433         out = archiveFile.read()
434         archiveFile.close()
435
436         shutil.rmtree(tmpDirPath)
437
438         if self.REQUEST:
439             resp = self.REQUEST.RESPONSE
440             resp.setHeader('Content-Type', 'application/zip')
441             resp.setHeader('Content-Disposition', 'filename=' + archiveFileName)
442             # The "no-cache" headers hit a bug when using MSIE on SSL so we
443             # need to use the approach of using the Last-Modified header.
444             # http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/q316/4/31.asp&NoWebContent=1&NoWebContent=&NoWebContent=1
445             #resp.setHeader('Pragma', 'no-cache')
446             #resp.setHeader('Cache-Control', 'no-cache')
447             resp.setHeader('Last-Modified', rfc1123_date())
448
449         return out
450
451
452     security.declarePrivate('postCommitHook')
453     def postCommitHook(self, datamodel=None):
454         """This method is called just after the datamodel commit.
455
456         Here we have to update:
457
458         - the metadata from the document if a document was uploaded,
459
460         - the document from the metadata if some metadata was modified.
461
462         If both document and metadata have been modified, the document
463         takes precedence.
464         """
465         # Call base class
466         CPSDocument.inheritedAttribute('postCommitHook')(
467             self, datamodel=datamodel)
468
469 ##         LOG(log_key, DEBUG, 'postCommitHook: dm.dirty=%s' %
470 ##             datamodel.dirty.keys())
471
472         if datamodel.isDirty('file'):
473             self._updateMetadataFromDocument(datamodel)
474         else:
475             self._updateDocumentFromMetadata(datamodel)
476
477
478     def _updateMetadataFromDocument(self, datamodel):
479         """Update the object's metadata from the document."""
480 ##         LOG(log_key, DEBUG, "_updateMetadataFromDocument")
481
482         if not self.file_xml:
483 ##             LOG(log_key, PROBLEM,
484 ##                 "_updateMetadataFromDocument no file_xml -> no update")
485             return
486
487         file_xml_string = str(self.file_xml)
488         if not file_xml_string:
489 ##             LOG(log_key, PROBLEM,
490 ##                 "_updateMetadataFromDocument no file_xml_string -> no update")
491             return
492         doc = ElementTree(XML(file_xml_string))
493         rootElt = doc.getroot()
494         metainfoElt = xpath_find(rootElt, self.metainfo_element_name)
495
496         title = findFirstText(metainfoElt, 'title')
497         elts = xpath_findall(metainfoElt, 'abstract/para')
498         abstract = ''
499         delimiter = ''
500         for elt in elts:
501             if elt.text:
502                 abstract = '%s%s%s' % (abstract, delimiter, toLatin9(elt.text))
503                 delimiter = '\n\n'
504
505 ##         LOG(log_key, DEBUG, "_updateMetadataFromDocument abstract = %s" % abstract)
506
507         year = findText(metainfoElt, 'copyright/year')
508         holder = findText(metainfoElt, 'copyright/holder')
509         rights = " ".join(filter(None, [year, holder]))
510         if rights:
511             rights = "Copyright © " + rights
512
513         coverage = findFirstText(metainfoElt, 'bibliocoverage')
514 ##         LOG(log_key, DEBUG, "_updateMetadataFromDocument coverage = %s" % coverage)
515         source = findFirstText(metainfoElt, 'bibliosource')
516 ##         LOG(log_key, DEBUG, "_updateMetadataFromDocument source = %s" % source)
517         relation = ''
518         relationElts = xpath_findall(metainfoElt,
519                                      'bibliorelation/ulink')
520         for elt in relationElts:
521             if elt.get('url'):
522                 relation = elt.get('url')
523                 break
524
525         contributors = []
526         contributorsElts = xpath_findall(metainfoElt, 'othercredit')
527         for contributorsElt in contributorsElts:
528             firstname = findFirstText(contributorsElt, 'firstname')
529             surname = findFirstText(contributorsElt, 'surname')
530             contributor = " ".join(filter(None, [firstname, surname]))
531             if contributor:
532                 contributors.append(contributor)
533
534         keywordElts = xpath_findall(metainfoElt, 'keywordset/keyword')
535         keywords = [toLatin9(x.text) for x in keywordElts or ()]
536 ##         LOG(log_key, DEBUG, "_updateMetadataFromDocument keywords = %s" % ", ".join(keywords))
537
538         # Do not use unfilled data from an OOo document on to the
539         # portal. Unfilled data is marked up as <xxxxx>.
540         if (title is not None and title is not ''
541             and not title.startswith('<') and not title.endswith('>')):
542             self.setTitle(title)
543         if (abstract is not None
544             and not abstract.startswith('<') and not abstract.endswith('>')):
545             self.setDescription(abstract)
546         if (rights is not None
547             and not rights.startswith('<') and not rights.endswith('>')):
548             self.setRights(rights)
549         if (coverage is not None
550             and not coverage.startswith('<') and not coverage.endswith('>')):
551             self.setCoverage(coverage)
552         if (source is not None
553             and not source.startswith('<') and not source.endswith('>')):
554             self.setSource(source)
555         if (relation is not None
556             and not relation.startswith('<') and not relation.endswith('>')):
557             self.setRelation(relation)
558         self.setContributors(contributors)
559         self.Keywords = keywords
560
561         # Parse XML into DOM and modify it.
562         document = xml.dom.minidom.parseString(file_xml_string)
563         metainfoElt = document.getElementsByTagName(self.metainfo_element_name)[0]
564         paraElts = metainfoElt.getElementsByTagName('para')
565         for elt in paraElts:
566             if elt.getAttribute('role') == 'demandeur':
567                 demandeur = elt.childNodes[0].nodeValue
568                 self.Demandeur = demandeur
569             if elt.getAttribute('role') == 'rapporteur':
570                 rapporteur = elt.childNodes[0].nodeValue
571                 self.Rapporteur = rapporteur
572
573
574     def _updateDocumentFromMetadata(self, datamodel):
575         """Update the document from the object's metadata."""
576 ##         LOG(log_key, DEBUG, '_updateDocumentFromMetadata')
577
578         file = getattr(aq_base(self), 'file', None)
579         if file is None:
580             return
581
582         # These filenames always cleaned up
583         dirname = mktempdir()
584         all_filenames = {} # map of inzip-filename to fs-filename
585         zipfilename = None
586
587         try:
588             # Uncompress zipfile into a flat structure.
589             # Keep content_xml for later treatment
590             content_xml = None
591             try:
592                 z = ZipFile(StringIO(str(file)), 'r')
593             except BadZipfile:
594 ##                 LOG(log_key, DEBUG, "Attached file is not a zipfile")
595                 return
596             for zfilename in z.namelist():
597                 filename = zfilename.replace('/', '_')
598                 all_filenames[zfilename] = filename
599                 fstr = z.read(zfilename)
600                 if filename == 'content.xml':
601                     content_xml = fstr
602                 else:
603                     full_filename = os.path.join(dirname, filename)
604                     f = open(full_filename, 'w')
605                     f.write(fstr)
606                     f.close()
607                 del fstr
608             z.close()
609
610             if content_xml is None:
611 ##                 LOG(log_key, DEBUG, "Document does not have any content.xml")
612                 return
613
614             # Parse XML into DOM and modify it.
615             document = xml.dom.minidom.parseString(content_xml)
616
617             # OOo Version : 1.x or 2.x (odf)
618             rootNode = document.documentElement
619             if rootNode.attributes['xmlns:office'].value == 'http://openoffice.org/2000/office':
620                 oooVersion = 'ooo1'
621             elif rootNode.attributes['xmlns:office'].value == 'urn:oasis:names:tc:opendocument:xmlns:office:1.0':
622                 oooVersion = 'ooo2'
623
624             LOG(log_key, DEBUG, "oooversion = %s" % oooVersion)
625
626
627             self._updateDomFromMetadata(document)
628
629             # Write the final doc.
630             full_filename = os.path.join(dirname, 'content.xml')
631             f = open(full_filename, 'w')
632             xml.dom.ext.Print(document, f)
633             f.close()
634
635             # Recompress all into a zipfile.
636             if oooVersion == 'ooo1':
637                 ooo_suffix = '.sxw'
638                 ooo_content_type = 'application/vnd.sun.xml.writer'
639             else:
640                 ooo_suffix = '.odt'
641                 ooo_content_type = 'application/vnd.oasis.opendocument.text'
642
643             fd, zipfilename = tempfile.mkstemp(suffix=ooo_suffix)
644             os.close(fd)
645             os.unlink(zipfilename)
646             z = ZipFile(zipfilename, 'w', ZIP_DEFLATED)
647             for zfilename, filename in all_filenames.items():
648                 full_filename = os.path.join(dirname, filename)
649                 z.write(full_filename, zfilename)
650             z.close()
651
652             # Now read the zipfile into memory
653             f = open(zipfilename, 'rb')
654             file = File(file.getId(), file.title, f)
655             file.content_type = ooo_content_type
656             f.close()
657
658             # Set file back in datamodel and recommit
659             # (this recomputes dependent fields).
660             datamodel['file'] = file
661             datamodel._commitData()
662
663         finally:
664             # Cleanup temp files
665             for zfilename, filename in all_filenames.items():
666                 full_filename = os.path.join(dirname, filename)
667                 try:
668                     os.unlink(full_filename)
669                 except OSError:
670                     pass
671             try:
672                 os.rmdir(dirname)
673             except OSError:
674                 pass
675             if zipfilename:
676                 try:
677                     os.unlink(zipfilename)
678                 except OSError:
679                     pass
680
681         return
682
683
684     def _updateDomFromMetadata(self, document):
685         """Update a DOM tree from the current metadata."""
686         iter_context = {
687             'textnodes': (
688                 ('text:p', 'text:style-name', 'Title',
689                  toUnicode(self.Title())),
690                 ('text:p', 'text:style-name', 'Abstract',
691                  toUnicode(self.Description())),
692                 ('text:p', 'text:style-name', 'Bibliocoverage',
693                  toUnicode(self.Coverage())),
694                 ('text:p', 'text:style-name', 'Bibliosource',
695                  toUnicode(self.Source())),
696                 ),
697             }
698         #iterDoc(document, replaceTextElements, iter_context)
699         iterDoc(document, replaceTextElementsByStyleName, iter_context)
700
701         iter_context = {
702             'keywords': [toUnicode(k) for k in self.Keywords],
703             }
704         iterDoc(document, replaceKeywords, iter_context)
705
706         iter_context = {
707             'bibliorelation': [toUnicode(self.Relation())],
708             }
709         iterDoc(document, replaceBiblio, iter_context)
710
711         copyright, year, holder = parseCopyright(toUnicode(self.Rights()))
712         iter_context = {
713             'copyright': copyright,
714             'year': year,
715             'holder': holder,
716             }
717         iterDoc(document, replaceCopyright, iter_context)
718
719         replaceContributors([toUnicode(k) for k in self.Contributors()], document)
720
721
722 InitializeClass(OOoDocbookDocument)
723
724
725 def addOOoDocbookDocumentInstance(container, id, REQUEST=None, **kw):
726     """Factory method
727     """
728
729     instance = OOoDocbookDocument(id, **kw)
730     container._setObject(id, instance)
731
732     # It's mandatory then after to get the object through its parent, for the
733     # object to have a reference on its parent. Having the object know about
734     # its parent is mandatory if one wants to be able to call some methods like
735     # manage_addProduct() on it.
736     #object = getattr(container, id)
737
738     if REQUEST:
739         object = container._getOb(id)
740         REQUEST.RESPONSE.redirect(object.absolute_url() + '/manage_main')
Note: See TracBrowser for help on using the browser.