Skip to content

Commit 6c7987a

Browse files
authored
Merge pull request #2033 from pbiering/sharing-bday-add-desc
Sharing bday add description, doc updates, bugfixes
2 parents b5e34fb + f9853ce commit 6c7987a

File tree

7 files changed

+80
-57
lines changed

7 files changed

+80
-57
lines changed

SHARING.md

Lines changed: 61 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,67 @@
11

22
# Collection Sharing
33

4-
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]
4+
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)
55

6-
With _3.7.0_ major extension was implemented using internal mapping configuration stored in a database and a management API.
6+
With _3.7.0_ major extension was implemented
7+
* added internal mapping with configuration stored in a database
8+
* added management API
9+
* WebUI extension using the management API
710

811
## Sharing Implementation
912

10-
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.
13+
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.
1114

1215
Permissions are filtered by provided `Permissions`.
1316

17+
## Sharing Configuration
18+
19+
New section `[sharing]` controls sharing configuration, see [DOCUMENTATION:Sharing](DOCUMENTATION.md#sharing) for details
20+
21+
## Sharing Configuration Store
22+
23+
Types of supported sharing configuration:
24+
25+
* *csv* (_>= 3.7.0_)
26+
* *files* (_>= 3.7.0_)
27+
28+
### Sharing Configuration Entry Data
29+
30+
* `ShareType`: type of share
31+
* `token`: token-based share (do not require user authentication)
32+
* `map`: map-based share (requires user authentication)
33+
* `bday`: map-based share (requires user authentication) with on-the-fly auto-conversion
34+
* `PathOrToken`: token or "virtual" collection, has to be unique (PRIMARY KEY)
35+
* `PathMapped`: target collection
36+
* `Owner`: owner of the share
37+
* `User`: user of the share
38+
* `Permissions`: effective permission of the share (*bday* is always read-only)
39+
* `EnabledByOwner`: control by owner
40+
* `EnabledByUser`: control by user
41+
* `HiddenByOwner`: control by owner
42+
* `HiddenByUser`: control by user
43+
* `TimestampCreated`: unixtime of creation
44+
* `TimestampUpdated`: unixtime of last update
45+
* `Properties`: overlay properties (limited set whitelisted)
46+
47+
`Enabled*`: owner AND user have to enable a share to become usable
48+
49+
`Hidden*`: owner AND user have to disable a share to become visible in PROPFIND
50+
51+
### Sharing Configuration Entry Storage
52+
53+
#### CSV
54+
55+
One CSV file containing one row per sharing config, separated by `;` and containing header with columns from above.
56+
57+
If given, properties are stored in JSON format in CSV.
58+
59+
#### Files
60+
61+
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).
62+
63+
## Sharing Request Handling
64+
1465
### CxDAV requests
1566

1667
#### CxDav request "(DELETE|GET|HEAD|PUT)"
@@ -21,8 +72,8 @@ Permissions are filtered by provided `Permissions`.
2172
* `path` (provided in request)
2273
* `user` (authenticated)
2374
* Replace
24-
* `user` by `Owner`
2575
* `path` by `PathMapped`
76+
* `user` by `Owner`
2677
* Activate
2778
* `permissions_filter` by `Permissions`
2879

@@ -35,8 +86,8 @@ Permissions are filtered by provided `Permissions`.
3586
* `path` (provided in request)
3687
* `user` (authenticated)
3788
* Replace
38-
* `user` by `Owner`
3989
* `path` by `PathMapped`
90+
* `user` by `Owner`
4091
* Activate
4192
* `permissions_filter` by `Permissions`
4293

