Skip to content

Commit 706ad77

Browse files
committed
Support for adding alarms (without having to manually create the icalendar data) to events. Partial fix for #132
1 parent 1028f12 commit 706ad77

3 files changed

Lines changed: 38 additions & 6 deletions

File tree

caldav/lib/vcal.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import uuid
66

77
import icalendar
8+
from caldav.lib.python_utilities import to_local
89
from caldav.lib.python_utilities import to_normal_str
10+
from caldav.lib.python_utilities import to_wire
911

1012
## Fixups to the icalendar data to work around compatbility issues.
1113

@@ -81,8 +83,12 @@ def fix(event):
8183

8284
## sorry for being english-language-euro-centric ... fits rather perfectly as default language for me :-)
8385
def create_ical(ical_fragment=None, objtype=None, language="en_DK", **props):
84-
"""
85-
I somehow feel this fits more into the icalendar library than here
86+
"""Creates some icalendar based on properties given as parameters.
87+
It basically creates an icalendar object with all the boilerplate,
88+
some sensible defaults, the properties given and returns it as a
89+
string.
90+
91+
TODO: timezones not supported so far
8692
"""
8793
ical_fragment = to_normal_str(ical_fragment)
8894
if not ical_fragment or not re.search("^BEGIN:V", ical_fragment, re.MULTILINE):
@@ -105,18 +111,31 @@ def create_ical(ical_fragment=None, objtype=None, language="en_DK", **props):
105111
my_instance = icalendar.Calendar.from_ical(ical_fragment)
106112
component = my_instance.subcomponents[0]
107113
ical_fragment = None
114+
alarm = {}
108115
for prop in props:
109116
if props[prop] is not None:
110117
if prop in ("child", "parent"):
111118
for value in props[prop]:
112119
component.add(
113120
"related-to", props[prop], parameters={"rel-type": prop.upper()}
114121
)
122+
elif prop.startswith("alarm_"):
123+
alarm[prop[6:]] = props[prop]
115124
else:
116125
component.add(prop, props[prop])
126+
if alarm:
127+
add_alarm(my_instance, alarm)
117128
ret = to_normal_str(my_instance.to_ical())
118129
if ical_fragment and ical_fragment.strip():
119130
ret = re.sub(
120131
"^END:V", ical_fragment.strip() + "\nEND:V", ret, flags=re.MULTILINE
121132
)
122133
return ret
134+
135+
136+
def add_alarm(ical, alarm):
137+
ia = icalendar.Alarm()
138+
for prop in alarm:
139+
ia.add(prop, alarm[prop])
140+
ical.subcomponents[0].add_component(ia)
141+
return ical

caldav/objects.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,8 @@ def save_event(self, ical=None, no_overwrite=False, no_create=False, **ical_data
704704
* ical - ical object (text)
705705
* no_overwrite - existing calendar objects should not be overwritten
706706
* no_create - don't create a new object, existing calendar objects should be updated
707-
* ical_data - passed to lib.vcal.create_ical
707+
* dt_start, dt_end, summary, etc - properties to be inserted into the icalendar object
708+
* alarm_trigger, alarm_action, alarm_attach, etc - when given, one alarm will be added
708709
"""
709710
e = Event(
710711
self.client,
@@ -1906,7 +1907,7 @@ def copy(self, keep_uid=False, new_parent=None):
19061907
id=self.id if keep_uid else str(uuid.uuid1()),
19071908
)
19081909
if new_parent or not keep_uid:
1909-
obj.url = obj.generate_url()
1910+
obj.url = obj._generate_url()
19101911
else:
19111912
obj.url = self.url
19121913
return obj
@@ -1963,7 +1964,7 @@ def _find_id_path(self, id=None, path=None):
19631964
error.assert_(x.get("UID", None) == self.id)
19641965

19651966
if path is None:
1966-
path = self.generate_url()
1967+
path = self._generate_url()
19671968
else:
19681969
path = self.parent.url.join(path)
19691970

@@ -1992,7 +1993,7 @@ def _create(self, id=None, path=None, retry_on_failure=True):
19921993
self._find_id_path(id=id, path=path)
19931994
self._put()
19941995

1995-
def generate_url(self):
1996+
def _generate_url(self):
19961997
## See https://github.com/python-caldav/caldav/issues/143 for the rationale behind double-quoting slashes
19971998
## TODO: should try to wrap my head around issues that arises when id contains weird characters. maybe it's
19981999
## better to generate a new uuid here, particularly if id is in some unexpected format.

tests/test_caldav.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from collections import namedtuple
1818
from datetime import date
1919
from datetime import datetime
20+
from datetime import timedelta
2021

2122
import pytest
2223
import requests
@@ -766,6 +767,17 @@ def testCreateEvent(self):
766767
events = c.events()
767768
assert len(events) == len(existing_events) + 2
768769

770+
def testCreateAlarm(self):
771+
c = self._fixCalendar()
772+
ev = c.save_event(
773+
dtstart=datetime(2015, 10, 10, 8, 7, 6),
774+
summary="This is a test event",
775+
dtend=datetime(2016, 10, 10, 9, 8, 7),
776+
alarm_trigger=timedelta(minutes=-15),
777+
alarm_action="AUDIO",
778+
)
779+
pass
780+
769781
def testCalendarByFullURL(self):
770782
"""
771783
ref private email, passing a full URL as cal_id works in 0.5.0 but

0 commit comments

Comments
 (0)