source: products/quintagroup.analytics/trunk/quintagroup/analytics/browser/views.py @ 3029

Last change on this file since 3029 was 3029, checked in by fenix, 13 years ago

added quick validation fix for forms, added MANIFEST.in file

  • Property svn:eol-style set to native
File size: 18.4 KB
Line 
1from Acquisition import aq_base
2from zope.component import getUtility, getMultiAdapter, queryMultiAdapter
3
4from OFS.interfaces import IPropertyManager
5from Products.Five.browser import BrowserView
6from Products.CMFCore.utils import getToolByName
7from Products.CMFCore.interfaces import IFolderish
8from Products.Archetypes.interfaces import IBaseFolder
9from plone.portlets.interfaces import IPortletManager
10from plone.portlets.interfaces import IPortletAssignmentMapping
11from plone.portlets.interfaces import ILocalPortletAssignmentManager
12try:
13    from plone.portlets.interfaces import IPortletAssignmentSettings
14except ImportError:
15    "Before plon4 we don't have an annotation storage for settings."
16    IPortletAssignmentSettings = lambda assignment:{}
17
18from GChartWrapper import VerticalBarStack
19
20from quintagroup.analytics.config import COLORS, OTHER_TYPES, NO_WF_BIND
21
22class OwnershipByType(BrowserView):
23    MAX = 10
24    def __init__(self, context, request):
25        self.context = context
26        self.request = request
27        self.cat = getToolByName(self.context, 'portal_catalog')
28        self.users = None
29        self.total = None
30        self.types = None
31        self.data = {}
32
33    def getUsers(self):
34        if self.users is None:
35            index = self.cat._catalog.getIndex('Creator')
36            data = {}
37            for k in index._index.keys():
38                haslen = hasattr(index._index[k], '__len__')
39                if haslen:
40                    data[k] = len(index._index[k])
41                else:
42                    data[k] = 1
43            data = data.items()
44            data.sort(lambda a, b: a[1] - b[1])
45            data.reverse()
46            data = data[:self.MAX]
47            self.users = [i[0] for i in data]
48            self.total = [i[1] for i in data]
49        return self.users
50
51    def getTypes(self, all=False):
52        if self.types is None:
53            index = self.cat._catalog.getIndex('portal_type')
54            data = {}
55            for k in index._index.keys():
56                if not k:
57                    continue
58                haslen = hasattr(index._index[k], '__len__')
59                if haslen:
60                    data[k] = len(index._index[k])
61                else:
62                    data[k] = 1
63            data = data.items()
64            data.sort(lambda a, b: a[1] - b[1])
65            data.reverse()
66            self.types = [i[0] for i in data]
67        return all and self.types or self.types[:self.MAX]
68
69    def getContent(self, type_):
70        if type_ not in self.data:
71            data = self.data[type_] = []
72            for user in self.getUsers():
73                res = self.cat(portal_type=type_, Creator=user)
74                l = len(res)
75                if l == 0:
76                    data.append(0)
77                else:
78                    data.append(l)
79        return self.data[type_]
80
81    def getTotal(self):
82        return self.total
83
84    def getChart(self):
85        data = []
86        types = self.getTypes()
87        for type_ in types:
88            data.append(self.getContent(type_))
89        other = [self.getContent(t) for t in self.getTypes(all=True)[self.MAX:]]
90        if other:
91            data.append([sum(l) for l in zip(*other)])
92        max_value = max(self.getTotal())
93        chart = VerticalBarStack(data, encoding='text')
94        types = other and types+OTHER_TYPES or types
95        chart.title('Content ownership by type').legend(*(types))
96        chart.bar('a', 10, 0).legend_pos("b")
97        chart.color(*COLORS)
98        chart.size(800, 375).scale(0,max_value).axes('xy').label(*self.users)
99        chart.axes.type("y")
100        chart.axes.range(0,0,max_value)
101        return chart.img()
102
103
104class OwnershipByState(BrowserView):
105    MAX = 10
106    def __init__(self, context, request):
107        self.context = context
108        self.request = request
109        self.cat = getToolByName(self.context, 'portal_catalog')
110        self.users = None
111        self.states = None
112        self.total = None
113        self.data = {}
114
115    def getUsers(self):
116        if self.users is None:
117            index = self.cat._catalog.getIndex('Creator')
118            data = {}
119            for k in index._index.keys():
120                haslen = hasattr(index._index[k], '__len__')
121                if haslen:
122                    data[k] = len(index._index[k])
123                else:
124                    data[k] = 1
125            data = data.items()
126            data.sort(lambda a, b: a[1] - b[1])
127            data.reverse()
128            data = data[:self.MAX]
129            self.users = [i[0] for i in data]
130            self.total = [i[1] for i in data]
131        return self.users
132
133    def getStates(self):
134        if self.states is None:
135            index = self.cat._catalog.getIndex('review_state')
136            data = {}
137            for k in index._index.keys():
138                haslen = hasattr(index._index[k], '__len__')
139                if haslen:
140                    data[k] = len(index._index[k])
141                else:
142                    data[k] = 1
143            data = data.items()
144            data.sort(lambda a, b: a[1] - b[1])
145            data.reverse()
146            self.states = [i[0] for i in data]
147        return self.states
148
149    def getContent(self, type_):
150        if type_ not in self.data:
151            if NO_WF_BIND not in self.data:
152                self.data[NO_WF_BIND] = self.getTotal()
153            data = self.data[type_] = []
154            for user in self.getUsers():
155                res = self.cat(review_state=type_, Creator=user)
156                l = len(res)
157                if l == 0:
158                    data.append(0)
159                else:
160                    data.append(l)
161            if len(data) > 0:
162                self.data[NO_WF_BIND] = map(lambda t,d:t-d, self.data[NO_WF_BIND], data)
163        return self.data[type_]
164
165    def getNoWFContentTitle(self):
166        return NO_WF_BIND
167
168    def getNoWFContent(self):
169        return self.getContent(NO_WF_BIND)
170
171    def getTotal(self):
172        if self.total is None:
173            self.getUsers()
174        return self.total
175
176    def getChart(self):
177        data = []
178        for state in self.getStates():
179            data.append(self.getContent(state))
180        data.append(self.getNoWFContent())
181        max_value = max(self.getTotal())
182        chart = VerticalBarStack(data, encoding='text')
183        chart.title('Content ownership by state').legend(*self.states+[NO_WF_BIND])
184        chart.bar('a', 10, 0).legend_pos("b")
185        chart.color(*COLORS)
186        chart.size(800, 375).scale(0,max_value).axes('xy').label(*self.users)
187        chart.axes.type("y")
188        chart.axes.range(0,0,max_value)
189        return chart.img()
190
191
192class TypeByState(BrowserView):
193    MAX = 10
194    def __init__(self, context, request):
195        self.context = context
196        self.request = request
197        self.cat = getToolByName(self.context, 'portal_catalog')
198        self.types = None
199        self.states = None
200        self.total = None
201        self.data = {}
202
203    def getTypes(self):
204        if self.types is None:
205            index = self.cat._catalog.getIndex('portal_type')
206            data = {}
207            for k in index._index.keys():
208                if not k:
209                    continue
210                haslen = hasattr(index._index[k], '__len__')
211                if haslen:
212                    data[k] = len(index._index[k])
213                else:
214                    data[k] = 1
215            data = data.items()
216            data.sort(lambda a, b: a[1] - b[1])
217            data.reverse()
218            self.types = [i[0] for i in data[:self.MAX]]
219            self.total = [i[1] for i in data[:self.MAX]]
220        return self.types
221
222    def getStates(self):
223        if self.states is None:
224            index = self.cat._catalog.getIndex('review_state')
225            data = {}
226            for k in index._index.keys():
227                haslen = hasattr(index._index[k], '__len__')
228                if haslen:
229                    data[k] = len(index._index[k])
230                else:
231                    data[k] = 1
232            data = data.items()
233            data.sort(lambda a, b: a[1] - b[1])
234            data.reverse()
235            self.states = [i[0] for i in data]
236        return self.states
237
238    def getContent(self, state):
239        if state not in self.data:
240            if NO_WF_BIND not in self.data:
241                self.data[NO_WF_BIND] = self.getTotal()
242            data = self.data[state] = []
243            for type_ in self.getTypes():
244                res = self.cat(portal_type=type_, review_state=state)
245                l = len(res)
246                if l == 0:
247                    data.append(0)
248                else:
249                    data.append(l)
250            if len(data) > 0:
251                self.data[NO_WF_BIND] = map(lambda t,d:t-d, self.data[NO_WF_BIND], data)
252        return self.data[state]
253
254    def getTotal(self):
255        if self.total is None:
256            self.getTypes()
257        return self.total
258
259    def getNoWFContentTitle(self):
260        return NO_WF_BIND
261
262    def getNoWFContent(self):
263        return self.getContent(NO_WF_BIND)
264
265    def getChart(self):
266        data = []
267        for state in self.getStates():
268            data.append(self.getContent(state))
269        data.append(self.getContent(NO_WF_BIND))
270        max_value = max(self.getTotal())
271        chart = VerticalBarStack(data, encoding='text')
272        chart.title('Content type by state').legend(*self.states+[NO_WF_BIND])
273        chart.bar('a', 10, 0).legend_pos("b")
274        chart.color(*COLORS)
275        chart.size(800, 375).scale(0,max_value).axes('xy').label(*self.types)
276        chart.axes.type("y")
277        chart.axes.range(0,0,max_value)
278        return chart.img()
279
280
281class LegacyPortlets(BrowserView):
282    def __init__(self, context, request):
283        self.context = context
284        self.request = request
285        self.total = None
286        self.DEBUG = False
287        self.expressions = set()
288
289    def _getInfo(self, obj):
290        href = obj.absolute_url()
291        path = '/'.join(obj.getPhysicalPath())
292        info = {
293            'path': path,
294            'href': href,
295            'left_slots': None,
296            'right_slots': None,
297        }
298        if IPropertyManager.providedBy(obj):
299            obj = aq_base(obj)
300            if obj.hasProperty('left_slots'):
301                info['left_slots'] = obj.getProperty('left_slots')
302                self.expressions = self.expressions.union(set(info['left_slots']))
303            if obj.hasProperty('right_slots'):
304                info['right_slots'] = obj.getProperty('right_slots')
305                self.expressions = self.expressions.union(set(info['right_slots']))
306        return info
307
308    def _walk(self, obj, level=-1):
309        yield self._getInfo(obj)
310        if level != 0 and (IFolderish.providedBy(obj) or IBaseFolder.providedBy(obj)):
311            for v in obj.contentValues():
312                for i in self._walk(v, level-1):
313                    yield i
314
315    def getPortlets(self):
316        level = self.request.form.get('level', 1)
317        try:
318            level = level and int(level) or 1
319        except ValueError:
320            level = 1
321        infos = []
322        for i in self._walk(self.context, level):
323            if self.DEBUG or i['left_slots'] is not None or i['right_slots'] is not None:
324                infos.append(i)
325        self.total = len(infos)
326        return infos
327
328    def getTotal(self):
329        return self.total
330
331    def getAllPortletExpressions(self):
332        exprs = []
333        for name in self.expressions:
334            name = name.split('|')[0]
335            if not '/macros/' in name:
336                name = name.split('/')[-1]
337            name = name.strip()
338            if name not in exprs:
339                exprs.append(name)
340        exprs.sort()
341        return exprs
342
343class PropertiesStats(BrowserView):
344    def __init__(self, context, request):
345        self.context = context
346        self.request = request
347        self.total = None
348        self.DEBUG = False
349        self.expressions = set()
350        self.proplist = []
351        self.propname = self.request.form.get('propname') or ""
352
353    def _getInfo(self, obj):
354
355        href = obj.absolute_url()
356        path = '/'.join(obj.getPhysicalPath())
357        info = {
358            'path': path,
359            'href': href,
360            'slots': None,
361        }
362        if IPropertyManager.providedBy(obj):
363            obj = aq_base(obj)
364            self.proplist.extend([i for i in obj.propertyIds() if i not in self.proplist])
365            if obj.hasProperty(self.propname):
366                info['slots'] = obj.getProperty(self.propname)
367                if isinstance(info['slots'], int):
368                    info['slots'] = str(info['slots'])
369                if not isinstance(info['slots'], basestring):
370                    self.expressions = self.expressions.union(set(info['slots']))
371                else:
372                    self.expressions = self.expressions.union(set([info['slots']]))
373        return info
374
375    def _walk(self, obj, level=-1):
376        yield self._getInfo(obj)
377        if level != 0 and (IFolderish.providedBy(obj) or IBaseFolder.providedBy(obj)):
378            for v in obj.contentValues():
379                for i in self._walk(v, level-1):
380                    yield i
381
382    def getPropsList(self):
383        level = self.request.form.get('level', 1)
384        try:
385            level = level and int(level) or 1
386        except ValueError:
387            level = 1
388        infos = []
389        for i in self._walk(self.context, level):
390            if self.DEBUG or i['slots'] is not None:
391                infos.append(i)
392        self.total = len(infos)
393        return infos
394
395    def getTotal(self):
396        return self.total
397
398    def getAllPortletExpressions(self):
399        exprs = []
400        for name in self.expressions:
401            name = name.strip()
402            if name not in exprs:
403                exprs.append(name)
404        #exprs.sort()
405        return exprs
406
407class PortletsStats(BrowserView):
408    def __init__(self, context, request):
409        self.context = context
410        self.request = request
411        self.total = None
412        self.DEBUG = False
413        self.expressions = set()
414        self.proplist = []
415        self.propname = self.request.form.get('propname') or ""
416
417    def getAssignmentMappingUrl(self, context, manager):
418        baseUrl = str(getMultiAdapter((context, self.request), name='absolute_url'))
419        return '%s/++contextportlets++%s' % (baseUrl, manager.__name__)
420
421    def getAssignmentsForManager(self, context, manager):
422        assignments = getMultiAdapter((context, manager), IPortletAssignmentMapping)
423        return assignments.values()
424
425    def getPortletsMapping(self, context):
426        leftcolumn = getUtility(IPortletManager, name=u'plone.leftcolumn', context=context)
427        rightcolumn = getUtility(IPortletManager, name=u'plone.rightcolumn', context=context)
428        leftmapping = getMultiAdapter((context, leftcolumn,), IPortletAssignmentMapping)
429        rightmapping = getMultiAdapter((context, rightcolumn,), IPortletAssignmentMapping)
430        return (leftmapping, rightmapping)
431
432    def getLocalPortletsManager(self, context):
433        leftcolumn = getUtility(IPortletManager, name='plone.leftcolumn', context=context)
434        rightcolumn = getUtility(IPortletManager, name='plone.rightcolumn', context=context)
435        leftmanager = getMultiAdapter((context, leftcolumn,), ILocalPortletAssignmentManager)
436        rightmanager = getMultiAdapter((context, rightcolumn,), ILocalPortletAssignmentManager)
437        return (leftmanager, rightmanager)
438
439    def getPortletsManager(self, context):
440        left = getUtility(IPortletManager, name='plone.leftcolumn', context=context)
441        right = getUtility(IPortletManager, name='plone.rightcolumn', context=context)
442        return (left, right)
443
444    def portlets_for_assignments(self, assignments, manager, base_url):
445        data = []
446        for idx in range(len(assignments)):
447            name = assignments[idx].__name__
448
449            editview = queryMultiAdapter(
450                (assignments[idx], self.request), name='edit', default=None)
451
452            if editview is None:
453                editviewName = ''
454            else:
455                editviewName = '%s/%s/edit' % (base_url, name)
456
457            settings = IPortletAssignmentSettings(assignments[idx])
458
459            data.append({
460                'title'      : assignments[idx].title,
461                'editview'   : editviewName,
462                'visible'    : settings.get('visible', True),
463                })
464        return data
465
466    def getPortlets(self, context, mapping, manager):
467        #import pdb; pdb.set_trace()
468        return mapping.keys()
469
470    def _getInfo(self, obj):
471        href = obj.absolute_url()
472        path = '/'.join(obj.getPhysicalPath())
473        info = {
474            'path': path,
475            'href': href,
476            'left_slots': None,
477            'right_slots': None,
478        }
479        left, right = self.getPortletsManager(obj)
480        #leftmapping, rightmapping = self.getPortletsMapping(obj)
481        #leftmanager, rightmanager = self.getLocalPortletsManager(obj)
482        #info['left_slots'] = self.getPortlets(obj, leftmapping, leftmanager)
483        #info['right_slots'] = self.getPortlets(obj, rightmapping, rightmanager)
484        lass = self.getAssignmentsForManager(obj, left)
485        rass = self.getAssignmentsForManager(obj, right)
486        lurl = self.getAssignmentMappingUrl(obj, left)
487        rurl = self.getAssignmentMappingUrl(obj, right)
488        plass = self.portlets_for_assignments(lass, left, lurl)
489        prass = self.portlets_for_assignments(rass, right, rurl)
490        #print obj, plass, prass
491        info['left_slots'] = plass #[i['title'] for i in plass]
492        info['right_slots'] = prass #[i['title'] for i in prass]
493        return info
494
495    def _walk(self, obj, level=-1):
496        try:
497            yield self._getInfo(obj)
498        except:
499            pass
500        if level != 0 and (IFolderish.providedBy(obj) or IBaseFolder.providedBy(obj)):
501            for v in obj.contentValues():
502                for i in self._walk(v, level-1):
503                    yield i
504
505    def getPropsList(self):
506        level = self.request.form.get('level', 1)
507        try:
508            level = level and int(level) or 1
509        except ValueError:
510            level = 1
511        infos = []
512        for i in self._walk(self.context, level):
513            if self.DEBUG or i['left_slots'] is not None or i['right_slots'] is not None:
514                infos.append(i)
515        self.total = len(infos)
516        return infos
517
518    def getTotal(self):
519        return self.total
520
521    def getAllPortletExpressions(self):
522        exprs = []
523        for name in self.expressions:
524            name = name.strip()
525            if name not in exprs:
526                exprs.append(name)
527        #exprs.sort()
528        return exprs
Note: See TracBrowser for help on using the repository browser.