source: products/quintagroup.transmogrifier/branches/plone-2.1/quintagroup.transmogrifier/quintagroup/transmogrifier/catalogsource.py @ 436

Last change on this file since 436 was 436, checked in by crchemist, 16 years ago

Fix an error in PingTool?.py

File size: 5.0 KB
Line 
1from zope.interface import classProvides, implements
2from zope.app.annotation.interfaces import IAnnotations
3
4from collective.transmogrifier.interfaces import ISection, ISectionBlueprint
5
6from Products.CMFCore import utils
7
8from quintagroup.transmogrifier.logger import VALIDATIONKEY
9
10class CatalogSourceSection(object):
11    classProvides(ISectionBlueprint)
12    implements(ISection)
13
14    def __init__(self, transmogrifier, name, options, previous):
15        self.previous = previous
16        self.context = transmogrifier.context
17
18        # next is for communication with 'logger' section
19        self.anno = IAnnotations(transmogrifier)
20        self.storage = self.anno.setdefault(VALIDATIONKEY, [])
21
22        self.pathkey = options.pop('path-key', '_path')
23        self.entrieskey = options.pop('entries-key', '_entries')
24
25        # remove 'blueprint' option - it cannot be a query
26        options.pop('blueprint')
27
28        self.query = {}
29        for k, v in options.items():
30            for p in v.split(';'):
31                params = p.split('=', 1)
32                if len(params) == 1:
33                    self.query[k] = p.strip()
34                else :
35                    q = self.query.setdefault(k, {})
36                    q[params[0].strip()] = params[1].strip()
37
38        self.catalog = utils.getToolByName(self.context, 'portal_catalog')
39
40    def __iter__(self):
41        for item in self.previous:
42            yield item
43
44        exported = []
45
46        results = list(self.catalog(**self.query))
47        results.sort(key=lambda x: x.getPath())
48        for brain in results:
49            # discussion items are indexed and they must be replaced to
50            # content objects to which they correspond
51            # we need to skip them
52            if brain.portal_type == 'Discussion Item':
53                path =  '/'.join(brain.getPath().split('/')[:-2])
54                cp, id_ = path.rsplit('/', 1)
55                brain = self.catalog(path=cp, id=id_)[0]
56            else:
57                path = brain.getPath()
58
59            # folderish objects are tried to export twice:
60            # when their contained items are exported and when they are
61            # returned in catalog search results
62            if path in exported:
63                continue
64            exported.append(path)
65
66            # export also all parents of current object
67            containers = []
68            container_path = path.rsplit('/', 1)[0]
69            while container_path:
70                if container_path in exported:
71                    container_path = container_path.rsplit('/', 1)[0]
72                    continue
73                contained = self.getContained(container_path)
74                if contained:
75                    exported.append(container_path)
76                    containers.append({
77                        self.pathkey: '/'.join(container_path.split('/')[2:]),
78                        self.entrieskey: contained,
79                    })
80                container_path = container_path.rsplit('/', 1)[0]
81            containers.reverse()
82            # order metter for us
83            for i in containers:
84                self.storage.append(i[self.pathkey])
85                yield i
86
87            item = {
88                self.pathkey: '/'.join(path.split('/')[2:]),
89            }
90            if brain.is_folderish:
91                contained = self.getContained(path)
92                if contained:
93                    item[self.entrieskey] = contained
94
95            self.storage.append(item[self.pathkey])
96            yield item
97
98        # cleanup
99        if VALIDATIONKEY in self.anno:
100            del self.anno[VALIDATIONKEY]
101
102    def getContained(self, path):
103        """ Return list of (object_id, portal_type) for objects that are returned by catalog
104            and contained in folder with given 'path'.
105        """
106        results = []
107        seen = []
108        raw_results = self.catalog(path=path, **self.query)
109        for brain in raw_results:
110            current = brain.getPath()
111            relative = current[len(path):]
112            relative = relative.strip('/')
113            if not relative:
114                # it's object with path that was given in catalog query
115                continue
116            elif '/' in relative:
117                # object stored in subfolders, we need append to results their parent folder
118                parent_path = '/'.join([path, relative.split('/', 1)[0]])
119                if parent_path not in seen:                   
120                    res = self.catalog(path=path) #, meta_type='Folder')
121                    for i in res:
122                        if i.getPath() == parent_path:
123                            results.append(i)
124                            seen.append(parent_path)
125                            break
126            elif current not in seen:
127                # object is directly stored in folder, that has path given in query
128                seen.append(current)
129                results.append(brain)
130        contained = [(i.getId, str(i.portal_type)) for i in results]
131        return tuple(contained)
Note: See TracBrowser for help on using the repository browser.