Skip to content

Commit 00741ca

Browse files
committed
Remove dependency of portal_calendar tool
1 parent 8c8cdfb commit 00741ca

File tree

8 files changed

+150
-78
lines changed

8 files changed

+150
-78
lines changed

CHANGES.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ There's a frood who really knows where his towel is.
1313
All Layout tab helper views use now ``collective.cover.CanEditLayout`` permission.
1414
The ``BaseGrid`` class is now located in the ``collective.cover.grids`` module.
1515

16+
- Remove dependency on portal_calendar tool for tile calendar.
17+
[rodfersou]
18+
1619
- Remove dependency on plone.directives.form.
1720
[l34marr]
1821

src/collective/cover/testing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def setUpPloneSite(self, portal):
169169

170170
portal_workflow = portal.portal_workflow
171171
portal_workflow.setChainForPortalTypes(
172-
['Collection'], ['simple_publication_workflow'])
172+
['Event', 'Collection'], ['simple_publication_workflow'])
173173

174174
# Prevent kss validation errors in Plone 4.2
175175
portal_kss = getattr(portal, 'portal_kss', None)

src/collective/cover/tests/test_calendar_tile.py

Lines changed: 88 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from collective.cover.tests.base import TestTileMixin
33
from collective.cover.tiles.calendar import CalendarTile
44
from collective.cover.tiles.calendar import ICalendarTile
5+
from datetime import datetime
6+
from plone import api
57

68
import unittest
79

@@ -10,10 +12,28 @@ class CalendarTileTestCase(TestTileMixin, unittest.TestCase):
1012

1113
def setUp(self):
1214
super(CalendarTileTestCase, self).setUp()
15+
16+
# Pin calendar to month 08/2016
17+
self.request['year'] = 2016
18+
self.request['month'] = 8
19+
1320
self.tile = CalendarTile(self.cover, self.request)
1421
self.tile.__name__ = u'collective.cover.calendar'
1522
self.tile.id = u'test'
1623

24+
# Pin today as day 18
25+
self.tile.isToday = lambda day: day == 18
26+
27+
# create some events
28+
with api.env.adopt_roles(['Manager']):
29+
for i in [3, 12, 21, 30]:
30+
start = datetime(2016, 8, i, 10, 30)
31+
end = datetime(2016, 8, i, 11, 30)
32+
obj = api.content.create(
33+
container=self.portal, type='Event', id='e{0}'.format(i),
34+
startDate=start, endDate=end, start=start, end=end)
35+
api.content.transition(obj, 'publish')
36+
1737
@unittest.expectedFailure # FIXME: raises BrokenImplementation
1838
def test_interface(self):
1939
self.interface = ICalendarTile
@@ -28,12 +48,73 @@ def test_default_configuration(self):
2848
def test_accepted_content_types(self):
2949
self.assertEqual(self.tile.accepted_ct(), [])
3050

51+
def test_getEventsForCalendar(self):
52+
self.assertEqual(self.tile.getEventsForCalendar(), EXPECTED_CALENDAR)
53+
54+
def test_getYearAndMonthToDisplay(self):
55+
self.assertEqual(self.tile.getYearAndMonthToDisplay(), (2016, 8))
56+
57+
def test_getWeekdays(self):
58+
expected = [
59+
u'weekday_mon_short', u'weekday_tue_short', u'weekday_wed_short',
60+
u'weekday_thu_short', u'weekday_fri_short', u'weekday_sat_short',
61+
u'weekday_sun_short']
62+
self.assertEqual(self.tile.getWeekdays(), expected)
3163

32-
# load tests only in Plone < 5
33-
def test_suite():
34-
# FIXME: https://github.com/collective/collective.cover/issues/633
35-
from collective.cover.config import IS_PLONE_5
36-
if IS_PLONE_5:
37-
return unittest.TestSuite()
3864