@@ -50,8 +101,8 @@ Permissions are filtered by provided `Permissions`.
50101
* `path` (provided in request)
51102
* `user` (authenticated)
52103
* Replace
53-
* `user` by `Owner`
54104
* `path` by `PathMapped`
105+
* `user` by `Owner`
55106
* Overlay
56107
* `Properties` if provided
57108
* Activate
@@ -74,8 +125,8 @@ Permissions are filtered by provided `Permissions`.
74125
* `path` (provided in request)
75126
* `user` (authenticated)
76127
* Replace
77-
* `user` by `Owner`
78128
* `path` by `PathMapped`
129+
* `user` by `Owner`
79130
* Activate
80131
* `permissions_filter` by `Permissions`
81132
* Depending on `permissions_filter`, global options and `Permissions`
@@ -102,56 +153,14 @@ Permissions are filtered by provided `Permissions`.
102153
* `to_path` (provided in request)
103154
* `to_user` (same as `user`)
104155
* Replace
105-
* `user` by `Owner` (of `path`)
106156
* `path` by `PathMapped` (of path)
107-
* `to_user` by `Owner` (of `to_path`)
157+
* `user` by `Owner` (of `path`)
108158
* `to_path` by `PathMapped` (of `to_path`)
159+
* `to_user` by `Owner` (of `to_path`)
109160
* Activate
110161
* `permissions_filter` by `Permissions` (of `to_path`)
111162
* `to_permissions_filter` by `Permissions` (of `to_path`)
112163

113-
## Sharing Configuration Store
114-
115-
Types of supported sharing configuration:
116-
117-
* csv (_>= 3.7.0_)
118-
* files (_>= 3.7.0_)
119-
120-
### Sharing Configuration Entry Data
121-
122-
* `ShareType`: type of share
123-
* `token`: token-based share (do not require user authentication)
124-
* `map`: map-based share (requires user authentication)
125-
* `bday`: map-based share (requires user authentication) with on-the-fly auto-conversion
126-
* `PathOrToken`: token or "virtual" collection, has to be unique (PRIMARY KEY)
127-
* `PathMapped`: target collection
128-
* `Owner`: owner of the share
129-
* `User`: user of the share
130-
* `Permissions`: effective permission of the share (*bday* is always read-only)
131-
* `EnabledByOwner`: control by owner
132-
* `EnabledByUser`: control by user
133-
* `HiddenByOwner`: control by owner
134-
* `HiddenByUser`: control by user
135-
* `TimestampCreated`: unixtime of creation
136-
* `TimestampUpdated`: unixtime of last update
137-
* `Properties`: overlay properties (limited set whitelisted)
138-
139-
`Enabled*`: owner AND user have to enable a share to become usable
140-
141-
`Hidden*`: owner AND user have to disable a share to become visible in PROPFIND
142-
143-
### Sharing Configuration Entry Storage
144-
145-
#### CSV
146-
147-
One CSV file containing one row per sharing config, separated by `;` and containing header with columns from above.
148-
149-
If given, properties are stored in JSON format in CSV.
150-
151-
#### Files
152-
153-
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).
154-
155164
## Sharing Access
156165

