source: trunk/BlogPost.py @ 1983

Revision 1956, 8.4 KB checked in by jukka, 12 years ago (diff)

Fixed #1494. Anonymous users can view discussions, but are asked to join to reply to them. When anonymous views an empty discussion, it doesn't cause creation of discussion post.

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 Resources import CommonMixIn
29from SharedMetadata import bodytext, bodytext_simple, tags, coverImage, latest_edit_schema, score
30from Products.Archetypes.atapi import DisplayList
31from FieldsWidgets import TagsField, TagsWidget, LeStringWidget
32from permissions import ModerateContent, MODIFY_CONTENT
33from DateTime import DateTime
34
35# Same thing as with MemberFolder but easier: MemberBlogs contain the values of groups itself in indexable storage.
36
37schema = BaseSchema + bodytext_simple + coverImage + latest_edit_schema + score + Schema((
38    StringField(
39        name='title',
40        required=1,
41        searchable=1,
42        default='',
43        accessor='Title',
44        widget=LeStringWidget(
45            label='Topic',
46            label_msgid='label_topic',
47            visible={'view' : 'invisible'},
48            i18n_domain='lemill',
49        ),
50    ),
51    BooleanField(
52        name="is_discussion",
53        default=False,
54        index='FieldIndex:schema',
55        widget=ComputedWidget(
56            visible={'edit':'invisible', 'view':'invisible'}
57            ),
58        ),
59))
60schema = schema.copy()
61schema['bodyText'].required = True
62schema['bodyText'].widget.rows = 10
63
64class BlogPost(BaseContent,CommonMixIn):
65    """Blog post"""
66
67    meta_type = "BlogPost"
68    archetype_name = "BlogPost"
69    allow_discussion = True
70    _at_rename_after_creation = True
71
72    security = ClassSecurityInfo()
73    default_view = ('blogpost_view')
74    security.declareObjectPublic()
75    schema = schema
76
77    security.declarePrivate('manage_afterAdd')
78    def manage_afterAdd(self, item, container):
79        """1) Replaces the left side portlets with the content type's own action portlet. 2) add obj id to list of recent entries in parent GroupBlog. """
80        BaseContent.manage_afterAdd(self, item, container)
81        if not hasattr(item.aq_base, 'left_slots'):
82            self._setProperty('left_slots', ['here/portlet_groupblog_actions/macros/portlet',], 'lines')
83        if hasattr(container, 'recent_posts'):
84            container.addRecent_post(self.getId())
85        syn_tool = getToolByName(self, 'portal_syndication', None)
86        if syn_tool is not None:
87            try:
88                syn_tool.enableSyndication(self)
89            except: # might get 'Syndication Information Exists'
90                pass
91        BaseContent.manage_afterAdd(self, item, container)
92
93
94
95    security.declarePrivate('at_post_edit_script')
96    def at_post_edit_script(self):
97        """ Rename id to resemble title, add to list of collaboration proposals of community if such, and add to recent posts of blog. """
98        old=self.getId()
99        uid=self.UID()
100        self._renameAfterCreation()
101        new=self.getId()
102
103        if old != new: # new id is updated to recent posts list
104            try: # if for some reason posts are not inside blogs
105                blog=self.getBlog()
106                blog.replaceRecent_post(old, new)
107            except:
108                pass
109
110
111               
112    def getAuthors(self):
113        """Emulate the method that Resource has"""
114        return [self.Creator(),]
115
116    def getCoverImageURL(self):
117        """BlogPosts shouldn't have their own cover images -- returns authors portrait."""
118        return getattr(self.community,self.Creator).getPortraitURL()
119       
120    def NiceName(self):
121        """ I don't think this will get called but just to make sure. """
122        return self.getTitle()
123
124    def isPost(self):
125        return True
126
127    security.declareProtected(ModerateContent, 'delete_post')
128    def delete_post(self):
129        """ Hide, remove from recent posts and remove from Collaboration proposals """
130        container=self.getBlog()
131        uid=self.UID()
132        self.content_status_modify(workflow_action='delete')
133        self.reindexObject()
134        if hasattr(container, 'recent_posts'):
135            container.removeRecent_post(self.getId())
136
137    security.declareProtected(ModerateContent, 'undelete_post')
138    def undelete_post(self):
139        """ Bring back post but currently doesn't add to collaboration proposals or recent posts """
140        container=self.getBlog()
141        uid=self.UID()
142        self.content_status_modify(workflow_action='publish')
143        self.reindexObject()
144        if hasattr(container, 'recent_posts'):
145            container.addRecent_post(self.getId())
146   
147#    def setProperties(self, newprops=None, **kw):
148#        """ just a helper method """
149#        if newprops is None:
150#            newprops = kw
151#        for (key, value) in newprops.items():
152#            accessor='get'+str(key.capitalize())
153#            mutator='set'+str(key.capitalize())
154#
155#            if hasattr(self, accessor):
156#                if eval('self.'+accessor+'()') != value:
157#                    eval('self.'+mutator+'(value)')
158
159    security.declareProtected(MODIFY_CONTENT, 'setCoverImage')
160    def setCoverImage(self, value, **kwargs):
161        """ This modification for a mutator flags object to have a coverImage """
162        cover=self.getField('coverImage')
163        cover.set(self,value,**kwargs)
164        has_cover=self.getField('hasCoverImage')
165        has_cover.set(self,True)
166
167
168    def getComments(self, n=False):
169        """ Get discussion comments or their number """
170        pd=getToolByName(self, 'portal_discussion')
171        rp=pd.getDiscussionFor(self).getReplies()               
172        if n:
173            return len(rp)
174        rp=self.sort_modified_ascending(rp)
175        return rp
176
177    def getLatestComment(self):
178        """ Return time to latest comment in dictionary of days, hours, minutes """
179        pd=getToolByName(self, 'portal_discussion')
180        letool=getToolByName(self,'lemill_tool')
181        rp=pd.getDiscussionFor(self).getReplies()               
182        if not rp:
183            return None
184        #rp=self.sort_modified_ascending(rp)
185        latest=rp[-1]       
186        return letool.getTimeDifference(latest.CreationDate())
187       
188
189    def Description(self):
190        """ Redirect to full body text """
191        return self.getBodyText()
192   
193    def getDefaultIcon(self, meta_type='', obj=None):
194        """ blogposts don't currently have icons """
195        # in my opinion this should return creator's portrait
196        # but I currently don't have time to find methods for getting them
197        return 'images/default_member.png'
198
199    def getLatestEditDate(self):
200        """ Returns creation date as blog posts do not have History """
201        return DateTime(self.CreationDate())
202
203    def getLastEditor(self):
204        """ Returns id of the Creator """
205        return self.Creator()
206   
207    def getShortenBlog(self):
208        """ Creates shorten link names """
209        lt = getToolByName(self, 'lemill_tool')
210        return lt.split_at_p_or_br(self.getBlog(),min_len=50, max_len=200);
211
212    def getDiscussedResource(self):
213        """ if this is related to some resource, get the resource """
214        reftool= getToolByName(self, 'reference_catalog')
215        obj_uid = self.UID()
216        found = []
217        ref_query = { 'sourceUID': obj_uid, 'type': 'is_discussion_about' }
218        refresults = reftool(ref_query)
219        for q in refresults:
220            refobject = reftool.lookupObject(q.UID)
221            target = refobject.getTargetObject()
222            if target:
223                return target
224        return None
225
226
227registerType(BlogPost, PROJECTNAME)
Note: See TracBrowser for help on using the repository browser.