Skip to content

Commit

Permalink
Support for adding alarms (without having to manually create the ical…
Browse files Browse the repository at this point in the history
…endar data) to events. Partial fix for #132
  • Loading branch information
tobixen committed Oct 24, 2022
1 parent 86e85f9 commit dddb5f4
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 8 deletions.
24 changes: 20 additions & 4 deletions caldav/lib/vcal.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import re
import uuid

import icalendar
from caldav.lib.python_utilities import to_local
from caldav.lib.python_utilities import to_wire

Expand Down Expand Up @@ -79,13 +80,15 @@ def fix(event):

## sorry for being english-language-euro-centric ... fits rather perfectly as default language for me :-)
def create_ical(ical_fragment=None, objtype=None, language="en_DK", **props):
"""
I somehow feel this fits more into the icalendar library than here
"""Creates some icalendar based on properties given as parameters.
It basically creates an icalendar object with all the boilerplate,
some sensible defaults, the properties given and returns it as a
string.
TODO: timezones not supported so far
"""
## late import, icalendar is not an explicit requirement for v0.x of the caldav library.
## (perhaps I should change my position on that soon)
import icalendar

ical_fragment = to_wire(ical_fragment)
if not ical_fragment or not re.search(b"^BEGIN:V", ical_fragment, re.MULTILINE):
my_instance = icalendar.Calendar()
Expand All @@ -107,18 +110,31 @@ def create_ical(ical_fragment=None, objtype=None, language="en_DK", **props):
my_instance = icalendar.Calendar.from_ical(ical_fragment)
component = my_instance.subcomponents[0]
ical_fragment = None
alarm = {}
for prop in props:
if props[prop] is not None:
if prop in ("child", "parent"):
for value in props[prop]:
component.add(
"related-to", props[prop], parameters={"rel-type": prop.upper()}
)
elif prop.startswith("alarm_"):
alarm[prop[6:]] = props[prop]
else:
component.add(prop, props[prop])
if alarm:
add_alarm(my_instance, alarm)
ret = my_instance.to_ical()
if ical_fragment and ical_fragment.strip():
ret = re.sub(
b"^END:V", ical_fragment.strip() + b"\nEND:V", ret, flags=re.MULTILINE
)
return ret


def add_alarm(ical, alarm):
ia = icalendar.Alarm()
for prop in alarm:
ia.add(prop, alarm[prop])
ical.subcomponents[0].add_component(ia)
return ical
9 changes: 5 additions & 4 deletions caldav/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,8 @@ def save_event(self, ical=None, no_overwrite=False, no_create=False, **ical_data
* ical - ical object (text)
* no_overwrite - existing calendar objects should not be overwritten
* no_create - don't create a new object, existing calendar objects should be updated
* ical_data - passed to lib.vcal.create_ical
* dt_start, dt_end, summary, etc - properties to be inserted into the icalendar object
* alarm_trigger, alarm_action, alarm_attach, etc - when given, one alarm will be added
"""
e = Event(
self.client,
Expand Down Expand Up @@ -1794,7 +1795,7 @@ def copy(self, keep_uid=False, new_parent=None):
id=self.id if keep_uid else str(uuid.uuid1()),
)
if not keep_uid:
obj.url = obj.generate_url()
obj.url = obj._generate_url()
return obj

def load(self):
Expand Down Expand Up @@ -1846,7 +1847,7 @@ def _find_id_path(self, id=None, path=None):
self.id = id

if path is None:
path = self.generate_url()
path = self._generate_url()
else:
path = self.parent.url.join(path)

Expand All @@ -1864,7 +1865,7 @@ def _create(self, data, id=None, path=None):
elif not (r.status in (204, 201)):
raise error.PutError(errmsg(r))

def generate_url(self):
def _generate_url(self):
## See https://github.com/python-caldav/caldav/issues/143 for the rationale behind double-quoting slashes
## TODO: should try to wrap my head around issues that arises when id contains weird characters. maybe it's
## better to generate a new uuid here, particularly if id is in some unexpected format.
Expand Down
12 changes: 12 additions & 0 deletions tests/test_caldav.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from collections import namedtuple
from datetime import date
from datetime import datetime
from datetime import timedelta

import pytest
import requests
Expand Down Expand Up @@ -776,6 +777,17 @@ def testCreateEvent(self):
events = c.events()
assert len(events) == len(existing_events) + 2

def testCreateAlarm(self):
c = self._fixCalendar()
ev = c.save_event(
dtstart=datetime(2015, 10, 10, 8, 7, 6),
summary="This is a test event",
dtend=datetime(2016, 10, 10, 9, 8, 7),
alarm_trigger=timedelta(minutes=-15),
alarm_action="AUDIO",
)
pass

def testCalendarByFullURL(self):
"""
ref private email, passing a full URL as cal_id works in 0.5.0 but
Expand Down

0 comments on commit dddb5f4

Please sign in to comment.