157166
### Sharing Access via Maps
@@ -579,7 +588,7 @@ Whitelisted ones are defined in `OVERLAY_PROPERTIES_WHITELIST` in `radicale/shar
579588
580589
#### Requirements
581590
582-
* sharing / permit_properties_overlay = True
591+
* `permit_properties_overlay = True`
583592
584593
#### Test sequence
585594

radicale/app/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -549,8 +549,12 @@ def response(status: int, headers: types.WSGIResponseHeaders,
549549
else:
550550
profiler_active = True
551551

552-
status, headers, answer, xml_request = function(
553-
environ, base_prefix, path, user, remote_host, remote_useragent)
552+
try:
553+
status, headers, answer, xml_request = function(
554+
environ, base_prefix, path, user, remote_host, remote_useragent)
555+
except PermissionError as e:
556+
logger.error("PermissionError: %s", e)
557+
status, headers, answer, xml_request = httputils.INTERNAL_SERVER_ERROR
554558

555559
# Profiling
556560
if self._profiling_per_request:

radicale/item/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,7 @@ def convert_vcf_to_ics(self) -> Union["Item", None]:
537537
pass
538538

539539
bdayS = match[1] + match[2] + match[3]
540+
bdaySdesc = match[1] + "-" + match[2] + "-" + match[3]
540541
bdayY = int(match[1])
541542
bdayM = int(match[2])
542543
bdayD = int(match[3])
@@ -594,6 +595,9 @@ def convert_vcf_to_ics(self) -> Union["Item", None]:
594595
# add transparency
595596
item_ics.vevent.add('transp').value = "TRANSPARENT"
596597

598+
# add description
599+
item_ics.vevent.add('description').value = "BDAY=" + bdaySdesc
600+
597601
href = self.href
598602
if href is not None:
599603
href = href.rstrip(".vcf") + ".ics"

radicale/sharing/csv.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,9 @@ def database_create_sharing(self,
266266
"HiddenByOwner": HiddenByOwner,
267267
"HiddenByUser": HiddenByUser,
268268
"TimestampCreated": Timestamp,
269-
"TimestampUpdated": Timestamp}
269+
"TimestampUpdated": Timestamp,
270+
"Properties": Properties}
271+
270272
if logger.isEnabledFor(logging.DEBUG):
271273
logger.debug("TRACE/sharing/*/create: add row: %r", row)
272274
self._sharing_cache.append(row)

radicale/sharing/files.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@ def database_create_sharing(self,
244244
"HiddenByOwner": HiddenByOwner,
245245
"HiddenByUser": HiddenByUser,
246246
"TimestampCreated": Timestamp,
247-
"TimestampUpdated": Timestamp}
247+
"TimestampUpdated": Timestamp,
248+
"Properties": Properties}
248249

249250
version = DB_VERSION
250251

radicale/tests/test_sharing.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,7 @@ def test_sharing_api_map_usage(self) -> None:
942942
json_dict['User'] = "user"
943943
json_dict['PathMapped'] = path_mapped
944944
json_dict['PathOrToken'] = path_shared
945+
json_dict['Properties'] = {"D:displayname": "Test"}
945946
_, headers, answer = self._sharing_api_json("map", "create", check=200, login="owner:ownerpw", json_dict=json_dict)
946947
answer_dict = json.loads(answer)
947948
assert answer_dict['Status'] == "success"
@@ -962,6 +963,7 @@ def test_sharing_api_map_usage(self) -> None:
962963
assert answer_dict['Content'][0]['HiddenByOwner'] is True
963964
assert answer_dict['Content'][0]['HiddenByUser'] is True
964965
assert answer_dict['Content'][0]['Permissions'] == "r"
966+
assert answer_dict['Content'][0]['Properties'] == {"D:displayname": "Test"}
965967

966968
logging.info("\n*** enable map by owner (json->json) -> 200")
967969
json_dict = {}
@@ -4288,6 +4290,7 @@ def test_sharing_api_bday_basic(self) -> None:
42884290
assert "DTSTART;VALUE=DATE:19700101" in answer
42894291
assert "DTEND;VALUE=DATE:19700102" in answer
42904292
assert "TRANSP:TRANSPARENT" in answer
4293+
assert "DESCRIPTION:BDAY=1970-01-01" in answer
42914294

42924295
# verify report as user
42934296
logging.info("\n*** REPORT collection user -> ok")

setup.py.legacy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ setup(
6060
license="GNU GPL v3",
6161
platforms="Any",
6262
packages=find_packages(
63-
exclude=["*.tests", "*.tests.*", "tests.*", "tests"]),
63+
exclude=["*.tests", "*.tests.*", "tests.*", "tests", "integ_tests"]),
6464
package_data={"radicale": [*web_files, "py.typed"]},
6565
entry_points={"console_scripts": ["radicale = radicale.__main__:run"]},
6666
install_requires=install_requires,

0 commit comments

Comments
 (0)