root/trunk/BlogPost.py

Revision 3195, 9.3 kB (checked in by jukka, 1 week ago)

Fixed #2046. Last commit was from wrong branch.

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
19 from Products.Archetypes.public import *
20 from Products.ATReferenceBrowserWidget.ATReferenceBrowserWidget import ReferenceBrowserWidget
21 from Products.CMFCore.permissions import ModifyPortalContent
22 from Products.Archetypes.public import BaseSchema, BaseContent, registerType
23 from Products.Archetypes.atapi import DisplayList
24 from Globals import InitializeClass
25 from Products.CMFCore.utils import getToolByName
26 from AccessControl import ClassSecurityInfo, Unauthorized
27 from config import PROJECTNAME, MODIFY_CONTENT, VIEW
28 from CommonMixIn import CommonMixIn
29 from Schemata import coverImage, latest_edit_schema, score, state
30 from Products.Archetypes.atapi import DisplayList
31 from FieldsWidgets import TagsField, TagsWidget, LeStringWidget, LeTextAreaWidget, WYSIWYMField, AuthorsWidget
32 from permissions import ModerateContent, MODIFY_CONTENT, ACCESS_CONTENT, VIEW
33 from DateTime import DateTime
34 from GroupBlog import GroupBlog
35 from Discussable import Discussable
36
37 # Same thing as with MemberFolder but easier: MemberBlogs contain the values of groups itself in indexable storage.
38
39 schema = 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
77 class 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 getCreatorsString(self, as_links=True):
131         """ Emulate similar method from Resources, used by document_byline.pt """
132         values=self.getAuthors()
133         utool=getToolByName(self, 'lemill_usertool')
134         if values[0]=='*!*':
135             values=values[1:] 
136         names=[utool.linkTo(user_id, disabled=not as_links) for user_id in values]
137         return ", ".join(names)
138
139     def getCoverImageURL(self):
140         """BlogPosts shouldn't have their own cover images -- returns authors portrait."""
141         lutool=getToolByName(self, 'lemill_usertool')
142         return lutool.getMemberPortrait(self.Creator())       
143
144     def getDiscussionURL(self):
145         """ Overrides Discussable's method """
146         return self.absolute_url()
147
148     def getMetaDescription(self):
149         """ Description for html header. """
150         desc=self.getRawBodyText()
151         desc_len=0
152         desc_result=[]
153         ltool = getToolByName(self, 'lemill_tool')       
154         desc=ltool.stripHTML(desc)
155         # Add paragraphs until total is over 140 characters
156         for p in desc.split('\n'):
157             if p: # ignore empty lines
158                 desc_len+=len(p)
159                 desc_result.append(p)
160             if desc_len > 140:
161                 break
162         return '\n'.join(desc_result)
163    
164        
165     def getNicename(self):
166         """ I don't think this will get called but just to make sure. """
167         return self.Title()
168
169     def isPost(self):
170         return True
171
172     def notifyResourceDiscussed(self):
173         """ overload method from Discussable -- do not alert "resource owner" about replies """
174         pass
175
176     def canIEdit(self, member=None):
177         return self.amIOwner() or self.canIModerate()
178
179     security.declareProtected(ModerateContent, 'delete_post')
180     def delete_post(self):
181         """ Hide, remove from recent posts and remove from Collaboration proposals """
182         REQUEST = self.REQUEST
183         container=self.getBlog()
184         uid=self.UID()
185         self.setState('deleted')
186         self.reindexObject()
187         if hasattr(container, 'recent_posts'):
188             container.removeRecent_post(self.getId())
189         return REQUEST.RESPONSE.redirect(container.absolute_url())
190
191     security.declareProtected(ModerateContent, 'undelete_post')
192     def undelete_post(self):
193         """ Bring back post but currently doesn't add to collaboration proposals or recent posts """
194         REQUEST = self.REQUEST
195         container=self.getBlog()
196         uid=self.UID()
197         self.setState('public')
198         self.reindexObject()
199         if hasattr(container, 'recent_posts'):
200             container.addRecent_post(self.getId())
201         return REQUEST.RESPONSE.redirect(self.absolute_url())
202    
203     def Description(self):
204         """ Redirect to full body text """
205         return self.getBodyText()
206    
207     def getDefaultIcon(self, meta_type='', obj=None):
208         """ blogposts return creator's portrait """
209         lutool=getToolByName(self, 'lemill_usertool')
210         return lutool.getMemberPortrait(self.Creator())       
211
212     def getLatestEditDate(self):
213         """ Returns creation date as blog posts do not have History """
214         return DateTime(self.CreationDate())
215
216     def getLastEditor(self):
217         """ Returns id of the Creator """
218         return self.Creator()
219    
220
221     def getPortletDetails(self, REQUEST, isAnon, member):
222         """ Return an object of booleans to determine what to show and what to hide in portlet view """
223
224         v={'groupURL':'',
225             'groupCoverImageURL':'',
226             'groupTitle':'',
227             'editPost':False,
228             'deletePost':False,
229             'undeletePost':False,
230         }
231        
232         canEdit= self.canIEdit(member)
233         isDeleted = self.isDeleted()
234         # If resource is not assigned to any group, use the unassigned_discussions instead
235         try:
236             groupblog=self.getBlog()
237         except:
238             groupblog=self.community.groups.unassigned_discussions
239         if groupblog.id!='unassigned_discussions' and not groupblog.isDeleted():
240             v['groupURL']=groupblog.absolute_url()
241             v['groupCoverImageURL']=groupblog.getCoverImageURL()
242             v['groupTitle']=groupblog.title_or_id()
243        
244
245         v['editPost'] = canEdit and not isDeleted
246         v['deletePost'] = canEdit and not isDeleted
247         v['undeletePost'] = canEdit and isDeleted       
248         return v
249
250
251 registerType(BlogPost, PROJECTNAME)
Note: See TracBrowser for help on using the browser.