39-
return unittest.defaultTestLoader.loadTestsFromName(__name__)
65+
EXPECTED_CALENDAR = [
66+
[{'day': 1, 'event': 0, 'eventslist': [], 'is_today': False},
67+
{'day': 2, 'event': 0, 'eventslist': [], 'is_today': False},
68+
{'date_string': '2016-8-3',
69+
'day': 3,
70+
'event': 1,
71+
'eventslist': [{'end': '11:30:00', 'start': '10:30:00', 'title': 'e3'}],
72+
'eventstring': u'Aug 03, 2016\n 10:30-11:30 e3',
73+
'is_today': False},
74+
{'day': 4, 'event': 0, 'eventslist': [], 'is_today': False},
75+
{'day': 5, 'event': 0, 'eventslist': [], 'is_today': False},
76+
{'day': 6, 'event': 0, 'eventslist': [], 'is_today': False},
77+
{'day': 7, 'event': 0, 'eventslist': [], 'is_today': False}],
78+
[{'day': 8, 'event': 0, 'eventslist': [], 'is_today': False},
79+
{'day': 9, 'event': 0, 'eventslist': [], 'is_today': False},
80+
{'day': 10, 'event': 0, 'eventslist': [], 'is_today': False},
81+
{'day': 11, 'event': 0, 'eventslist': [], 'is_today': False},
82+
{'date_string': '2016-8-12',
83+
'day': 12,
84+
'event': 1,
85+
'eventslist': [{'end': '11:30:00', 'start': '10:30:00', 'title': 'e12'}],
86+
'eventstring': u'Aug 12, 2016\n 10:30-11:30 e12',
87+
'is_today': False},
88+
{'day': 13, 'event': 0, 'eventslist': [], 'is_today': False},
89+
{'day': 14, 'event': 0, 'eventslist': [], 'is_today': False}],
90+
[{'day': 15, 'event': 0, 'eventslist': [], 'is_today': False},
91+
{'day': 16, 'event': 0, 'eventslist': [], 'is_today': False},
92+
{'day': 17, 'event': 0, 'eventslist': [], 'is_today': False},
93+
{'day': 18, 'event': 0, 'eventslist': [], 'is_today': True},
94+
{'day': 19, 'event': 0, 'eventslist': [], 'is_today': False},
95+
{'day': 20, 'event': 0, 'eventslist': [], 'is_today': False},
96+
{'date_string': '2016-8-21',
97+
'day': 21,
98+
'event': 1,
99+
'eventslist': [{'end': '11:30:00', 'start': '10:30:00', 'title': 'e21'}],
100+
'eventstring': u'Aug 21, 2016\n 10:30-11:30 e21',
101+
'is_today': False}],
102+
[{'day': 22, 'event': 0, 'eventslist': [], 'is_today': False},
103+
{'day': 23, 'event': 0, 'eventslist': [], 'is_today': False},
104+
{'day': 24, 'event': 0, 'eventslist': [], 'is_today': False},
105+
{'day': 25, 'event': 0, 'eventslist': [], 'is_today': False},
106+
{'day': 26, 'event': 0, 'eventslist': [], 'is_today': False},
107+
{'day': 27, 'event': 0, 'eventslist': [], 'is_today': False},
108+
{'day': 28, 'event': 0, 'eventslist': [], 'is_today': False}],
109+
[{'day': 29, 'event': 0, 'eventslist': [], 'is_today': False},
110+
{'date_string': '2016-8-30',
111+
'day': 30,
112+
'event': 1,
113+
'eventslist': [{'end': '11:30:00', 'start': '10:30:00', 'title': 'e30'}],
114+
'eventstring': u'Aug 30, 2016\n 10:30-11:30 e30',
115+
'is_today': False},
116+
{'day': 31, 'event': 0, 'eventslist': [], 'is_today': False},
117+
{'day': 0, 'event': 0, 'eventslist': []},
118+
{'day': 0, 'event': 0, 'eventslist': []},
119+
{'day': 0, 'event': 0, 'eventslist': []},
120+
{'day': 0, 'event': 0, 'eventslist': []}]]

