From bd7641699e9502d2a663d1703c6b0d46e5b75a36 Mon Sep 17 00:00:00 2001 From: Unrud Date: Wed, 3 Aug 2016 14:45:52 +0200 Subject: [PATCH] Atomic PROPPATCH --- radicale/__init__.py | 8 +++----- radicale/storage.py | 25 +++++++++++-------------- radicale/xmlutils.py | 12 +++++++----- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/radicale/__init__.py b/radicale/__init__.py index 8cee0de..dde8890 100644 --- a/radicale/__init__.py +++ b/radicale/__init__.py @@ -484,8 +484,7 @@ class Application: # timezone = props.get("C:calendar-timezone") collection = self.Collection.create_collection( environ["PATH_INFO"], tag="VCALENDAR") - for key, value in props.items(): - collection.set_meta(key, value) + collection.set_meta(props) return client.CREATED, {}, None def do_MKCOL(self, environ, read_collections, write_collections, content, @@ -498,8 +497,7 @@ class Application: props = xmlutils.props_from_request(content) collection = self.Collection.create_collection(environ["PATH_INFO"]) - for key, value in props.items(): - collection.set_meta(key, value) + collection.set_meta(props) return client.CREATED, {}, None def do_MOVE(self, environ, read_collections, write_collections, content, @@ -582,7 +580,7 @@ class Application: tags = {value: key for key, value in storage.MIMETYPES.items()} tag = tags.get(content_type.split(";")[0]) if tag: - collection.set_meta("tag", tag) + collection.set_meta({"tag": tag}) headers = {} item_name = xmlutils.name_from_path(environ["PATH_INFO"], collection) item = collection.get(item_name) diff --git a/radicale/storage.py b/radicale/storage.py index 10cffc1..feee9e5 100644 --- a/radicale/storage.py +++ b/radicale/storage.py @@ -298,8 +298,8 @@ class BaseCollection: """Get metadata value for collection.""" raise NotImplementedError - def set_meta(self, key, value): - """Set metadata value for collection.""" + def set_meta(self, props): + """Set metadata values for collection.""" raise NotImplementedError @property @@ -419,7 +419,7 @@ class Collection(BaseCollection): tag = collection[0].name if tag == "VCALENDAR": - self.set_meta("tag", "VCALENDAR") + self.set_meta({"tag": "VCALENDAR"}) if collection: collection, = collection items = [] @@ -440,7 +440,7 @@ class Collection(BaseCollection): self._find_available_file_name(), new_collection) elif tag == "VCARD": - self.set_meta("tag", "VADDRESSBOOK") + self.set_meta({"tag": "VADDRESSBOOK"}) if collection: for card in collection: self.upload(self._find_available_file_name(), card) @@ -542,19 +542,16 @@ class Collection(BaseCollection): with open(self._props_path, encoding=self.storage_encoding) as prop: return json.load(prop).get(key) - def set_meta(self, key, value): - properties = {} + def set_meta(self, props): if os.path.exists(self._props_path): with open(self._props_path, encoding=self.storage_encoding) as prop: - properties.update(json.load(prop)) - - if value: - properties[key] = value - else: - properties.pop(key, None) - + old_props = json.load(prop) + old_props.update(props) + props = old_props + # filter empty entries + props = {k:v for k,v in props.items() if v} with self._atomic_write(self._props_path, "w+") as prop: - json.dump(properties, prop) + json.dump(props, prop) @property def last_modified(self): diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index 9134102..0682a96 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -757,12 +757,14 @@ def proppatch(path, xml_request, collection): href.text = _href(collection, path) response.append(href) - for short_name, value in props_to_set.items(): - collection.set_meta(short_name, value) - _add_propstat_to(response, short_name, 200) - + # Merge props_to_set and props_to_remove for short_name in props_to_remove: - collection.set_meta(short_name, "") + props_to_set[short_name] = "" + + # Set/Delete props in one atomic operation + collection.set_meta(props_to_set) + + for short_name in props_to_set: _add_propstat_to(response, short_name, 200) return _pretty_xml(multistatus)