Skip to content

Commit

Permalink
if we cannot load an object using GET, try using REPORT and multiget.…
Browse files Browse the repository at this point in the history
… Updates #459
  • Loading branch information
tobixen committed Dec 12, 2024
1 parent 0837d46 commit 9d3e07e
Showing 1 changed file with 33 additions and 7 deletions.
40 changes: 33 additions & 7 deletions caldav/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ def _query(
expected_return_value is not None and ret.status != expected_return_value
) or ret.status >= 400:
## COMPATIBILITY HACK - see https://github.com/python-caldav/caldav/issues/309
## TODO: server quirks!
body = to_wire(body)
if (
ret.status == 500
Expand Down Expand Up @@ -946,7 +947,11 @@ def save(self):
self._create(id=self.id, name=self.name, **self.extra_init_options)
return self

def calendar_multiget(self, event_urls: Iterable[URL]) -> List["Event"]:
## TODO: this is missing test code.
## TODO: needs refactoring:
## Objects found may be Todo and Journal, not only Event.
## Replace the last lines with _request_report_build_resultlist method
def calendar_multiget(self, event_urls: Iterable[URL]) -> List[_CC]:
"""
get multiple events' data
@author [email protected]
Expand Down Expand Up @@ -1078,15 +1083,15 @@ def date_search(

return objects

## TODO: this logic has been partly duplicated in calendar_multiget, but
## the code there is much more readable and condensed than this.
## Can code below be refactored?
def _request_report_build_resultlist(
self, xml, comp_class=None, props=None, no_calendardata=False
):
"""
Takes some input XML, does a report query on a calendar object
and returns the resource objects found.
TODO: similar code is duplicated many places, we ought to do even more code
refactoring
"""
matches = []
if props is None:
Expand Down Expand Up @@ -1122,7 +1127,6 @@ def _request_report_build_resultlist(
props=pdata,
)
)

return (response, matches)

def search(
Expand Down Expand Up @@ -1163,7 +1167,7 @@ def search(
unless the next parameter is set ...
* include_completed - include completed tasks
* event - sets comp_class to event
* text attribute search parameters: category, uid, summary, omment,
* text attribute search parameters: category, uid, summary, comment,
description, location, status
* no-category, no-summary, etc ... search for objects that does not
have those attributes. TODO: WRITE TEST CODE!
Expand Down Expand Up @@ -2338,6 +2342,8 @@ def copy(self, keep_uid: bool = False, new_parent: Optional[Any] = None) -> Self
obj.url = self.url
return obj

## TODO: move get-logics to a load_by_get method.
## The load method should deal with "server quirks".
def load(self, only_if_unloaded: bool = False) -> Self:
"""
(Re)load the object from the caldav server.
Expand All @@ -2351,7 +2357,10 @@ def load(self, only_if_unloaded: bool = False) -> Self:
if self.client is None:
raise ValueError("Unexpected value None for self.client")

r = self.client.request(str(self.url))
try:
r = self.client.request(str(self.url))
except:
return self.load_by_multiget()
if r.status == 404:
raise error.NotFoundError(errmsg(r))
self.data = vcal.fix(r.raw)
Expand All @@ -2361,6 +2370,23 @@ def load(self, only_if_unloaded: bool = False) -> Self:
self.props[cdav.ScheduleTag.tag] = r.headers["Schedule-Tag"]
return self

def load_by_multiget(self) -> Self:
"""
Some servers do not accept a GET, but we can still do a REPORT
with a multiget query
"""
error.assert_(self.url)
href = self.url.path
prop = dav.Prop() + cdav.CalendarData()
root = cdav.CalendarMultiGet() + prop + dav.Href(value=href)
response = self.parent._query(root, 1, "report")
results = response.expand_simple_props([cdav.CalendarData()])
error.assert_(len(results) == 1)
data = results[href][cdav.CalendarData.tag]
error.assert_(data)
self.data = data
return self

## TODO: self.id should either always be available or never
def _find_id_path(self, id=None, path=None) -> None:
"""
Expand Down

0 comments on commit 9d3e07e

Please sign in to comment.