src/collective/cover/tests/test_upgrades.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,8 +524,6 @@ def test_registrations(self):
524524
self.assertGreaterEqual(int(version), int(self.to_version))
525525
self.assertEqual(self._how_many_upgrades_to_do(), 4)
526526

527-
# FIXME: https://github.com/collective/collective.cover/issues/633
528-
@unittest.skipIf(IS_PLONE_5, 'Upgrade step not supported under Plone 5')
529527
def test_register_calendar_tile(self):
530528
# address also an issue with Setup permission
531529
title = u'Register calendar tile'

src/collective/cover/tests/test_vocabularies.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# -*- coding: utf-8 -*-
2-
from collective.cover.config import IS_PLONE_5
32
from collective.cover.controlpanel import ICoverSettings
43
from collective.cover.testing import INTEGRATION_TESTING
54
from plone.registry.interfaces import IRegistry
@@ -46,10 +45,6 @@ def test_available_tiles_vocabulary(self):
4645
'collective.cover.richtext',
4746
]
4847

49-
# FIXME: https://github.com/collective/collective.cover/issues/633
50-
if IS_PLONE_5:
51-
expected.remove('collective.cover.calendar')
52-
5348
self.assertEqual(len(tiles), len(expected))
5449
for i in expected:
5550
self.assertIn(i, tiles)
@@ -73,10 +68,6 @@ def test_enabled_tiles_vocabulary(self):
7368
'collective.cover.richtext',
7469
]
7570

76-
# FIXME: https://github.com/collective/collective.cover/issues/633
77-
if IS_PLONE_5:
78-
expected.remove('collective.cover.calendar')
79-
8071
self.assertEqual(len(tiles), len(expected))
8172
for i in expected:
8273
self.assertIn(i, tiles)

src/collective/cover/tiles/calendar.py

Lines changed: 57 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
11
# -*- coding: utf-8 -*-
2+
# Avoid to import wrong calendar module
3+
# http://stackoverflow.com/a/8280677/2116850
4+
from __future__ import absolute_import
25
from Acquisition import aq_inner
36
from collective.cover import _
47
from collective.cover.tiles.base import IPersistentCoverTile
58
from collective.cover.tiles.base import PersistentCoverTile
69
from DateTime import DateTime
10+
from plone import api
11+
from plone.api.exc import InvalidParameterError
712
from Products.CMFCore.utils import getToolByName
813
from Products.CMFPlone.utils import safe_unicode
914
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
1015
from time import localtime
1116
from urllib import quote_plus
12-
from zope.component import getMultiAdapter
1317
from zope.i18nmessageid import MessageFactory
1418
from zope.interface import implementer
1519

20+
import calendar
21+
1622

1723
PLMF = MessageFactory('plonelocales')
1824

@@ -39,7 +45,6 @@ def __init__(self, context, request):
3945

4046
def _setup(self):
4147
context = aq_inner(self.context)
42-
self.calendar = getToolByName(context, 'portal_calendar')
4348
self._ts = getToolByName(context, 'translation_service')
4449
self.url_quote_plus = quote_plus
4550

@@ -56,31 +61,57 @@ def _setup(self):
5661

5762
self.monthName = PLMF(self._ts.month_msgid(month),
5863
default=self._ts.month_english(month))
64+
self._set_first_weekday()
65+
66+
def _set_first_weekday(self):
67+
try: # Plone 5.x
68+
first_weekday = api.portal.get_registry_record('plone.first_weekday')
69+
except InvalidParameterError:
70+
try: # plone.app.event
71+
first_weekday = api.portal.get_registry_record('plone.app.event.first_weekday')
72+
except InvalidParameterError: # Plone 4.x
73+
portal_calendar = api.portal.get_tool('portal_calendar')
74+
first_weekday = getattr(portal_calendar, 'firstweekday', calendar.SUNDAY)
75+
calendar.setfirstweekday(first_weekday)
5976

