1 | from zope.interface import Interface |
---|
2 | from zope.interface import implements |
---|
3 | from zope.component import getMultiAdapter |
---|
4 | |
---|
5 | from plone.app.portlets.portlets import base |
---|
6 | from plone.portlets.interfaces import IPortletDataProvider |
---|
7 | |
---|
8 | from zope import schema |
---|
9 | from zope.formlib import form |
---|
10 | from plone.memoize.instance import memoize |
---|
11 | from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile |
---|
12 | from DateTime.DateTime import DateTime |
---|
13 | |
---|
14 | from quintagroup.quills.extras import quintagroupQuillsMessageFactory as _ |
---|
15 | |
---|
16 | class IMostCommented(IPortletDataProvider): |
---|
17 | """A portlet |
---|
18 | |
---|
19 | It inherits from IPortletDataProvider because for this portlet, the |
---|
20 | data that is being rendered and the portlet assignment itself are the |
---|
21 | same. |
---|
22 | """ |
---|
23 | |
---|
24 | # TODO: Add any zope.schema fields here to capture portlet configuration |
---|
25 | # information. Alternatively, if there are no settings, leave this as an |
---|
26 | # empty interface - see also notes around the add form and edit form |
---|
27 | # below. |
---|
28 | |
---|
29 | blog = schema.TextLine( |
---|
30 | title=_(u"Path to Blog"), |
---|
31 | description=_(u"Physical path to blog, from the plone object, 'blog' for ex."), |
---|
32 | required=True) |
---|
33 | |
---|
34 | period = schema.Int( |
---|
35 | title=_(u"Actual Period"), |
---|
36 | description=_(u"Actual period in days"), |
---|
37 | default = 30, |
---|
38 | required=True) |
---|
39 | |
---|
40 | limit = schema.Int( |
---|
41 | title=_(u"Maximum entries"), |
---|
42 | default = 5, |
---|
43 | description=_(u"What's the maximum number of entries to list?"), |
---|
44 | required=True) |
---|
45 | |
---|
46 | |
---|
47 | class Assignment(base.Assignment): |
---|
48 | """Portlet assignment. |
---|
49 | |
---|
50 | This is what is actually managed through the portlets UI and associated |
---|
51 | with columns. |
---|
52 | """ |
---|
53 | |
---|
54 | implements(IMostCommented) |
---|
55 | |
---|
56 | # TODO: Set default values for the configurable parameters here |
---|
57 | |
---|
58 | # some_field = u"" |
---|
59 | |
---|
60 | # TODO: Add keyword parameters for configurable parameters here |
---|
61 | # def __init__(self, some_field=u"): |
---|
62 | # self.some_field = some_field |
---|
63 | |
---|
64 | def __init__(self, blog='/www/blog', period=30, limit=5): |
---|
65 | self.blog = blog |
---|
66 | self.period = period |
---|
67 | self.limit = limit |
---|
68 | |
---|
69 | @property |
---|
70 | def title(self): |
---|
71 | """This property is used to give the title of the portlet in the |
---|
72 | "manage portlets" screen. |
---|
73 | """ |
---|
74 | return "Most Commented" |
---|
75 | |
---|
76 | class Renderer(base.Renderer): |
---|
77 | """Portlet renderer. |
---|
78 | |
---|
79 | This is registered in configure.zcml. The referenced page template is |
---|
80 | rendered, and the implicit variable 'view' will refer to an instance |
---|
81 | of this class. Other methods can be added and referenced in the template. |
---|
82 | """ |
---|
83 | |
---|
84 | render = ViewPageTemplateFile('mostcommented.pt') |
---|
85 | |
---|
86 | @property |
---|
87 | def days(self): |
---|
88 | return self.data.period |
---|
89 | |
---|
90 | @property |
---|
91 | @memoize |
---|
92 | def mostCommented(self): |
---|
93 | catalog = getMultiAdapter((self.context, self.request), name=u'plone_tools').catalog() |
---|
94 | pstate = getMultiAdapter((self.context, self.request), name=u'plone_portal_state') |
---|
95 | portal_id = pstate.portal().getId() |
---|
96 | brains = catalog(path='/%s/%s' % (portal_id, self.data.blog), |
---|
97 | portal_type='Discussion Item', |
---|
98 | review_state='published', |
---|
99 | created={'query':DateTime() - self.data.period, |
---|
100 | 'range':'min'} |
---|
101 | ) |
---|
102 | # count comments per blogpost |
---|
103 | comments = {} |
---|
104 | for b in brains: |
---|
105 | bep = '/'.join(b.getPath().split('/')[:-2]) |
---|
106 | comments.setdefault(bep, 0) |
---|
107 | comments[bep] = comments[bep] + 1 |
---|
108 | # sort blogpost_pathes by comment number |
---|
109 | sorted_dict = list(comments.iteritems()) |
---|
110 | sorted_dict.sort(lambda i1, i2: cmp(i1[1], i2[1])) |
---|
111 | sorted_dict.reverse() |
---|
112 | mcpathes = [k for k,v in sorted_dict[:self.data.limit]] |
---|
113 | # get mostcommented blogpost brains |
---|
114 | mostcommented = catalog(path={'query':mcpathes, 'depth':0}) |
---|
115 | mcomm_dict = dict([(b.getPath(),b) for b in mostcommented]) |
---|
116 | # associate comment number with appropriate blogpost brain |
---|
117 | res = [(n,mcomm_dict[p]) for p,n in sorted_dict if p in mcomm_dict.keys()] |
---|
118 | return res |
---|
119 | |
---|
120 | # NOTE: If this portlet does not have any configurable parameters, you can |
---|
121 | # inherit from NullAddForm and remove the form_fields variable. |
---|
122 | |
---|
123 | class AddForm(base.AddForm): |
---|
124 | """Portlet add form. |
---|
125 | |
---|
126 | This is registered in configure.zcml. The form_fields variable tells |
---|
127 | zope.formlib which fields to display. The create() method actually |
---|
128 | constructs the assignment that is being added. |
---|
129 | """ |
---|
130 | form_fields = form.Fields(IMostCommented) |
---|
131 | |
---|
132 | def create(self, data): |
---|
133 | return Assignment(**data) |
---|
134 | |
---|
135 | |
---|
136 | # NOTE: IF this portlet does not have any configurable parameters, you can |
---|
137 | # remove this class definition and delete the editview attribute from the |
---|
138 | # <plone:portlet /> registration in configure.zcml |
---|
139 | |
---|
140 | class EditForm(base.EditForm): |
---|
141 | """Portlet edit form. |
---|
142 | |
---|
143 | This is registered with configure.zcml. The form_fields variable tells |
---|
144 | zope.formlib which fields to display. |
---|
145 | """ |
---|
146 | form_fields = form.Fields(IMostCommented) |
---|