source: products/quintagroup.transmogrifier/branches/plone-2.1/quintagroup.transmogrifier/quintagroup/transmogrifier/binary.py @ 1386

Last change on this file since 1386 was 1386, checked in by piv, 14 years ago

fix binary fields export issue

File size: 6.3 KB
Line 
1import traceback
2from xml.dom import minidom
3
4from zope.interface import classProvides, implements
5
6from ZODB.POSException import ConflictError
7
8from plone.app.transmogrifier.interfaces import IBaseObject
9
10from collective.transmogrifier.interfaces import ISection, ISectionBlueprint
11from collective.transmogrifier.utils import defaultMatcher
12
13class FileExporterSection(object):
14    classProvides(ISectionBlueprint)
15    implements(ISection)
16
17    def __init__(self, transmogrifier, name, options, previous):
18        self.previous = previous
19        self.context = transmogrifier.context
20
21        self.pathkey = defaultMatcher(options, 'path-key', name, 'path')
22        self.fileskey = options.get('files-key', '_files').strip()
23        # only this section can add 'excluded_field' for marshalling
24        #self.excludekey = defaultMatcher(options, 'exclude-key', name, 'excluded_fields')
25        self.excludekey = options.get('exclude-key', '_excluded_fields').strip()
26
27    def __iter__(self):
28        for item in self.previous:
29            pathkey = self.pathkey(*item.keys())[0]
30
31            if not pathkey:
32                yield item; continue
33
34            path = item[pathkey]
35            obj = self.context.unrestrictedTraverse(path, None)
36            if obj is None:         # path doesn't exist
37                yield item; continue
38
39            if IBaseObject.providedBy(obj):
40                schema = obj.Schema()
41                binary_fields = {}
42                binary_field_names = []
43                for field in schema.keys():
44                    if obj.isBinary(field):
45                        fname, ct, data = self.extractFile(obj, field)
46                        binary_field_names.append(field)
47                        if data == '':
48                            # empty file fields have no data and we skip them
49                            continue
50                        elif fname == '':
51                            fname = 'field-%s' % field
52
53                        binary_fields[field] = dict(filename=fname, mimetype=ct)
54                        files = item.setdefault(self.fileskey, {})
55                        #key = "field-%s" % field
56                        files[fname] = {
57                            # now we export FileField as file with it's original name,
58                            # but it may cause name collapse
59                            'name': fname,
60                            'data': data,
61                            'content_type': ct,
62                        }
63                if binary_fields:
64                    files['file-fields'] = {
65                        'name': '.file-fields.xml',
66                        'data': self.createManifest(binary_fields),
67                    }
68                if binary_field_names:
69                    item[self.excludekey] = binary_field_names
70
71            yield item
72
73    def extractFile(self, obj, field):
74        """ Return tuple of (filename, content_type, data)
75        """
76        field = obj.getField(field)
77        base_unit = field.getBaseUnit(obj, full=True)
78        fname = base_unit.getFilename() 
79        ct = base_unit.getContentType()
80        value = base_unit.getRaw()
81
82        return fname, ct, value
83
84    def createManifest(self, binary_fields):
85        manifest = '<?xml version="1.0" ?>\n<manifest>\n'
86        for field, info in binary_fields.items():
87            manifest += '  <field name="%s">\n' % field
88            manifest += '    <filename>%s</filename>\n' % info['filename']
89            manifest += '    <mimetype>%s</mimetype>\n' % info['mimetype']
90            manifest += '  </field>\n'
91        manifest += "</manifest>\n"
92        return manifest
93
94class FileImporterSection(object):
95    classProvides(ISectionBlueprint)
96    implements(ISection)
97
98    def __init__(self, transmogrifier, name, options, previous):
99        self.previous = previous
100        self.context = transmogrifier.context
101
102        self.pathkey = defaultMatcher(options, 'path-key', name, 'path')
103        self.fileskey = defaultMatcher(options, 'files-key', name, 'files')
104        self.contextkey = defaultMatcher(options, 'context-key', name, 'import_context')
105
106    def __iter__(self):
107        for item in self.previous:
108            pathkey = self.pathkey(*item.keys())[0]
109            fileskey = self.fileskey(*item.keys())[0]
110            contextkey = self.contextkey(*item.keys())[0]
111
112            if not (pathkey and fileskey):
113                yield item; continue
114            if 'file-fields' not in item[fileskey]:
115                yield item; continue
116
117            path = item[pathkey]
118            obj = self.context.unrestrictedTraverse(path, None)
119            if obj is None:         # path doesn't exist
120                yield item; continue
121
122            if IBaseObject.providedBy(obj):
123                try:
124                    manifest = item[fileskey]['file-fields']['data']
125                    for field, info in self.parseManifest(manifest).items():
126                        fname = info['filename']
127                        ct = info['mimetype']
128                        if fname in item[fileskey]:
129                            data = item[fileskey][fname]['data']
130                        elif contextkey:
131                            data = context.readDataFile("%s/%s" % (path, fname))
132                            if data is None:
133                                continue
134                        mutator = obj.getField(field).getMutator(obj)
135                        mutator(data, filename=fname, mimetype=ct)
136                except ConflictError:
137                    raise
138                except Exception, e:
139                    print "Exception in fileimporter section:"
140                    print '-'*60
141                    traceback.print_exc()
142                    print '-'*60
143
144            yield item
145
146    def parseManifest(self, manifest):
147        doc = minidom.parseString(manifest)
148        fields = {}
149        for elem in doc.getElementsByTagName('field'):
150            field = fields.setdefault(str(elem.getAttribute('name')), {})
151            for child in elem.childNodes:
152                if child.nodeType != child.ELEMENT_NODE:
153                    continue
154                if child.tagName == u'filename':
155                    field['filename'] = child.firstChild.nodeValue.strip().encode('utf-8')
156                elif child.tagName == u'mimetype':
157                    field['mimetype'] = str(child.firstChild.nodeValue.strip())
158
159        return fields
Note: See TracBrowser for help on using the repository browser.