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

Last change on this file since 3666 was 3666, checked in by kroman0, 11 years ago

flake8

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