Merge pull request #2033 from pbiering/sharing-bday-add-desc
Sharing bday add description, doc updates, bugfixes
This commit is contained in:
215
SHARING.md
215
SHARING.md
@@ -1,121 +1,29 @@
|
||||
|
||||
# Collection Sharing
|
||||
|
||||
Static collection sharing without permissions filter using soft-links (Unix-only) is supported since storage type `multifilesystem` was implemented, see (Wiki: Sharing Collections)[https://github.com/Kozea/Radicale/wiki/Sharing-Collections]
|
||||
Static collection sharing without permissions filter using soft-links (Unix-only) is supported since storage type `multifilesystem` was implemented, see [Wiki: Sharing Collections](https://github.com/Kozea/Radicale/wiki/Sharing-Collections)
|
||||
|
||||
With _3.7.0_ major extension was implemented using internal mapping configuration stored in a database and a management API.
|
||||
With _3.7.0_ major extension was implemented
|
||||
* added internal mapping with configuration stored in a database
|
||||
* added management API
|
||||
* WebUI extension using the management API
|
||||
|
||||
## Sharing Implementation
|
||||
|
||||
Implemenation of sharing collections is done in case entry exists in sharing database by replacing provided data on request and adjust if required data in responses.
|
||||
Implemenation of sharing collections is done by using a database to lookup the URI and in case entry exists by mapping to target URI and replacing provided data on request and adjust if required data in response.
|
||||
|
||||
Permissions are filtered by provided `Permissions`.
|
||||
|
||||
### CxDAV requests
|
||||
## Sharing Configuration
|
||||
|
||||
#### CxDav request "(DELETE|GET|HEAD|PUT)"
|
||||
|
||||
* Actions
|
||||
* map
|
||||
* Lookup by
|
||||
* `path` (provided in request)
|
||||
* `user` (authenticated)
|
||||
* Replace
|
||||
* `user` by `Owner`
|
||||
* `path` by `PathMapped`
|
||||
* Activate
|
||||
* `permissions_filter` by `Permissions`
|
||||
|
||||
#### CxDav request "REPORT"
|
||||
|
||||
* Actions
|
||||
* map
|
||||
* back-map response
|
||||
* Lookup by
|
||||
* `path` (provided in request)
|
||||
* `user` (authenticated)
|
||||
* Replace
|
||||
* `user` by `Owner`
|
||||
* `path` by `PathMapped`
|
||||
* Activate
|
||||
* `permissions_filter` by `Permissions`
|
||||
|
||||
#### CxDav request "PROPFIND" without HTTP_DEPTH=1
|
||||
|
||||
* Actions
|
||||
* map
|
||||
* back-map response
|
||||
* overwrite `Properties` if provided
|
||||
* Lookup by
|
||||
* `path` (provided in request)
|
||||
* `user` (authenticated)
|
||||
* Replace
|
||||
* `user` by `Owner`
|
||||
* `path` by `PathMapped`
|
||||
* Overlay
|
||||
* `Properties` if provided
|
||||
* Activate
|
||||
* `permissions_filter` by `Permissions`
|
||||
|
||||
#### CxDav request "PROPFIND" with HTTP_DEPTH=1
|
||||
|
||||
* Actions
|
||||
* extend list
|
||||
* Lookup for active shares for `user` in sharing database
|
||||
* Extend list if conditions are met
|
||||
* `permissions_filter` by `Permissions`
|
||||
|
||||
#### CxDav request "PROPPATCH"
|
||||
|
||||
* Actions
|
||||
* map
|
||||
* adjust properties of a collection
|
||||
* Lookup by
|
||||
* `path` (provided in request)
|
||||
* `user` (authenticated)
|
||||
* Replace
|
||||
* `user` by `Owner`
|
||||
* `path` by `PathMapped`
|
||||
* Activate
|
||||
* `permissions_filter` by `Permissions`
|
||||
* Depending on `permissions_filter`, global options and `Permissions`
|
||||
* adjust properties of collection
|
||||
* adjust whitelisted properties in `Properties` for overlay (see OVERLAY_PROPERTIES_WHITELIST)
|
||||
|
||||
#### CxDav request "(MKCALENDAR|MKCOL)"
|
||||
|
||||
* Action
|
||||
* check for conflicts
|
||||
* Lookup by
|
||||
* `user` (authenticated)
|
||||
* Verify for non-existence as `PathOrToken` in sharing database
|
||||
* `path` (provided in request)
|
||||
|
||||
#### CxDav request "(MOVE)"
|
||||
|
||||
* Action
|
||||
* map source
|
||||
* map destination
|
||||
* Lookup by
|
||||
* `path` (provided in request)
|
||||
* `user` (authenticated)
|
||||
* `to_path` (provided in request)
|
||||
* `to_user` (same as `user`)
|
||||
* Replace
|
||||
* `user` by `Owner` (of `path`)
|
||||
* `path` by `PathMapped` (of path)
|
||||
* `to_user` by `Owner` (of `to_path`)
|
||||
* `to_path` by `PathMapped` (of `to_path`)
|
||||
* Activate
|
||||
* `permissions_filter` by `Permissions` (of `to_path`)
|
||||
* `to_permissions_filter` by `Permissions` (of `to_path`)
|
||||
New section `[sharing]` controls sharing configuration, see [DOCUMENTATION:Sharing](DOCUMENTATION.md#sharing) for details
|
||||
|
||||
## Sharing Configuration Store
|
||||
|
||||
Types of supported sharing configuration:
|
||||
|
||||
* csv (_>= 3.7.0_)
|
||||
* files (_>= 3.7.0_)
|
||||
* *csv* (_>= 3.7.0_)
|
||||
* *files* (_>= 3.7.0_)
|
||||
|
||||
### Sharing Configuration Entry Data
|
||||
|
||||
@@ -152,6 +60,107 @@ If given, properties are stored in JSON format in CSV.
|
||||
|
||||
File-based configuration store is using encoded `PathOrToken` as filename for each config. File contains the data stored as "dict" in binary Python "pickle" format (same is also used for item cache files).
|
||||
|
||||
## Sharing Request Handling
|
||||
|
||||
### CxDAV requests
|
||||
|
||||
#### CxDav request "(DELETE|GET|HEAD|PUT)"
|
||||
|
||||
* Actions
|
||||
* map
|
||||
* Lookup by
|
||||
* `path` (provided in request)
|
||||
* `user` (authenticated)
|
||||
* Replace
|
||||
* `path` by `PathMapped`
|
||||
* `user` by `Owner`
|
||||
* Activate
|
||||
* `permissions_filter` by `Permissions`
|
||||
|
||||
#### CxDav request "REPORT"
|
||||
|
||||
* Actions
|
||||
* map
|
||||
* back-map response
|
||||
* Lookup by
|
||||
* `path` (provided in request)
|
||||
* `user` (authenticated)
|
||||
* Replace
|
||||
* `path` by `PathMapped`
|
||||
* `user` by `Owner`
|
||||
* Activate
|
||||
* `permissions_filter` by `Permissions`
|
||||
|
||||
#### CxDav request "PROPFIND" without HTTP_DEPTH=1
|
||||
|
||||
* Actions
|
||||
* map
|
||||
* back-map response
|
||||
* overwrite `Properties` if provided
|
||||
* Lookup by
|
||||
* `path` (provided in request)
|
||||
* `user` (authenticated)
|
||||
* Replace
|
||||
* `path` by `PathMapped`
|
||||
* `user` by `Owner`
|
||||
* Overlay
|
||||
* `Properties` if provided
|
||||
* Activate
|
||||
* `permissions_filter` by `Permissions`
|
||||
|
||||
#### CxDav request "PROPFIND" with HTTP_DEPTH=1
|
||||
|
||||
* Actions
|
||||
* extend list
|
||||
* Lookup for active shares for `user` in sharing database
|
||||
* Extend list if conditions are met
|
||||
* `permissions_filter` by `Permissions`
|
||||
|
||||
#### CxDav request "PROPPATCH"
|
||||
|
||||
* Actions
|
||||
* map
|
||||
* adjust properties of a collection
|
||||
* Lookup by
|
||||
* `path` (provided in request)
|
||||
* `user` (authenticated)
|
||||
* Replace
|
||||
* `path` by `PathMapped`
|
||||
* `user` by `Owner`
|
||||
* Activate
|
||||
* `permissions_filter` by `Permissions`
|
||||
* Depending on `permissions_filter`, global options and `Permissions`
|
||||
* adjust properties of collection
|
||||
* adjust whitelisted properties in `Properties` for overlay (see OVERLAY_PROPERTIES_WHITELIST)
|
||||
|
||||
#### CxDav request "(MKCALENDAR|MKCOL)"
|
||||
|
||||
* Action
|
||||
* check for conflicts
|
||||
* Lookup by
|
||||
* `user` (authenticated)
|
||||
* Verify for non-existence as `PathOrToken` in sharing database
|
||||
* `path` (provided in request)
|
||||
|
||||
#### CxDav request "(MOVE)"
|
||||
|
||||
* Action
|
||||
* map source
|
||||
* map destination
|
||||
* Lookup by
|
||||
* `path` (provided in request)
|
||||
* `user` (authenticated)
|
||||
* `to_path` (provided in request)
|
||||
* `to_user` (same as `user`)
|
||||
* Replace
|
||||
* `path` by `PathMapped` (of path)
|
||||
* `user` by `Owner` (of `path`)
|
||||
* `to_path` by `PathMapped` (of `to_path`)
|
||||
* `to_user` by `Owner` (of `to_path`)
|
||||
* Activate
|
||||
* `permissions_filter` by `Permissions` (of `to_path`)
|
||||
* `to_permissions_filter` by `Permissions` (of `to_path`)
|
||||
|
||||
## Sharing Access
|
||||
|
||||
### Sharing Access via Maps
|
||||
@@ -579,7 +588,7 @@ Whitelisted ones are defined in `OVERLAY_PROPERTIES_WHITELIST` in `radicale/shar
|
||||
|
||||
#### Requirements
|
||||
|
||||
* sharing / permit_properties_overlay = True
|
||||
* `permit_properties_overlay = True`
|
||||
|
||||
#### Test sequence
|
||||
|
||||
|
||||
@@ -549,8 +549,12 @@ class Application(ApplicationPartDelete, ApplicationPartHead,
|
||||
else:
|
||||
profiler_active = True
|
||||
|
||||
status, headers, answer, xml_request = function(
|
||||
environ, base_prefix, path, user, remote_host, remote_useragent)
|
||||
try:
|
||||
status, headers, answer, xml_request = function(
|
||||
environ, base_prefix, path, user, remote_host, remote_useragent)
|
||||
except PermissionError as e:
|
||||
logger.error("PermissionError: %s", e)
|
||||
status, headers, answer, xml_request = httputils.INTERNAL_SERVER_ERROR
|
||||
|
||||
# Profiling
|
||||
if self._profiling_per_request:
|
||||
|
||||
@@ -537,6 +537,7 @@ class Item:
|
||||
pass
|
||||
|
||||
bdayS = match[1] + match[2] + match[3]
|
||||
bdaySdesc = match[1] + "-" + match[2] + "-" + match[3]
|
||||
bdayY = int(match[1])
|
||||
bdayM = int(match[2])
|
||||
bdayD = int(match[3])
|
||||
@@ -594,6 +595,9 @@ class Item:
|
||||
# add transparency
|
||||
item_ics.vevent.add('transp').value = "TRANSPARENT"
|
||||
|
||||
# add description
|
||||
item_ics.vevent.add('description').value = "BDAY=" + bdaySdesc
|
||||
|
||||
href = self.href
|
||||
if href is not None:
|
||||
href = href.rstrip(".vcf") + ".ics"
|
||||
|
||||
@@ -266,7 +266,9 @@ class Sharing(sharing.BaseSharing):
|
||||
"HiddenByOwner": HiddenByOwner,
|
||||
"HiddenByUser": HiddenByUser,
|
||||
"TimestampCreated": Timestamp,
|
||||
"TimestampUpdated": Timestamp}
|
||||
"TimestampUpdated": Timestamp,
|
||||
"Properties": Properties}
|
||||
|
||||
if logger.isEnabledFor(logging.DEBUG):
|
||||
logger.debug("TRACE/sharing/*/create: add row: %r", row)
|
||||
self._sharing_cache.append(row)
|
||||
|
||||
@@ -244,7 +244,8 @@ class Sharing(sharing.BaseSharing):
|
||||
"HiddenByOwner": HiddenByOwner,
|
||||
"HiddenByUser": HiddenByUser,
|
||||
"TimestampCreated": Timestamp,
|
||||
"TimestampUpdated": Timestamp}
|
||||
"TimestampUpdated": Timestamp,
|
||||
"Properties": Properties}
|
||||
|
||||
version = DB_VERSION
|
||||
|
||||
|
||||
@@ -942,6 +942,7 @@ class TestSharingApiSanity(BaseTest):
|
||||
json_dict['User'] = "user"
|
||||
json_dict['PathMapped'] = path_mapped
|
||||
json_dict['PathOrToken'] = path_shared
|
||||
json_dict['Properties'] = {"D:displayname": "Test"}
|
||||
_, headers, answer = self._sharing_api_json("map", "create", check=200, login="owner:ownerpw", json_dict=json_dict)
|
||||
answer_dict = json.loads(answer)
|
||||
assert answer_dict['Status'] == "success"
|
||||
@@ -962,6 +963,7 @@ class TestSharingApiSanity(BaseTest):
|
||||
assert answer_dict['Content'][0]['HiddenByOwner'] is True
|
||||
assert answer_dict['Content'][0]['HiddenByUser'] is True
|
||||
assert answer_dict['Content'][0]['Permissions'] == "r"
|
||||
assert answer_dict['Content'][0]['Properties'] == {"D:displayname": "Test"}
|
||||
|
||||
logging.info("\n*** enable map by owner (json->json) -> 200")
|
||||
json_dict = {}
|
||||
@@ -4288,6 +4290,7 @@ permissions: RrWw""")
|
||||
assert "DTSTART;VALUE=DATE:19700101" in answer
|
||||
assert "DTEND;VALUE=DATE:19700102" in answer
|
||||
assert "TRANSP:TRANSPARENT" in answer
|
||||
assert "DESCRIPTION:BDAY=1970-01-01" in answer
|
||||
|
||||
# verify report as user
|
||||
logging.info("\n*** REPORT collection user -> ok")
|
||||
|
||||
@@ -60,7 +60,7 @@ setup(
|
||||
license="GNU GPL v3",
|
||||
platforms="Any",
|
||||
packages=find_packages(
|
||||
exclude=["*.tests", "*.tests.*", "tests.*", "tests"]),
|
||||
exclude=["*.tests", "*.tests.*", "tests.*", "tests", "integ_tests"]),
|
||||
package_data={"radicale": [*web_files, "py.typed"]},
|
||||
entry_points={"console_scripts": ["radicale = radicale.__main__:run"]},
|
||||
install_requires=install_requires,
|
||||
|
||||
Reference in New Issue
Block a user