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

Last change on this file since 3171 was 3171, checked in by vmaksymiv, 13 years ago

pylint fixes

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