Reorganize filters

Related to #33 and #372.
This commit is contained in:
Guillaume Ayoub 2016-05-06 17:53:02 +02:00
parent 2f97d7d1e1
commit a28df4dd4b
2 changed files with 235 additions and 13 deletions

View file

@ -117,6 +117,108 @@ def _href(collection, href):
href.lstrip("/"))
def _comp_match(item, filter_, scope="collection"):
"""Check whether the ``item`` matches the comp ``filter_``.
If ``scope`` is ``"collection"``, the filter is applied on the
item's collection. Otherwise, it's applied on the item.
See rfc4791-9.7.1.
"""
filter_length = len(filter_)
if scope == "collection":
tag = item.collection.get_meta("tag")
else:
for component in item.components():
if component.name in ("VTODO", "VEVENT", "VJOURNAL"):
tag = component.name
if filter_length == 0:
# Point #1 of rfc4791-9.7.1
return filter_.get("name") == tag
else:
if filter_length == 1:
if filter_[0].tag == _tag("C", "is-not-defined"):
# Point #2 of rfc4791-9.7.1
return filter_.get("name") != tag
if filter_[0].tag == _tag("C", "time-range"):
# Point #3 of rfc4791-9.7.1
if not _time_range_match(item, filter_[0]):
return False
filter_.remove(filter_[0])
# Point #4 of rfc4791-9.7.1
return all(
_prop_match(item, child) if child.tag == _tag("C", "prop-filter")
else _comp_match(item, child, scope="component")
for child in filter_)
def _prop_match(item, filter_):
"""Check whether the ``item`` matches the prop ``filter_``.
See rfc4791-9.7.2 and rfc6352-10.5.1.
"""
filter_length = len(filter_)
if item.collection.get_meta("tag") == "VCALENDAR":
for component in item.components():
if component.name in ("VTODO", "VEVENT", "VJOURNAL"):
vobject_item = component
else:
vobject_item = item.item
if filter_length == 0:
# Point #1 of rfc4791-9.7.2
return filter_.get("name").lower() in vobject_item.contents
else:
if filter_length == 1:
if filter_[0].tag == _tag("C", "is-not-defined"):
# Point #2 of rfc4791-9.7.2
return filter_.get("name").lower() not in vobject_item.contents
if filter_[0].tag == _tag("C", "time-range"):
# Point #3 of rfc4791-9.7.2
if not _time_range_match(item, filter_[0]):
return False
filter_.remove(filter_[0])
elif filter_[0].tag == _tag("C", "text-match"):
# Point #4 of rfc4791-9.7.2
if not _text_match(item, filter_[0]):
return False
filter_.remove(filter_[0])
return all(
_param_filter_match(item, param_filter)
for param_filter in filter_)
def _time_range_match(item, _filter):
"""Check whether the ``item`` matches the time-range ``filter_``.
See rfc4791-9.9.
"""
# TODO: implement this
return True
def _text_match(item, _filter):
"""Check whether the ``item`` matches the text-match ``filter_``.
See rfc4791-9.7.3.
"""
# TODO: implement this
return True
def _param_filter_match(item, _filter):
"""Check whether the ``item`` matches the param-filter ``filter_``.
See rfc4791-9.7.3.
"""
# TODO: implement this
return True
def name_from_path(path, collection):
"""Return Radicale item name from ``path``."""
collection_parts = collection.path.strip("/").split("/")
@ -491,16 +593,11 @@ def report(path, xml_request, collection):
hreferences.add(href_path[len(base_prefix) - 1:])
else:
hreferences = (path,)
# TODO: handle other filters
# TODO: handle the nested comp-filters correctly
# Read rfc4791-9.7.1 for info
tag_filters = set(
element.get("name").upper() for element
in root.findall(".//%s" % _tag("C", "comp-filter")))
tag_filters.discard("VCALENDAR")
filters = (
root.findall(".//%s" % _tag("C", "filter")) +
root.findall(".//%s" % _tag("CR", "filter")))
else:
hreferences = ()
tag_filters = set()
hreferences = filters = ()
# Writing answer
multistatus = ET.Element(_tag("D", "multistatus"))
@ -526,10 +623,12 @@ def report(path, xml_request, collection):
items = [collection.get(href) for href, etag in collection.list()]
for item in items:
if (tag_filters and
item.name not in tag_filters and
not {tag.upper() for tag in item.contents} & tag_filters):
continue
if filters:
match = (
_comp_match if collection.get_meta("tag") == "VCALENDAR"
else _prop_match)
if not all(match(item, filter_[0]) for filter_ in filters):
continue
found_props = []
not_found_props = []