6077
def accepted_ct(self):
6178
"""Return an empty list as no content types are accepted."""
6279
return []
6380

64-
def getEventsForCalendar(self):
65-
context = aq_inner(self.context)
66-
year = self.year
67-
month = self.month
68-
portal_state = getMultiAdapter((self.context, self.request), name='plone_portal_state')
69-
navigation_root_path = portal_state.navigation_root_path()
70-
weeks = self.calendar.getEventsForCalendar(month, year, path=navigation_root_path)
71-
for week in weeks:
72-
for day in week:
73-
daynumber = day['day']
74-
if daynumber == 0:
75-
continue
76-
day['is_today'] = self.isToday(daynumber)
77-
if day['event']:
78-
cur_date = DateTime(year, month, daynumber)
79-
localized_date = [self._ts.ulocalized_time(cur_date, context=context, request=self.request)]
80-
day['eventstring'] = '\n'.join(localized_date + [
81-
' {0}'.format(self.getEventString(e)) for e in day['eventslist']])
82-
day['date_string'] = '{0}-{1}-{2}'.format(year, month, daynumber)
81+
def addEvents(self, day):
82+
catalog = api.portal.get_tool('portal_catalog')
83+
start = DateTime(self.year, self.month, day['day'])
84+
end = start + 1
85+
query = dict(
86+
portal_type='Event', review_state='published',
87+
start={'query': (start, end), 'range': 'min:max'}, sort_on='start')
88+
for brain in catalog(**query):
89+
day['event'] += 1
90+
day['date_string'] = '{0}-{1}-{2}'.format(self.year, self.month, day['day'])
91+
if 'eventslist' not in day:
92+
day['eventslist'] = []
93+
event = dict(
94+
start=brain.start.Time(), end=brain.end.Time(), title=brain.Title or brain.id)
95+
day['eventslist'].append(event)
96+
if 'eventstring' not in day:
97+
localized_date = self._ts.ulocalized_time(
98+
start, context=self.context, request=self.request)
99+
day['eventstring'] = localized_date
100+
day['eventstring'] += '\n {0}'.format(self.getEventString(event))
101+
return day
83102

103+
def getEventsForCalendar(self):
104+
monthcalendar = calendar.monthcalendar(self.year, self.month)
105+
weeks = []
106+
for w in monthcalendar:
107+
week = []
108+
for d in w:
109+
day = {'day': d, 'event': 0, 'eventslist': []}
110+
if d > 0:
111+
day['is_today'] = self.isToday(d)
112+
day = self.addEvents(day)
113+
week.append(day)
114+
weeks.append(week)
84115
return weeks
85116

86117
def getEventString(self, event):
@@ -100,22 +131,12 @@ def getEventString(self, event):
100131
return eventstring
101132

102133
def getYearAndMonthToDisplay(self):
103-
session = None
104134
request = self.request
105135

106136
# First priority goes to the data in the REQUEST
107137
year = request.get('year', None)
108138
month = request.get('month', None)
109139

110-
# Next get the data from the SESSION
111-
if self.calendar.getUseSession():
112-
session = request.get('SESSION', None)
113-
if session:
114-
if not year:
115-
year = session.get('calendar_year', None)
116-
if not month:
117-
month = session.get('calendar_month', None)
118-
119140
# Last resort to today
120141
if not year:
121142
year = self.now[0]
@@ -129,11 +150,6 @@ def getYearAndMonthToDisplay(self):
129150
except (TypeError, ValueError):
130151
year, month = self.now[:2]
131152

132-
# Store the results in the session for next time
133-
if session:
134-
session.set('calendar_year', year)
135-
session.set('calendar_month', month)
136-
137153
# Finally return the results
138154
return year, month
139155

