source: products/quintagroup.transmogrifier/branches/plone-2.1/quintagroup.transmogrifier/quintagroup/transmogrifier/comments.py @ 1413

Last change on this file since 1413 was 282, checked in by fenix, 18 years ago

Tagging 0.4.4 version of product

File size: 6.4 KB
Line 
1from xml.dom import minidom
2
3from zope.interface import classProvides, implements
4
5from Acquisition import aq_base
6from Products.CMFCore import utils
7from Products.CMFDefault import DiscussionItem
8from Products.CMFDefault.exceptions import DiscussionNotAllowed
9
10from collective.transmogrifier.interfaces import ISection, ISectionBlueprint
11from collective.transmogrifier.utils import defaultMatcher
12
13class CommentsExporterSection(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
24        self.doc = minidom.Document()
25
26    def __iter__(self):
27        for item in self.previous:
28            pathkey = self.pathkey(*item.keys())[0]
29
30            if not pathkey:
31                yield item; continue
32
33            path = item[pathkey]
34            obj = self.context.unrestrictedTraverse(path, None)
35            if obj is None:         # path doesn't exist
36                yield item; continue
37
38            # check if object has comments
39            discussion_container = getattr(aq_base(obj), 'talkback', None)
40            if discussion_container is not None:
41                data = self.extractComments(discussion_container)
42                if data:
43                    files = item.setdefault(self.fileskey, {})
44                    item[self.fileskey]['comments'] = {
45                        'name': '.comments.xml',
46                        'data': data,
47                    }
48
49            yield item
50
51    def extractComments(self, container):
52        doc = self.doc
53
54        items = container.objectItems()
55        if not items:
56            return None
57
58        root = doc.createElement('discussion')
59        doc.appendChild(root)
60        for item_id, item in items:
61            hdrlist = item.getMetadataHeaders()
62            # get creator (it is displayed in "Posted by")
63            hdrlist.append(('Creator', item.Creator()))
64            # get modification date (also is displayed)
65            hdrlist.append(('Modification_date', item.ModificationDate()))
66            # get relation
67            hdrlist.append(('In_reply_to', str(item.in_reply_to)))
68            # get comment text
69            hdrlist.append(('Text', item.text))
70
71            item_elem = doc.createElement('item')
72            attr = doc.createAttribute('id')
73            attr.value = item_id
74            item_elem.setAttributeNode(attr)
75
76            for k, v in hdrlist:
77                field = doc.createElement('field')
78                attr = doc.createAttribute('name')
79                attr.value = k
80                field.setAttributeNode(attr)
81                text = doc.createTextNode(v)
82                field.appendChild(text)
83                item_elem.appendChild(field)
84
85            root.appendChild(item_elem)
86
87        # all comments are strings encoded in 'utf-8' and they will properly
88        # saved in xml file, but if we explicitly give 'utf-8' encoding
89        # UnicodeDecodeError will be raised when they have non-ascii chars
90        data = self.doc.toprettyxml(indent='  ') #, encoding='utf-8')
91
92        self.doc.unlink()
93        return data
94
95class CommentsImporterSection(object):
96    classProvides(ISectionBlueprint)
97    implements(ISection)
98
99    def __init__(self, transmogrifier, name, options, previous):
100        self.previous = previous
101        self.context = transmogrifier.context
102
103        self.pathkey = defaultMatcher(options, 'path-key', name, 'path')
104        self.fileskey = defaultMatcher(options, 'files-key', name, 'files')
105
106        self.dtool = utils.getToolByName(self.context, 'portal_discussion')
107
108    def __iter__(self):
109        for item in self.previous:
110            pathkey = self.pathkey(*item.keys())[0]
111            fileskey = self.fileskey(*item.keys())[0]
112
113            if not (pathkey and fileskey):
114                yield item; continue
115
116            if 'comments' not in item[fileskey]:
117                yield item; continue
118
119            path = item[pathkey]
120            obj = self.context.unrestrictedTraverse(path, None)
121            if obj is None:         # path doesn't exist
122                yield item; continue
123
124            # allow discussion if it wasn't allowed (because we have comments)
125            try:
126                discussion_container = self.dtool.getDiscussionFor(obj)
127            except DiscussionNotAllowed:
128                obj.allow_discussion = True
129                discussion_container = self.dtool.getDiscussionFor(obj)
130
131            data = item[fileskey]['comments']['data']
132            discussion_container._container.clear()
133            for id_, props in self.parseXML(data).items():
134                comment = DiscussionItem.DiscussionItem(id_)
135                discussion_container._container[id_] = comment
136                comment = comment.__of__(discussion_container)
137                self.updateDiscussionItem(comment, props)
138
139            yield item
140
141    def parseXML(self, data):
142        doc = minidom.parseString(data)
143        root = doc.documentElement
144
145        items = {}
146        for child in root.childNodes:
147            if child.nodeName != 'item':
148                continue
149            id_ = str(child.getAttribute('id'))
150            item = items[id_] = {}
151            for field in child.childNodes:
152                if field.nodeName != 'field':
153                    continue
154                name = field.getAttribute('name')
155                # this will be unicode string, encode it?
156                value = ''
157                for node in field.childNodes:
158                    if node.nodeName != '#text':
159                        continue
160                    lines = [line.lstrip() for line in node.nodeValue.splitlines()]
161                    value += '\n'.join(lines)
162                item[name] = value.strip()
163
164        return items
165
166    def updateDiscussionItem(self, item, props):
167        in_reply_to = props['In_reply_to']
168        # if 'In_reply_to' field is string "None" we need to set attribute to None
169        if in_reply_to == 'None':
170            item.in_reply_to = None
171        else:
172            item.in_reply_to = in_reply_to
173
174        item.addCreator(props['Creator'])
175        item.setFormat('text/plain')
176        item.setMetadata(props)
177        item._edit(text=props['Text'])
178        item.setModificationDate(props['Modification_date'])
179        item.indexObject()
Note: See TracBrowser for help on using the repository browser.