source: products/SimpleBlog/branches/plone-2.1/SimpleBlogTool.py @ 1

Last change on this file since 1 was 1, checked in by myroslav, 18 years ago

Building directory structure

File size: 18.6 KB
Line 
1from Products.CMFCore.utils import UniqueObject
2from OFS.SimpleItem import SimpleItem
3from OFS.PropertyManager import PropertyManager
4from Globals import InitializeClass
5from AccessControl import ClassSecurityInfo, Unauthorized
6from Products.CMFCore import CMFCorePermissions
7import zLOG,os
8
9import calendar
10calendar.setfirstweekday(6) #start day  Mon(0)-Sun(6)
11from DateTime import DateTime
12
13
14class SimpleBlogManager(UniqueObject, SimpleItem,PropertyManager): 
15    """ This tool provides some functions for SimpleBlog objects """ 
16    id = 'simpleblog_tool' 
17    meta_type= 'SimpleBlog manager' 
18    plone_tool = 1
19       
20    manage_options=PropertyManager.manage_options
21   
22    security = ClassSecurityInfo()
23    calendar_types=['BlogEntry']
24    use_session=""
25   
26    def __init__(self):
27        self.manage_addProperty('publishedState', 'published', 'string')
28        self.manage_addProperty('maxItemsInPortlet', 5, 'int')
29        self.manage_addProperty('globalCategories', '', 'lines')
30        self.manage_addProperty('showStandardButtons', 1,'boolean')
31        self.manage_addProperty('createPortletOnBlogCreation', 1,'boolean')
32        self.manage_addProperty('showIcons', 1,'boolean')
33
34
35    def _getState(self):
36        try:
37            return self.publishedState
38        except:
39            return 'published'
40
41    def _getMaxItemsInPortlet(self):
42        try:
43            return self.maxItemsInPortlet
44        except:
45            return 5
46    def _getGlobalCategories(self):
47        try:
48            cats = self.globalCategories
49            ret=[]
50            for c in cats:
51                if c!='':
52                    ret.append(c)
53            return ret
54        except:
55            return []
56       
57    def _getShowStandardButtons(self):
58        try:
59            return self.showStandardButtons
60        except:
61            return 1
62
63    def _getShowIcons(self):
64        if not self.hasProperty('showIcons'):
65            self.manage_addProperty('showIcons', 1,'boolean')
66        try:
67            return self.showIcons
68        except:
69            return 1
70       
71    def _getCreatePortletOnBlogCreation(self):
72        try:
73            return self.createPortletOnBlogCreation
74        except:
75            return 1
76
77    security.declareProtected(CMFCorePermissions.ManagePortal,'setProperties')       
78    def setProperties(self, publishedState='published', createPortletOnBlogCreation=None, maxItemsInPortlet=5, globalCategories='', showStandardButtons=1, showIcons=None):
79        self.publishedState = publishedState
80        if createPortletOnBlogCreation==1 or createPortletOnBlogCreation=='on':
81            self.createPortletOnBlogCreation=1
82        else:
83            self.createPortletOnBlogCreation=0
84
85        if showIcons==1 or showIcons=='on':
86            self.showIcons = 1
87        else:
88            self.showIcons = 0
89           
90        self.maxItemsInPortlet=int(maxItemsInPortlet)
91
92        value=''
93        if globalCategories<>'':
94            value =  globalCategories.split('\n')
95            value = [v.strip() for v in value if v.strip()]
96            value = filter(None, value)
97
98        self.globalCategories=value
99        self.showStandardButtons=int(showStandardButtons)
100   
101    security.declarePublic('getPublishedState')
102    def getPublishedState(self):
103        return self._getState()
104   
105    security.declarePublic('getMaxItemsInPortlet')
106    def getMaxItemsInPortlet(self):
107        return self._getMaxItemsInPortlet()
108   
109    security.declarePublic('getFrontPage')
110    def getFrontPage(self, context):
111        """
112        returns the frontpage (Blog object) when viewing an Entry
113        """
114        if context.portal_type!='Blog':
115            portal = context.portal_url.getPortalObject()
116            if context!=portal:
117                parent=context.aq_parent
118            else:
119                parent=context
120            found=0
121            while parent!=portal and context.portal_type!='Blog':
122                if parent.portal_type=='Blog':
123                    found=1
124                    break
125                parent=parent.aq_parent
126           
127            if found==1:
128                return parent
129            else:
130                return None
131        else:
132            return context
133     
134    security.declarePublic('getAvailableCategories')
135    def getAvailableCategories(self, context):
136        """
137        returns a dict of all the available categories with the number of posts inside
138        """
139        # get all EntryFolders
140        # first get the starting point in case we are inside a Blog section
141        # if we are higher in the tree than any Blog then we will end up in the portalobject itself
142        # in that case we just search for categories starting in context.
143
144        startpoint = self.getStartpoint(context, fromHere=0)
145
146        # now we have the starting point for our search
147       
148        result = startpoint.portal_catalog.searchResults(meta_type=['BlogFolder', 'Blog'], path={'query':self.getObjectPath(startpoint),'level':0})
149       
150        # now fetch all the available categories
151        categories=[]
152        for o in result:
153            obj=o.getObject()
154            cats = obj.getCategories()
155            for c in cats:
156                if not c in categories:
157                    categories.append(c)
158       
159        # add the global categories
160        for c in self.getGlobalCategories():
161            if not c in categories:
162                categories.append(c)
163       
164        # now we have a list of unique categories available from startpoint and deeper in tree
165        # next step is to count the number of entries for each category
166        rescats={}
167        for c in categories:
168            result = startpoint.portal_catalog.searchResults(review_state=self._getState(), meta_type='BlogEntry', EntryCategory=c,  path={'query':self.getObjectPath(startpoint),'level':0})
169            rescats[c]=len(result)
170        return rescats       
171   
172    security.declarePublic('getSortedKeys')
173    def getSortedKeys(self, dict):
174        keys = dict.keys()
175        keys.sort()
176        return keys
177   
178    security.declarePublic('getGlobalCategories')
179    def getGlobalCategories(self):
180        return self._getGlobalCategories()
181   
182    security.declarePublic('searchForEntries')
183    def getStartpoint(self, context, fromHere=0):
184        if context.portal_type!='Blog' and fromHere==0:
185            portal = context.portal_url.getPortalObject()
186            if context!=portal:
187                parent=context.aq_parent
188            else:
189                parent=context
190            found=0
191            while parent!=portal and context.portal_type!='Blog':
192                if parent.portal_type=='Blog':
193                    found=1
194                    break
195                parent=parent.aq_parent
196           
197            if found==1:
198                startpoint=parent
199            else:
200                if context.isPrincipiaFolderish:
201                    startpoint=context
202                else:
203                    startpoint=context.aq_parent
204        else:
205            startpoint=context
206
207        return startpoint
208   
209    security.declarePublic('searchForEntries')
210    def searchForEntries(self, context, category=None, maxResults=None, fromHere=0):
211        # set maxResults=0 for all the results,
212        # leave it to None to get the max from the properties
213        # set fromHere=1 to search from the current location. Is used for BlogFolders
214       
215        # first, get the context right
216        # when inside a Blog: search for the frontpage
217        # when outside a Blog: use context (or its container)
218           
219        startpoint = self.getStartpoint(context, fromHere)
220        # now we have the starting point for our search
221       
222        query={}
223       
224        if category!=None:
225            query['EntryCategory']=category
226           
227        query['getAlwaysOnTop']=1
228        resultsTop = startpoint.portal_catalog.searchResults(query, review_state=self._getState(), meta_type='BlogEntry', path={'query':self.getObjectPath(startpoint),'level':0}, sort_order='reverse', sort_on='effective')
229       
230        query['getAlwaysOnTop']=0
231        resultsNoTop = startpoint.portal_catalog.searchResults(query, review_state=self._getState(), meta_type='BlogEntry', path={'query':self.getObjectPath(startpoint),'level':0}, sort_order='reverse', sort_on='effective')
232       
233        results = resultsTop + resultsNoTop
234
235       
236        if maxResults==0:
237            return results
238        elif maxResults==None:
239            return results[:self._getMaxItemsInPortlet()]
240        else:
241            return results[:maxResults]   
242
243    security.declarePublic('searchForDay')
244    def searchForDay(self, context, date):
245        startpoint = self.getStartpoint(context, fromHere=0)
246        # now we have the starting point for our search
247       
248        query={'start': DateTime(date).earliestTime(), 'start_usage': 'range:min', 
249                    'end': DateTime(date).latestTime(), 'end_usage':'range:max'}
250        query['getAlwaysOnTop']=1
251        resultsTop = startpoint.portal_catalog.searchResults(query, 
252                                                             review_state=self._getState(), 
253                                                             meta_type='BlogEntry', 
254                                                             path={'query':self.getObjectPath(startpoint),'level':0}, 
255                                                             sort_order='reverse', sort_on='effective')
256       
257       
258        query['getAlwaysOnTop']=0
259        resultsNoTop = startpoint.portal_catalog.searchResults(query, 
260                                                             review_state=self._getState(), 
261                                                             meta_type='BlogEntry', 
262                                                             path={'query':self.getObjectPath(startpoint),'level':0}, 
263                                                             sort_order='reverse', sort_on='effective')
264       
265        results = resultsTop + resultsNoTop
266        return results
267   
268    security.declarePublic('blogHasEntries')
269    def blogHasEntries(self, context, fromHere=0):
270        """
271        returns if a blog has entries, either published or not published.
272        this function is used to display a message in the simpleblog(folder)_view when
273        there are entries but none of them published
274        """
275        startpoint = self.getStartpoint(context, fromHere=0)
276       
277        # get all entries, doesn't matter what state they're in
278        results = startpoint.portal_catalog.searchResults(meta_type='BlogEntry', path={'query':self.getObjectPath(startpoint),'level':0})       
279       
280        if results:
281            return True
282        else:
283            return False
284   
285    security.declarePublic('getEntryDate')
286    def getEntryDate(self, context):
287        if context.EffectiveDate()=='None':
288            return context.modification_date.aCommon()
289        else:
290            return context.EffectiveDate()
291
292    security.declarePublic('getShowStandardButtons')
293    def getShowStandardButtons(self):
294        return self._getShowStandardButtons()
295
296    security.declarePublic('getShowIcons')
297    def getShowIcons(self):
298        return self._getShowIcons()
299   
300    security.declarePublic('getCreatePortletOnBlogCreation')
301    def getCreatePortletOnBlogCreation(self):
302        return self._getCreatePortletOnBlogCreation()
303       
304    security.declareProtected(CMFCorePermissions.ManagePortal,'getAllWorkflowStates')
305    def getAllWorkflowStates(self, context):
306        lst=[]
307        for wf in context.portal_workflow.listWorkflows():
308            states = context.portal_workflow.getWorkflowById(wf).states
309            for s in states.keys():
310                if not states[s].id in lst:
311                    lst.append(states[s].id)
312        return lst
313   
314    security.declareProtected(CMFCorePermissions.ManagePortal,'getEntryWorkflowStates')
315    def getEntryWorkflowStates(self, context):
316        chain = context.portal_workflow.getChainForPortalType('BlogEntry', 0)
317        lst=[]
318        for wf in chain:
319            states = context.portal_workflow.getWorkflowById(wf).states
320            for s in states.keys():
321                if not states[s].id in lst:
322                    lst.append(states[s].id)
323       
324        return lst
325
326    # return object's url relative to the portal
327    def getObjectPath(self, object):
328        return os.path.join(*object.getPhysicalPath()).replace('\\', '/')
329       
330    # ======================================================
331    # calendar stuff, copied from CMFCalender
332    # ======================================================
333
334    security.declarePublic('getCalendarTypes')
335    def getCalendarTypes(self):
336        """ Returns a list of type that will show in the calendar """
337        return self.calendar_types
338
339    security.declarePublic('getUseSession')
340    def getUseSession(self):
341        """ Returns the Use_Session option """
342        return self.use_session
343
344    security.declarePublic('getDays')
345    def getDays(self):
346        """ Returns a list of days with the correct start day first """       
347        return calendar.weekheader(2).split()
348       
349    security.declarePublic('getWeeksList')
350    def getWeeksList(self, month='1', year='2002'):
351        """Creates a series of weeks, each of which contains an integer day number.
352           A day number of 0 means that day is in the previous or next month.
353        """
354        # daysByWeek is a list of days inside a list of weeks, like so:
355        # [[0, 1, 2, 3, 4, 5, 6],
356        #  [7, 8, 9, 10, 11, 12, 13],
357        #  [14, 15, 16, 17, 18, 19, 20],
358        #  [21, 22, 23, 24, 25, 26, 27],
359        #  [28, 29, 30, 31, 0, 0, 0]]
360        daysByWeek=calendar.monthcalendar(year, month)
361   
362        return daysByWeek
363
364    security.declarePublic('getEventsForCalendar')
365    def getEventsForCalendar(self, context, month='1', year='2002'):
366        """ recreates a sequence of weeks, by days each day is a mapping.
367            {'day': #, 'url': None}
368        """
369        year=int(year)
370        month=int(month)
371        # daysByWeek is a list of days inside a list of weeks, like so:
372        # [[0, 1, 2, 3, 4, 5, 6],
373        #  [7, 8, 9, 10, 11, 12, 13],
374        #  [14, 15, 16, 17, 18, 19, 20],
375        #  [21, 22, 23, 24, 25, 26, 27],
376        #  [28, 29, 30, 31, 0, 0, 0]]
377        daysByWeek=calendar.monthcalendar(year, month)
378        weeks=[]
379       
380        events=self.catalog_getevents(context, year, month)
381   
382        for week in daysByWeek:
383            days=[]
384            for day in week:
385                if events.has_key(day):
386                    days.append(events[day])
387                else:
388                    days.append({'day': day, 'event': 0, 'eventslist':[]})
389               
390            weeks.append(days)
391           
392        return weeks
393   
394    security.declarePublic('catalog_getevents')
395    def catalog_getevents(self, context, year, month):
396        """ given a year and month return a list of days that have events """
397        first_date=DateTime(str(month)+'/1/'+str(year))
398        last_day=calendar.monthrange(year, month)[1]
399        ## This line was cropping the last day of the month out of the
400        ## calendar when doing the query
401        ## last_date=DateTime(str(month)+'/'+str(last_day)+'/'+str(year))
402        last_date=first_date + last_day   
403       
404        # get the starting point for our search. This is where we depart from the standard catalog_tool:
405        startpoint = self.getStartpoint(context, fromHere=0)
406       
407        query=self.portal_catalog(portal_type=self.calendar_types,
408                              review_state=self._getState(),
409                              start=last_date,
410                              start_usage='range:max',
411                              end=first_date,
412                              end_usage='range:min',
413                              path={'query':self.getObjectPath(startpoint),'level':0},
414                              sort_on='start')
415       
416        # compile a list of the days that have events
417        eventDays={}
418        for daynumber in range(1, 32): # 1 to 31
419            eventDays[daynumber] = {'eventslist':[], 'event':0, 'day':daynumber}
420        includedevents = []
421        for result in query:
422            if result.getRID() in includedevents:
423                break
424            else:
425                includedevents.append(result.getRID())
426            event={}
427            # we need to deal with events that end next month
428            if  result.end.month() != month:  # doesn't work for events that last ~12 months - fix it if it's a problem, otherwise ignore
429                eventEndDay = last_day
430                event['end'] = None
431            else:
432                eventEndDay = result.end.day()
433                event['end'] = result.end.Time()
434            # and events that started last month
435            if result.start.month() != month:  # same as above re: 12 month thing
436                eventStartDay = 1
437                event['start'] = None
438            else:
439                eventStartDay = result.start.day()
440                event['start'] = result.start.Time()
441            event['title'] = result.Title or result.id
442            if eventStartDay != eventEndDay:
443                allEventDays = range(eventStartDay, eventEndDay+1)
444                eventDays[eventStartDay]['eventslist'].append({'end':None, 'start':result.start.Time(), 'title':result.Title})
445                eventDays[eventStartDay]['event'] = 1
446                for eventday in allEventDays[1:-1]:
447                    eventDays[eventday]['eventslist'].append({'end':None, 'start':None, 'title':result.Title})
448                    eventDays[eventday]['event'] = 1
449                eventDays[eventEndDay]['eventslist'].append({'end':result.end.Time(), 'start':None, 'title':result.Title})
450                eventDays[eventEndDay]['event'] = 1
451            else:
452                eventDays[eventStartDay]['eventslist'].append(event)
453                eventDays[eventStartDay]['event'] = 1
454            # This list is not uniqued and isn't sorted
455            # uniquing and sorting only wastes time
456            # and in this example we don't need to because
457            # later we are going to do an 'if 2 in eventDays'
458            # so the order is not important.
459            # example:  [23, 28, 29, 30, 31, 23]
460        return eventDays
461
462        # ==================
463        # end calendar stuff
464        # ==================
465   
466   
467   
468InitializeClass(SimpleBlogManager)
Note: See TracBrowser for help on using the repository browser.