@@ -153,12 +169,12 @@ def getNextMonth(self, year, month):
153169

154170
def getWeekdays(self):
155171
"""Returns a list of Messages for the weekday names."""
156-
weekdays = []
157-
# list of ordered weekdays as numbers
158-
for day in self.calendar.getDayNumbers():
159-
weekdays.append(PLMF(self._ts.day_msgid(day, format='s'),
160-
default=self._ts.weekday_english(day, format='a')))
161172

173+
weekheaders = calendar.weekheader(3).split()
174+
weekdays = []
175+
for header in weekheaders:
176+
weekdays.append(PLMF('weekday_{0}_short'.format(header.lower()),
177+
default=header))
162178
return weekdays
163179

164180
def isToday(self, day):
@@ -168,14 +184,6 @@ def isToday(self, day):
168184
return (
169185
self.now[2] == day and self.now[1] == self.month and self.now[0] == self.year)
170186

171-
def getReviewStateString(self):
172-
states = self.calendar.getCalendarStates()
173-
return ''.join(map(lambda x: 'review_state={0}&amp;'.format(self.url_quote_plus(x)), states))
174-
175-
def getEventTypes(self):
176-
types = self.calendar.getCalendarTypes()
177-
return ''.join(map(lambda x: 'Type={0}&amp;'.format(self.url_quote_plus(x)), types))
178-
179187
def getQueryString(self):
180188
request = self.request
181189
query_string = request.get('orig_query',

src/collective/cover/tiles/templates/calendar.pt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
tal:attributes="class python:is_today and 'todayevent' or 'event'">
6868
<strong>
6969
<a href=""
70-
tal:attributes="href string:${navigation_root_url}/@@search?advanced_search=True&amp;${view/getReviewStateString}start.query:record:list:date=${day/date_string}+23%3A59%3A59&amp;start.range:record=max&amp;end.query:record:list:date=${day/date_string}+00%3A00%3A00&amp;end.range:record=min&amp;list:&amp;${view/getEventTypes};
70+
tal:attributes="href string:${navigation_root_url}/@@search?advanced_search=True&amp;review_state=published&amp;start.query:record:list:date=${day/date_string}+23%3A59%3A59&amp;start.range:record=max&amp;end.query:record:list:date=${day/date_string}+00%3A00%3A00&amp;end.range:record=min&amp;list:&amp;Type=Event&amp;;
7171
title day/eventstring;"
7272
tal:content="daynumber">31</a>
7373
</strong>

src/collective/cover/vocabularies.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# -*- coding: utf-8 -*-
2-
from collective.cover.config import IS_PLONE_5
32
from collective.cover.controlpanel import ICoverSettings
43
from collective.cover.interfaces import IGridSystem
54
from collective.cover.tiles.base import IPersistentCoverTile
@@ -36,10 +35,6 @@ def __call__(self, context):
3635
settings = registry.forInterface(ICoverSettings)
3736
tiles = settings.available_tiles
3837

39-
# FIXME: https://github.com/collective/collective.cover/issues/633
40-
if IS_PLONE_5 and 'collective.cover.calendar' in tiles:
41-
tiles.remove('collective.cover.calendar')
42-
4338
items = [SimpleTerm(value=i, title=i) for i in tiles]
4439
return SimpleVocabulary(items)
4540

@@ -59,10 +54,6 @@ class EnabledTilesVocabulary(object):
5954
"""Return a list of tiles ready to work with collective.cover."""
6055

6156
def _enabled(self, name):
62-
# FIXME: https://github.com/collective/collective.cover/issues/633
63-
if IS_PLONE_5 and name == 'collective.cover.calendar':
64-
return False
65-
6657
tile_type = queryUtility(ITileType, name)
6758
if tile_type:
6859
return issubclass(tile_type.schema, IPersistentCoverTile)

0 commit comments

Comments
 (0)