1 | import logging, types |
---|
2 | import transaction |
---|
3 | from zope.interface import implements |
---|
4 | from zope.component import getMultiAdapter |
---|
5 | from zope.component import queryMultiAdapter |
---|
6 | |
---|
7 | from Missing import MV |
---|
8 | from Acquisition import aq_inner |
---|
9 | from Acquisition import aq_parent |
---|
10 | |
---|
11 | from Products.CMFCore.utils import getToolByName |
---|
12 | from Products.ZCatalog.Catalog import safe_callable |
---|
13 | |
---|
14 | |
---|
15 | try: |
---|
16 | from plone.indexer.interfaces import IIndexableObject |
---|
17 | except ImportError: |
---|
18 | class IIndexableObject:pass |
---|
19 | from plone.app.content.interfaces import IIndexableObjectWrapper \ |
---|
20 | as _old_IIndexableObjectWrapper |
---|
21 | from plone.app.content.interfaces import IIndexableObjectWrapper |
---|
22 | |
---|
23 | register_bbb_indexers = lambda:None |
---|
24 | |
---|
25 | IS_NEW = False |
---|
26 | else: |
---|
27 | from Products.CMFPlone.CatalogTool import register_bbb_indexers |
---|
28 | from Products.CMFPlone.CatalogTool import _old_IIndexableObjectWrapper |
---|
29 | |
---|
30 | IS_NEW = True |
---|
31 | |
---|
32 | |
---|
33 | from quintagroup.catalogupdater.interfaces import ICatalogUpdater |
---|
34 | |
---|
35 | LOG = logging.getLogger('quintagroup.catalogupdater') |
---|
36 | |
---|
37 | |
---|
38 | class CatalogUpdaterUtility(object): |
---|
39 | |
---|
40 | implements(ICatalogUpdater) |
---|
41 | |
---|
42 | def validate(self, cat, cols): |
---|
43 | # Validate catalog and column name |
---|
44 | AVAIL_COLTYPES = list(types.StringTypes) + [types.ListType, types.TupleType] |
---|
45 | |
---|
46 | _cat = getattr(cat, '_catalog', None) |
---|
47 | if _cat is None: |
---|
48 | raise AttributeError("%s - is not ZCatalog based catalog" % cat) |
---|
49 | |
---|
50 | if not type(cols) in AVAIL_COLTYPES: |
---|
51 | raise TypeError("'columns' parameter must be one of the following " \ |
---|
52 | "types: %s" % AVAIL_COLTYPES) |
---|
53 | # Normalize columns |
---|
54 | if type(cols) in types.StringTypes: |
---|
55 | cols = [cols,] |
---|
56 | # Check is every column present in the catalog |
---|
57 | for col in cols: |
---|
58 | if not _cat.schema.has_key(col): |
---|
59 | raise AttributeError("'%s' - not presented column in %s catalog " % (col, cat)) |
---|
60 | |
---|
61 | return _cat, cols |
---|
62 | |
---|
63 | |
---|
64 | def getWrappedObjectNew(self, obj, portal, catalog): |
---|
65 | # Returned wrapped 'obj' object with IIndexable wrapper |
---|
66 | w = obj |
---|
67 | if not IIndexableObject.providedBy(obj): |
---|
68 | # BBB: Compatibility wrapper lookup. Should be removed in Plone 4. |
---|
69 | register_bbb_indexers() |
---|
70 | wrapper = queryMultiAdapter((obj, portal), _old_IIndexableObjectWrapper) |
---|
71 | if wrapper is not None: |
---|
72 | w = wrapper |
---|
73 | else: |
---|
74 | # This is the CMF 2.2 compatible approach, which should be used going forward |
---|
75 | wrapper = queryMultiAdapter((obj, catalog), IIndexableObject) |
---|
76 | if wrapper is not None: |
---|
77 | w = wrapper |
---|
78 | return w |
---|
79 | |
---|
80 | |
---|
81 | def getWrappedObjectOld(self, obj, portal, catalog): |
---|
82 | # Returned wrapped 'obj' object with IIndexable wrapper |
---|
83 | wf = getattr(self, 'portal_workflow', None) |
---|
84 | # A comment for all the frustrated developers which aren't able to pin |
---|
85 | # point the code which adds the review_state to the catalog. :) |
---|
86 | # The review_state var and some other workflow vars are added to the |
---|
87 | # indexable object wrapper throught the code in the following lines |
---|
88 | if wf is not None: |
---|
89 | vars = wf.getCatalogVariablesFor(obj) |
---|
90 | else: |
---|
91 | vars = {} |
---|
92 | |
---|
93 | w = getMultiAdapter((obj, portal), _old_IIndexableObjectWrapper) |
---|
94 | w.update(vars) |
---|
95 | |
---|
96 | return w |
---|
97 | |
---|
98 | |
---|
99 | def updateMetadata4All(self, catalog, columns): |
---|
100 | """ Look into appropriate method of ICatalogUpdate interface |
---|
101 | """ |
---|
102 | |
---|
103 | _catalog, columns = self.validate(catalog, columns) |
---|
104 | |
---|
105 | portal = getToolByName(catalog, 'portal_url').getPortalObject() |
---|
106 | root = aq_parent(portal) |
---|
107 | |
---|
108 | data = _catalog.data |
---|
109 | schema = _catalog.schema |
---|
110 | paths = _catalog.paths |
---|
111 | getWrappedObject = IS_NEW and self.getWrappedObjectNew or self.getWrappedObjectOld |
---|
112 | # For subtransaction support |
---|
113 | threshold = getattr(catalog, 'threshold', 10000) |
---|
114 | _v_total = 0 |
---|
115 | _v_transaction = None |
---|
116 | |
---|
117 | # For each catalog record update metadata |
---|
118 | for rid, md in data.items(): |
---|
119 | # get an object |
---|
120 | obj_uid = paths[rid] |
---|
121 | try: |
---|
122 | obj = root.unrestrictedTraverse(obj_uid) |
---|
123 | obj = getWrappedObject(obj, portal, catalog) |
---|
124 | except: |
---|
125 | LOG.error('updateMetadata4All could not resolve ' |
---|
126 | 'an object from the uid %r.' % obj_uid) |
---|
127 | continue |
---|
128 | |
---|
129 | mdlist = list(md) |
---|
130 | for column in columns: |
---|
131 | # calculate the column value |
---|
132 | attr=getattr(obj, column, MV) |
---|
133 | if(attr is not MV and safe_callable(attr)): attr=attr() |
---|
134 | # Update metadata value |
---|
135 | indx = schema[column] |
---|
136 | mdlist[indx] = attr |
---|
137 | |
---|
138 | # Update catalog record |
---|
139 | data[rid] = tuple(mdlist) |
---|
140 | |
---|
141 | # Steeled from ZCatalog |
---|
142 | if threshold is not None: |
---|
143 | # figure out whether or not to commit a subtransaction. |
---|
144 | t = id(transaction.get()) |
---|
145 | if t != _v_transaction: |
---|
146 | _v_total = 0 |
---|
147 | _v_transaction = t |
---|
148 | _v_total = _v_total + 1 |
---|
149 | if _v_total > threshold: |
---|
150 | transaction.savepoint(optimistic=True) |
---|
151 | catalog._p_jar.cacheGC() |
---|
152 | _v_total = 0 |
---|
153 | LOG.info('commiting subtransaction') |
---|
154 | |
---|