Allow for meeting to be scheduled every 4 weeks.
This allows for by weekly meetings to be run at alternate times. Change-Id: Ief437e53719c123399de8874469ef16540d3b3fd Signed-off-by: Graham Hayes <gr@ham.ie>
This commit is contained in:
parent
2bc859072f
commit
3150c1a59a
19
meetings/example3.yaml
Normal file
19
meetings/example3.yaml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
project: Example alternating quadweekly meeting
|
||||||
|
agenda_url: http://agenda.com/
|
||||||
|
project_url: http://project.com
|
||||||
|
schedule:
|
||||||
|
- time: '1700'
|
||||||
|
duration: 45
|
||||||
|
start_date: 20150801
|
||||||
|
day: Thursday
|
||||||
|
irc: openstack-meeting
|
||||||
|
frequency: quadweekly
|
||||||
|
- time: '600'
|
||||||
|
duration: 45
|
||||||
|
start_date: 20150801
|
||||||
|
day: Thursday
|
||||||
|
irc: openstack-meeting
|
||||||
|
frequency: quadweekly-alternate
|
||||||
|
chair: John Doe
|
||||||
|
description: >
|
||||||
|
quadweekly
|
@ -136,13 +136,27 @@ class Schedule(object):
|
|||||||
|
|
||||||
def conflicts(self, other):
|
def conflicts(self, other):
|
||||||
"""Checks for conflicting schedules."""
|
"""Checks for conflicting schedules."""
|
||||||
alternating = set(['biweekly-odd', 'biweekly-even'])
|
|
||||||
|
def _non_weekly_conflict_detection(self, other):
|
||||||
|
week = {
|
||||||
|
'weekly': set([0, 1, 2, 3]),
|
||||||
|
'biweekly-even': set([0, 2]),
|
||||||
|
'biweekly-odd': set([1, 3]),
|
||||||
|
'quadweekly': set([0]),
|
||||||
|
'quadweekly-week-1': set([1]),
|
||||||
|
'quadweekly-week-2': set([2]),
|
||||||
|
'quadweekly-week-3': set([3]),
|
||||||
|
'quadweekly-alternate': set([2]),
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(week[self.freq].intersection(week[other.freq])) > 0
|
||||||
|
|
||||||
# NOTE(tonyb): .meeting_start also includes the day of the week. So no
|
# NOTE(tonyb): .meeting_start also includes the day of the week. So no
|
||||||
# need to check .day explictly
|
# need to check .day explictly
|
||||||
return ((self.irc == other.irc) and
|
return ((self.irc == other.irc) and
|
||||||
((self.meeting_start < other.meeting_end) and
|
((self.meeting_start < other.meeting_end) and
|
||||||
(other.meeting_start < self.meeting_end)) and
|
(other.meeting_start < self.meeting_end)) and
|
||||||
(set([self.freq, other.freq]) != alternating))
|
_non_weekly_conflict_detection(self, other))
|
||||||
|
|
||||||
|
|
||||||
class Meeting(object):
|
class Meeting(object):
|
||||||
|
@ -78,6 +78,34 @@ class BiWeeklyRecurrence(object):
|
|||||||
return "Every two weeks (on %s weeks)" % self.style
|
return "Every two weeks (on %s weeks)" % self.style
|
||||||
|
|
||||||
|
|
||||||
|
class QuadWeeklyRecurrence(object):
|
||||||
|
"""Meetings occuring every 4 weeks.
|
||||||
|
|
||||||
|
A week number can be supplied to offset meetings
|
||||||
|
"""
|
||||||
|
def __init__(self, week=0):
|
||||||
|
self.week = week
|
||||||
|
|
||||||
|
def next_occurence(self, current_date, day):
|
||||||
|
"""Calculate the next biweekly meeting.
|
||||||
|
|
||||||
|
:param current_date: the current date
|
||||||
|
:param day: scheduled day of the meeting
|
||||||
|
:returns: datetime object of next meeting
|
||||||
|
"""
|
||||||
|
nextweek_day = WeeklyRecurrence().next_occurence(current_date, day)
|
||||||
|
if nextweek_day.isocalendar()[1] % 4 == self.week:
|
||||||
|
return nextweek_day
|
||||||
|
# If week doesn't match rule, skip one week
|
||||||
|
return self.next_occurence(nextweek_day + datetime.timedelta(7), day)
|
||||||
|
|
||||||
|
def rrule(self):
|
||||||
|
return {'freq': 'weekly', 'interval': 4}
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Every four weeks" % self.style
|
||||||
|
|
||||||
|
|
||||||
class AdhocRecurrence(object):
|
class AdhocRecurrence(object):
|
||||||
"""Meetings occuring as needed.
|
"""Meetings occuring as needed.
|
||||||
|
|
||||||
@ -105,5 +133,10 @@ supported_recurrences = {
|
|||||||
'weekly': WeeklyRecurrence(),
|
'weekly': WeeklyRecurrence(),
|
||||||
'biweekly-odd': BiWeeklyRecurrence(style='odd'),
|
'biweekly-odd': BiWeeklyRecurrence(style='odd'),
|
||||||
'biweekly-even': BiWeeklyRecurrence(),
|
'biweekly-even': BiWeeklyRecurrence(),
|
||||||
|
'quadweekly': QuadWeeklyRecurrence(week=0),
|
||||||
|
'quadweekly-week-1': QuadWeeklyRecurrence(week=1),
|
||||||
|
'quadweekly-week-2': QuadWeeklyRecurrence(week=2),
|
||||||
|
'quadweekly-week-3': QuadWeeklyRecurrence(week=3),
|
||||||
|
'quadweekly-alternate': QuadWeeklyRecurrence(week=2),
|
||||||
'adhoc': AdhocRecurrence(),
|
'adhoc': AdhocRecurrence(),
|
||||||
}
|
}
|
||||||
|
@ -272,3 +272,93 @@ chair: Shannon Stacker
|
|||||||
description: >
|
description: >
|
||||||
Adhoc random meeting for Subteam project.
|
Adhoc random meeting for Subteam project.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
QUADWEEKLY_MEETING_ALTERNATING = """
|
||||||
|
project: OpenStack Random Meeting
|
||||||
|
agenda_url: http://agenda.com/
|
||||||
|
project_url: http://project.com
|
||||||
|
schedule:
|
||||||
|
- time: '2200'
|
||||||
|
day: Wednesday
|
||||||
|
irc: openstack-meeting
|
||||||
|
frequency: quadweekly
|
||||||
|
- time: '600'
|
||||||
|
duration: 45
|
||||||
|
start_date: 20150801
|
||||||
|
day: Thursday
|
||||||
|
irc: openstack-meeting
|
||||||
|
frequency: quadweekly-alternate
|
||||||
|
chair: John Doe
|
||||||
|
description: >
|
||||||
|
Example alternating quadweekly meeting
|
||||||
|
"""
|
||||||
|
|
||||||
|
QUADWEEKLY_MEETING = """
|
||||||
|
project: OpenStack Random Meeting
|
||||||
|
agenda_url: http://agenda.com/
|
||||||
|
project_url: http://project.com
|
||||||
|
schedule:
|
||||||
|
- time: '2200'
|
||||||
|
day: Wednesday
|
||||||
|
irc: openstack-meeting
|
||||||
|
frequency: quadweekly
|
||||||
|
chair: John Doe
|
||||||
|
description: >
|
||||||
|
Example Quadweekly meeting
|
||||||
|
"""
|
||||||
|
|
||||||
|
QUADWEEKLY_MEETING_WEEK_1 = """
|
||||||
|
project: OpenStack Random Meeting
|
||||||
|
agenda_url: http://agenda.com/
|
||||||
|
project_url: http://project.com
|
||||||
|
schedule:
|
||||||
|
- time: '2200'
|
||||||
|
day: Wednesday
|
||||||
|
irc: openstack-meeting
|
||||||
|
frequency: quadweekly-week-1
|
||||||
|
chair: John Doe
|
||||||
|
description: >
|
||||||
|
Example Quadweekly meeting on week 1
|
||||||
|
"""
|
||||||
|
|
||||||
|
QUADWEEKLY_MEETING_WEEK_2 = """
|
||||||
|
project: OpenStack Random Meeting
|
||||||
|
agenda_url: http://agenda.com/
|
||||||
|
project_url: http://project.com
|
||||||
|
schedule:
|
||||||
|
- time: '2200'
|
||||||
|
day: Wednesday
|
||||||
|
irc: openstack-meeting
|
||||||
|
frequency: quadweekly-week-2
|
||||||
|
chair: John Doe
|
||||||
|
description: >
|
||||||
|
Example Quadweekly meeting on week 2
|
||||||
|
"""
|
||||||
|
|
||||||
|
QUADWEEKLY_MEETING_WEEK_3 = """
|
||||||
|
project: OpenStack Random Meeting
|
||||||
|
agenda_url: http://agenda.com/
|
||||||
|
project_url: http://project.com
|
||||||
|
schedule:
|
||||||
|
- time: '2200'
|
||||||
|
day: Wednesday
|
||||||
|
irc: openstack-meeting
|
||||||
|
frequency: quadweekly-week-3
|
||||||
|
chair: John Doe
|
||||||
|
description: >
|
||||||
|
Example Quadweekly meeting on week 3
|
||||||
|
"""
|
||||||
|
|
||||||
|
QUADWEEKLY_MEETING_ALTERNATE = """
|
||||||
|
project: OpenStack Random Meeting
|
||||||
|
agenda_url: http://agenda.com/
|
||||||
|
project_url: http://project.com
|
||||||
|
schedule:
|
||||||
|
- time: '2200'
|
||||||
|
day: Wednesday
|
||||||
|
irc: openstack-meeting
|
||||||
|
frequency: quadweekly-alternate
|
||||||
|
chair: John Doe
|
||||||
|
description: >
|
||||||
|
Example Quadweekly Alternate meeting
|
||||||
|
"""
|
||||||
|
@ -78,6 +78,77 @@ class MeetingTestCase(unittest.TestCase):
|
|||||||
sample_data.MEETING_MONDAY_LATE,
|
sample_data.MEETING_MONDAY_LATE,
|
||||||
sample_data.MEETING_TUESDAY_EARLY)
|
sample_data.MEETING_TUESDAY_EARLY)
|
||||||
|
|
||||||
|
def test_quadweekly_conflicts(self):
|
||||||
|
self.should_be_conflicting(
|
||||||
|
sample_data.BIWEEKLY_EVEN_MEETING,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_ALTERNATING)
|
||||||
|
self.should_be_conflicting(
|
||||||
|
sample_data.BIWEEKLY_EVEN_MEETING,
|
||||||
|
sample_data.QUADWEEKLY_MEETING)
|
||||||
|
self.should_be_conflicting(
|
||||||
|
sample_data.BIWEEKLY_EVEN_MEETING,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_ALTERNATE)
|
||||||
|
self.should_be_conflicting(
|
||||||
|
sample_data.BIWEEKLY_EVEN_MEETING,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_2)
|
||||||
|
self.should_not_conflict(
|
||||||
|
sample_data.BIWEEKLY_EVEN_MEETING,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_1)
|
||||||
|
self.should_not_conflict(
|
||||||
|
sample_data.BIWEEKLY_EVEN_MEETING,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_3)
|
||||||
|
self.should_be_conflicting(
|
||||||
|
sample_data.BIWEEKLY_EVEN_MEETING,
|
||||||
|
sample_data.QUADWEEKLY_MEETING)
|
||||||
|
self.should_be_conflicting(
|
||||||
|
sample_data.BIWEEKLY_ODD_MEETING,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_1)
|
||||||
|
self.should_be_conflicting(
|
||||||
|
sample_data.BIWEEKLY_ODD_MEETING,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_3)
|
||||||
|
self.should_not_conflict(
|
||||||
|
sample_data.BIWEEKLY_ODD_MEETING,
|
||||||
|
sample_data.QUADWEEKLY_MEETING)
|
||||||
|
self.should_not_conflict(
|
||||||
|
sample_data.BIWEEKLY_ODD_MEETING,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_2)
|
||||||
|
self.should_not_conflict(
|
||||||
|
sample_data.BIWEEKLY_ODD_MEETING,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_ALTERNATING)
|
||||||
|
self.should_not_conflict(
|
||||||
|
sample_data.QUADWEEKLY_MEETING,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_1)
|
||||||
|
self.should_not_conflict(
|
||||||
|
sample_data.QUADWEEKLY_MEETING,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_2)
|
||||||
|
self.should_not_conflict(
|
||||||
|
sample_data.QUADWEEKLY_MEETING,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_3)
|
||||||
|
self.should_not_conflict(
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_1,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_2)
|
||||||
|
self.should_not_conflict(
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_1,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_3)
|
||||||
|
self.should_not_conflict(
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_2,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_3)
|
||||||
|
self.should_be_conflicting(
|
||||||
|
sample_data.QUADWEEKLY_MEETING,
|
||||||
|
sample_data.QUADWEEKLY_MEETING)
|
||||||
|
self.should_be_conflicting(
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_1,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_1)
|
||||||
|
self.should_be_conflicting(
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_2,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_2)
|
||||||
|
self.should_be_conflicting(
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_3,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_3)
|
||||||
|
self.should_be_conflicting(
|
||||||
|
sample_data.QUADWEEKLY_MEETING_WEEK_2,
|
||||||
|
sample_data.QUADWEEKLY_MEETING_ALTERNATE)
|
||||||
|
|
||||||
def test_meeting_duration(self):
|
def test_meeting_duration(self):
|
||||||
m = meeting.load_meetings(sample_data.MEETING_WITH_DURATION)[0]
|
m = meeting.load_meetings(sample_data.MEETING_WITH_DURATION)[0]
|
||||||
self.assertEqual(30, m.schedules[0].duration)
|
self.assertEqual(30, m.schedules[0].duration)
|
||||||
|
@ -38,6 +38,26 @@ class RecurrenceTestCase(unittest.TestCase):
|
|||||||
datetime.datetime(2014, 10, 15, 2, 47, 28, 832666),
|
datetime.datetime(2014, 10, 15, 2, 47, 28, 832666),
|
||||||
self.next_meeting(recurrence.BiWeeklyRecurrence(style='even')))
|
self.next_meeting(recurrence.BiWeeklyRecurrence(style='even')))
|
||||||
|
|
||||||
|
def test_next_quadweekly_week_0(self):
|
||||||
|
self.assertEqual(
|
||||||
|
datetime.datetime(2014, 10, 29, 2, 47, 28, 832666),
|
||||||
|
self.next_meeting(recurrence.QuadWeeklyRecurrence(week=0)))
|
||||||
|
|
||||||
|
def test_next_quadweekly_week_1(self):
|
||||||
|
self.assertEqual(
|
||||||
|
datetime.datetime(2014, 10, 8, 2, 47, 28, 832666),
|
||||||
|
self.next_meeting(recurrence.QuadWeeklyRecurrence(week=1)))
|
||||||
|
|
||||||
|
def test_next_quadweekly_week_2(self):
|
||||||
|
self.assertEqual(
|
||||||
|
datetime.datetime(2014, 10, 15, 2, 47, 28, 832666),
|
||||||
|
self.next_meeting(recurrence.QuadWeeklyRecurrence(week=2)))
|
||||||
|
|
||||||
|
def test_next_quadweekly_week_3(self):
|
||||||
|
self.assertEqual(
|
||||||
|
datetime.datetime(2014, 10, 22, 2, 47, 28, 832666),
|
||||||
|
self.next_meeting(recurrence.QuadWeeklyRecurrence(week=3)))
|
||||||
|
|
||||||
def test_next_adhoc(self):
|
def test_next_adhoc(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
None,
|
None,
|
||||||
|
Loading…
Reference in New Issue
Block a user