Skip to content

Commit 1b43082

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

File tree

7 files changed

+161
-71
lines changed

7 files changed

+161
-71
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: 94 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,79 @@ 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)
63+
64+
def test_getReviewStateString(self):
65+
self.assertEqual(self.tile.getReviewStateString(), 'review_state=published&')
66+
67+
def test_getEventTypes(self):
68+
self.assertEqual(self.tile.getEventTypes(), 'Type=Event&')
3169

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()
3870

39-
return unittest.defaultTestLoader.loadTestsFromName(__name__)
71+
EXPECTED_CALENDAR = [
72+
[{'day': 1, 'event': 0, 'eventslist': [], 'is_today': False},
73+
{'day': 2, 'event': 0, 'eventslist': [], 'is_today': False},
74+
{'date_string': '2016-8-3',
75+
'day': 3,
76+
'event': 1,
77+
'eventslist': [{'end': '11:30:00', 'start': '10:30:00', 'title': 'e3'}],
78+
'eventstring': u'Aug 03, 2016\n 10:30-11:30 e3',
79+
'is_today': False},
80+
{'day': 4, 'event': 0, 'eventslist': [], 'is_today': False},
81+
{'day': 5, 'event': 0, 'eventslist': [], 'is_today': False},
82+
{'day': 6, 'event': 0, 'eventslist': [], 'is_today': False},
83+
{'day': 7, 'event': 0, 'eventslist': [], 'is_today': False}],
84+
[{'day': 8, 'event': 0, 'eventslist': [], 'is_today': False},
85+
{'day': 9, 'event': 0, 'eventslist': [], 'is_today': False},
86+
{'day': 10, 'event': 0, 'eventslist': [], 'is_today': False},
87+
{'day': 11, 'event': 0, 'eventslist': [], 'is_today': False},
88+
{'date_string': '2016-8-12',
89+
'day': 12,
90+
'event': 1,
91+
'eventslist': [{'end': '11:30:00', 'start': '10:30:00', 'title': 'e12'}],
92+
'eventstring': u'Aug 12, 2016\n 10:30-11:30 e12',
93+
'is_today': False},
94+
{'day': 13, 'event': 0, 'eventslist': [], 'is_today': False},
95+
{'day': 14, 'event': 0, 'eventslist': [], 'is_today': False}],
96+
[{'day': 15, 'event': 0, 'eventslist': [], 'is_today': False},
97+
{'day': 16, 'event': 0, 'eventslist': [], 'is_today': False},
98+
{'day': 17, 'event': 0, 'eventslist': [], 'is_today': False},
99+
{'day': 18, 'event': 0, 'eventslist': [], 'is_today': True},
100+
{'day': 19, 'event': 0, 'eventslist': [], 'is_today': False},
101+
{'day': 20, 'event': 0, 'eventslist': [], 'is_today': False},
102+
{'date_string': '2016-8-21',
103+
'day': 21,
104+
'event': 1,
105+
'eventslist': [{'end': '11:30:00', 'start': '10:30:00', 'title': 'e21'}],
106+
'eventstring': u'Aug 21, 2016\n 10:30-11:30 e21',
107+
'is_today': False}],
108+
[{'day': 22, 'event': 0, 'eventslist': [], 'is_today': False},
109+
{'day': 23, 'event': 0, 'eventslist': [], 'is_today': False},
110+
{'day': 24, 'event': 0, 'eventslist': [], 'is_today': False},
111+
{'day': 25, 'event': 0, 'eventslist': [], 'is_today': False},
112+
{'day': 26, 'event': 0, 'eventslist': [], 'is_today': False},
113+
{'day': 27, 'event': 0, 'eventslist': [], 'is_today': False},
114+
{'day': 28, 'event': 0, 'eventslist': [], 'is_today': False}],
115+
[{'day': 29, 'event': 0, 'eventslist': [], 'is_today': False},
116+
{'date_string': '2016-8-30',
117+
'day': 30,
118+
'event': 1,
119+
'eventslist': [{'end': '11:30:00', 'start': '10:30:00', 'title': 'e30'}],
120+
'eventstring': u'Aug 30, 2016\n 10:30-11:30 e30',
121+
'is_today': False},
122+
{'day': 31, 'event': 0, 'eventslist': [], 'is_today': False},
123+
{'day': 0, 'event': 0, 'eventslist': []},
124+
{'day': 0, 'event': 0, 'eventslist': []},
125+
{'day': 0, 'event': 0, 'eventslist': []},
126+
{'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: 63 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
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')
24+
EVENT_INTERFACES = [
25+
'plone.event.interfaces.IEvent', 'Products.ATContentTypes.interfaces.event.IATEvent']
1826

1927

2028
class ICalendarTile(IPersistentCoverTile):
@@ -39,7 +47,6 @@ def __init__(self, context, request):
3947

4048
def _setup(self):
4149
context = aq_inner(self.context)
42-
self.calendar = getToolByName(context, 'portal_calendar')
4350
self._ts = getToolByName(context, 'translation_service')
4451
self.url_quote_plus = quote_plus
4552

@@ -56,31 +63,57 @@ def _setup(self):
5663

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

6079
def accepted_ct(self):
6180
"""Return an empty list as no content types are accepted."""
6281
return []
6382

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)
83+
def addEvents(self, day):
84+
catalog = api.portal.get_tool('portal_catalog')
85+
start = DateTime(self.year, self.month, day['day'])
86+
end = start + 1
87+
query = dict(
88+
object_provides=EVENT_INTERFACES, review_state='published',
89+
start={'query': (start, end), 'range': 'min:max'}, sort_on='start')
90+
for brain in catalog(**query):
91+
day['event'] += 1
92+
day['date_string'] = '{0}-{1}-{2}'.format(self.year, self.month, day['day'])
93+
if 'eventslist' not in day:
94+
day['eventslist'] = []
95+
event = dict(
96+
start=brain.start.Time(), end=brain.end.Time(), title=brain.Title or brain.id)
97+
day['eventslist'].append(event)
98+
if 'eventstring' not in day:
99+
localized_date = self._ts.ulocalized_time(
100+
start, context=self.context, request=self.request)
101+
day['eventstring'] = localized_date
102+
day['eventstring'] += '\n {0}'.format(self.getEventString(event))
103+
return day
83104

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

86119
def getEventString(self, event):
@@ -100,22 +133,12 @@ def getEventString(self, event):
100133
return eventstring
101134

102135
def getYearAndMonthToDisplay(self):
103-
session = None
104136
request = self.request
105137

106138
# First priority goes to the data in the REQUEST
107139
year = request.get('year', None)
108140
month = request.get('month', None)
109141

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-
119142
# Last resort to today
120143
if not year:
121144
year = self.now[0]
@@ -129,11 +152,6 @@ def getYearAndMonthToDisplay(self):
129152
except (TypeError, ValueError):
130153
year, month = self.now[:2]
131154

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-
137155
# Finally return the results
138156
return year, month
139157

@@ -153,12 +171,12 @@ def getNextMonth(self, year, month):
153171

154172
def getWeekdays(self):
155173
"""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')))
161174

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

164182
def isToday(self, day):
@@ -169,11 +187,13 @@ def isToday(self, day):
169187
self.now[2] == day and self.now[1] == self.month and self.now[0] == self.year)
170188

171189
def getReviewStateString(self):
172-
states = self.calendar.getCalendarStates()
190+
states = ['published']
173191
return ''.join(map(lambda x: 'review_state={0}&amp;'.format(self.url_quote_plus(x)), states))
174192

175193
def getEventTypes(self):
176-
types = self.calendar.getCalendarTypes()
194+
catalog = api.portal.get_tool('portal_catalog')
195+
query = dict(object_provides=EVENT_INTERFACES)
196+
types = set([b.portal_type for b in catalog(**query)])
177197
return ''.join(map(lambda x: 'Type={0}&amp;'.format(self.url_quote_plus(x)), types))
178198

179199
def getQueryString(self):

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)