source: trunk/BlogPost.py @ 3002

Revision 3002, 8.9 KB checked in by jukka, 10 years ago (diff)

Removed two very useless metadata indexes, fixed one bug from yesterdays history cleanup.

Line 
1# Copyright 2006 by the LeMill Team (see AUTHORS)
2#
3# This file is part of LeMill.
4#
5# LeMill is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# LeMill is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with LeMill; if not, write to the Free Software
17# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19from Products.Archetypes.public import *
20from Products.ATReferenceBrowserWidget.ATReferenceBrowserWidget import ReferenceBrowserWidget
21from Products.CMFCore.permissions import ModifyPortalContent
22from Products.Archetypes.public import BaseSchema, BaseContent, registerType
23from Products.Archetypes.atapi import DisplayList
24from Globals import InitializeClass
25from Products.CMFCore.utils import getToolByName
26from AccessControl import ClassSecurityInfo, Unauthorized
27from config import PROJECTNAME, MODIFY_CONTENT, VIEW
28from CommonMixIn import CommonMixIn
29from Schemata import coverImage, latest_edit_schema, score, state
30from Products.Archetypes.atapi import DisplayList
31from FieldsWidgets import TagsField, TagsWidget, LeStringWidget, LeTextAreaWidget, WYSIWYMField
32from permissions import ModerateContent, MODIFY_CONTENT, ACCESS_CONTENT, VIEW
33from DateTime import DateTime
34from GroupBlog import GroupBlog
35from Discussable import Discussable
36
37# Same thing as with MemberFolder but easier: MemberBlogs contain the values of groups itself in indexable storage.
38
39schema = BaseSchema + coverImage + latest_edit_schema + score +  state + Schema((
40    StringField(
41        name='title',
42        required=1,
43        searchable=1,
44        default='',
45        accessor='Title',
46        widget=LeStringWidget(
47            label='Topic',
48            label_msgid='label_topic',
49            visible={'view' : 'invisible'},
50            i18n_domain='lemill',
51        ),
52    ),
53    StringField(
54        name='parentBlog',
55        index='FieldIndex:schema',
56        widget=ComputedWidget(
57            visible={'edit':'invisible', 'view':'invisible'}
58            ),
59        ),       
60    WYSIWYMField('bodyText',
61        accessor="getBodyText",
62        mutator = "setBodyText",
63        edit_accessor = 'getRawBodyText',
64        index='ZCTextIndex',
65        copied_in_translation=True,
66        searchable = True,
67        required = True,
68        widget=LeTextAreaWidget(
69            label="Body text",
70            label_msgid="label_wysiwym_body_text",
71            i18n_domain="lemill",
72            rows=10
73            ),
74        ),
75))
76
77class BlogPost(Discussable, CommonMixIn, BaseContent):
78    """Blog post"""
79
80    meta_type = "BlogPost"
81    archetype_name = "BlogPost"
82    allow_discussion = True
83    _at_rename_after_creation = True
84
85    security = ClassSecurityInfo()
86    default_view = ('blogpost_view')
87    security.declareObjectPublic()
88    schema = schema
89    portlet = 'here/portlet_blogpost_actions/macros/portlet'
90
91    security.declarePrivate('at_post_edit_script')
92    def at_post_edit_script(self):
93        """ Rename id to resemble title, add to list of collaboration proposals of community if such, and add to recent posts of blog. """
94        old=self.getId()
95        self._renameAfterCreation()
96        new=self.getId()
97        if old != new: # new id is updated to recent posts list
98            try: # if for some reason posts are not inside blogs
99                blog=self.getBlog()
100                blog.replaceRecent_post(old, new)
101            except:
102                pass
103
104    security.declarePrivate('at_post_create_script')
105    def at_post_create_script(self):
106        """ Add to blog's recent posts, notify group founder, enable syndication """
107        blog = self.getBlog()
108        if blog:
109            blog.addRecent_post(self.getId())
110            self.setParentBlog(blog.id)
111            blog.notifyNewThread()
112        syn_tool = getToolByName(self, 'portal_syndication', None)
113        if not syn_tool.isSyndicationAllowed(self):
114            try:
115                syn_tool.enableSyndication(self)
116            except AttributeError:
117                pass
118        self.reindexObject() # parentBlog does not get indexed unless we do this.
119
120    def setPermissions(self):
121        self.manage_permission(VIEW, ('Manager','Owner','Member','Authenticated','Anonymous'), acquire=0)
122        self.manage_permission(MODIFY_CONTENT, ('Manager','Owner'), acquire=0)
123        self.manage_permission(ModerateContent, ('Manager','Owner','Reviewer'), acquire=0)
124        self.manage_permission(ACCESS_CONTENT, ('Manager','Owner','Member','Authenticated','Anonymous'), acquire=0)
125               
126    def getAuthors(self):
127        """Emulate the method that Resource has"""
128        return [self.Creator(),]
129
130    def getCoverImageURL(self):
131        """BlogPosts shouldn't have their own cover images -- returns authors portrait."""
132        lutool=getToolByName(self, 'lemill_usertool')
133        return lutool.getMemberPortrait(self.Creator())       
134
135    def getDiscussionURL(self):
136        """ Overrides Discussable's method """
137        return self.absolute_url()
138
139       
140    def getNicename(self):
141        """ I don't think this will get called but just to make sure. """
142        return self.Title()
143
144    def isPost(self):
145        return True
146
147    def notifyResourceDiscussed(self):
148        """ overload method from Discussable -- do not alert "resource owner" about replies """
149        pass
150
151    def canIEdit(self, member=None):
152        return self.amIOwner() or self.canIModerate()
153
154    security.declareProtected(ModerateContent, 'delete_post')
155    def delete_post(self):
156        """ Hide, remove from recent posts and remove from Collaboration proposals """
157        REQUEST = self.REQUEST
158        container=self.getBlog()
159        uid=self.UID()
160        self.setState('deleted')
161        self.reindexObject()
162        if hasattr(container, 'recent_posts'):
163            container.removeRecent_post(self.getId())
164        return REQUEST.RESPONSE.redirect(container.absolute_url())
165
166    security.declareProtected(ModerateContent, 'undelete_post')
167    def undelete_post(self):
168        """ Bring back post but currently doesn't add to collaboration proposals or recent posts """
169        REQUEST = self.REQUEST
170        container=self.getBlog()
171        uid=self.UID()
172        self.setState('public')
173        self.reindexObject()
174        if hasattr(container, 'recent_posts'):
175            container.addRecent_post(self.getId())
176        return REQUEST.RESPONSE.redirect(self.absolute_url())
177   
178    def Description(self):
179        """ Redirect to full body text """
180        return self.getBodyText()
181   
182    def getDefaultIcon(self, meta_type='', obj=None):
183        """ blogposts return creator's portrait """
184        lutool=getToolByName(self, 'lemill_usertool')
185        return lutool.getMemberPortrait(self.Creator())       
186
187    def getLatestEditDate(self):
188        """ Returns creation date as blog posts do not have History """
189        return DateTime(self.CreationDate())
190
191    def getLastEditor(self):
192        """ Returns id of the Creator """
193        return self.Creator()
194   
195
196    def getPortletDetails(self, REQUEST, isAnon, member):
197        """ Return an object of booleans to determine what to show and what to hide in portlet view """
198
199        v={'groupURL':'',
200            'groupCoverImageURL':'',
201            'groupTitle':'',
202            'editPost':False,
203            'deletePost':False,
204            'undeletePost':False,
205        }
206       
207        canEdit= self.canIEdit(member)
208        isDeleted = self.isDeleted()
209        # If resource is not assigned to any group, use the unassigned_discussions instead
210        try:
211            groupblog=self.getBlog()
212        except:
213            groupblog=self.community.groups.unassigned_discussions
214        if groupblog.id!='unassigned_discussions' and not groupblog.isDeleted():
215            v['groupURL']=groupblog.absolute_url()
216            v['groupCoverImageURL']=groupblog.getCoverImageURL()
217            v['groupTitle']=groupblog.title_or_id()
218       
219
220        v['editPost'] = canEdit and not isDeleted
221        v['deletePost'] = canEdit and not isDeleted
222        v['undeletePost'] = canEdit and isDeleted       
223        return v
224
225
226    ################# RSS ######################################
227
228    def getRSSResults(self):
229        """ Returns list of tuples (discussion_obj, display_macro_path, url) with blogpost itself leading the bunch """
230        url_base=self.absolute_url()
231        title='re:%s' % self.Title()
232        return [(self, 'here/rss_macros/macros/real_object', url_base)]+[(x, 'here/rss_macros/macros/discussion_comment', '%s#%s' % (url_base, x.id), title) for x in self.getSortedDiscussion()]
233
234
235registerType(BlogPost, PROJECTNAME)
Note: See TracBrowser for help on using the repository browser.