Merge pull request #2148 from pbiering/sharing-bday-template-api
Sharing bday template api regression
This commit is contained in:
78
SHARING.md
78
SHARING.md
@@ -526,6 +526,8 @@ Execute delete+create in case `PathOrToken` needs to be changed.
|
|||||||
|
|
||||||
* Output: text/plain|application/json
|
* Output: text/plain|application/json
|
||||||
|
|
||||||
|
* Level-2 entries in "Actions" can be deleted using special value `#DEL#` (see API example below related to "bday" conversion)
|
||||||
|
|
||||||
* Examples:
|
* Examples:
|
||||||
|
|
||||||
###### form->text
|
###### form->text
|
||||||
@@ -738,3 +740,79 @@ BEGIN:VCALENDAR
|
|||||||
...
|
...
|
||||||
END:VCALENDAR
|
END:VCALENDAR
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### Adjusting templates per share
|
||||||
|
|
||||||
|
```bash
|
||||||
|
## set specific config: conversion_bday_summary_template
|
||||||
|
curl -u owner:$ownerpw -H "Content-Type: application/json" -d '{ "PathMapped": "/owner/addressbook/", "PathOrToken": "/owner/bday-of-addressbook/", "Actions": { "config": { "conversion_bday_summary_template": "{fn} ({year}" }}}' http://localhost:5232/.sharing/v1/map/update
|
||||||
|
{"ApiVersion": 1, "Status": "success"}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
## list adjusted share
|
||||||
|
curl -s -H "Content-Type: application/json" -u owner:$ownerpw -d '{ "PathMapped": "/owner/addressbook/", "PathOrToken": "/owner/bday-of-addressbook/"}' http://localhost:5232/.sharing/v1/map/list | jq
|
||||||
|
{
|
||||||
|
"ApiVersion": 1,
|
||||||
|
"Lines": 1,
|
||||||
|
"Status": "success",
|
||||||
|
"Content": [
|
||||||
|
{
|
||||||
|
"ShareType": "map",
|
||||||
|
"PathOrToken": "/owner/bday-of-addressbook/",
|
||||||
|
"PathMapped": "/owner/addressbook/",
|
||||||
|
"Conversion": "bday",
|
||||||
|
"Owner": "owner",
|
||||||
|
"User": "owner",
|
||||||
|
"Permissions": "r",
|
||||||
|
"EnabledByOwner": true,
|
||||||
|
"EnabledByUser": true,
|
||||||
|
"HiddenByOwner": false,
|
||||||
|
"HiddenByUser": false,
|
||||||
|
"TimestampCreated": 1774339430,
|
||||||
|
"TimestampUpdated": 1780240328,
|
||||||
|
"Properties": {},
|
||||||
|
"Actions": {
|
||||||
|
"config": {
|
||||||
|
"conversion_bday_summary_template": "{fn} ({year}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
## delete specific config: conversion_bday_summary_template (using special value "#DEL#")
|
||||||
|
curl -u owner:$ownerpw -H "Content-Type: application/json" -d '{ "PathMapped": "/owner/addressbook/", "PathOrToken": "/owner/bday-of-addressbook/", "Actions": { "config": { "conversion_bday_summary_template": "#DEL#" }}}' http://localhost:5232/.sharing/v1/map/update
|
||||||
|
{"ApiVersion": 1, "Status": "success"}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
## list share (specific config is deleted)
|
||||||
|
curl -s -H "Content-Type: application/json" -u owner:$ownerpw -d '{ "PathMapped": "/owner/addressbook/", "PathOrToken": "/owner/bday-of-addressbook/"}' http://localhost:5232/.sharing/v1/map/list | jq
|
||||||
|
{
|
||||||
|
"ApiVersion": 1,
|
||||||
|
"Lines": 1,
|
||||||
|
"Status": "success",
|
||||||
|
"Content": [
|
||||||
|
{
|
||||||
|
"ShareType": "map",
|
||||||
|
"PathOrToken": "/owner/bday-of-addressbook/",
|
||||||
|
"PathMapped": "/owner/addressbook/",
|
||||||
|
"Conversion": "bday",
|
||||||
|
"Owner": "owner",
|
||||||
|
"User": "owner",
|
||||||
|
"Permissions": "r",
|
||||||
|
"EnabledByOwner": true,
|
||||||
|
"EnabledByUser": true,
|
||||||
|
"HiddenByOwner": false,
|
||||||
|
"HiddenByUser": false,
|
||||||
|
"TimestampCreated": 1774339430,
|
||||||
|
"TimestampUpdated": 1780240558,
|
||||||
|
"Properties": {},
|
||||||
|
"Actions": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ SHARING_BDAY_AGE_MAX_DEFAULT: int = 99
|
|||||||
SHARING_BDAY_SUMMARY_TEMPLATE_DEFAULT: str = "[{n:f} {n:g}|{fn}|{nickname}] ({year}) (BDAY)"
|
SHARING_BDAY_SUMMARY_TEMPLATE_DEFAULT: str = "[{n:f} {n:g}|{fn}|{nickname}] ({year}) (BDAY)"
|
||||||
SHARING_BDAY_DESCRIPTION_TEMPLATE_DEFAULT: str = "BDAY={year}-{month}-{day}"
|
SHARING_BDAY_DESCRIPTION_TEMPLATE_DEFAULT: str = "BDAY={year}-{month}-{day}"
|
||||||
SHARING_BDAY_CATEGORIES_DEFAULT: str = 'Birthday'
|
SHARING_BDAY_CATEGORIES_DEFAULT: str = 'Birthday'
|
||||||
|
SHARING_ACTIONS_DELETE_VALUE: str = '#DEL#'
|
||||||
|
|
||||||
|
|
||||||
def check_bday_max_age(data: Any) -> int:
|
def check_bday_max_age(data: Any) -> int:
|
||||||
@@ -555,7 +556,6 @@ class BaseSharing:
|
|||||||
|
|
||||||
# adjust a share
|
# adjust a share
|
||||||
def sharing_collection_update(self, ShareType: str, PathOrToken: str, OwnerOrUser: str, Properties: dict) -> None:
|
def sharing_collection_update(self, ShareType: str, PathOrToken: str, OwnerOrUser: str, Properties: dict) -> None:
|
||||||
""" returning dict with PathMapped, Owner, Permissions or None if not found"""
|
|
||||||
logger.info("sharing/collection/update: ShareType=%r PathOrToken=%r OwnerOrUser=%r", ShareType, PathOrToken, OwnerOrUser)
|
logger.info("sharing/collection/update: ShareType=%r PathOrToken=%r OwnerOrUser=%r", ShareType, PathOrToken, OwnerOrUser)
|
||||||
# Filter properies for permitted ones
|
# Filter properies for permitted ones
|
||||||
properties_filtered: dict = {}
|
properties_filtered: dict = {}
|
||||||
@@ -943,7 +943,7 @@ class BaseSharing:
|
|||||||
if level1 in ACTIONS_WHITELIST:
|
if level1 in ACTIONS_WHITELIST:
|
||||||
for level2 in request_data['Actions'][level1]:
|
for level2 in request_data['Actions'][level1]:
|
||||||
if level2 in ACTIONS_WHITELIST[level1]:
|
if level2 in ACTIONS_WHITELIST[level1]:
|
||||||
if callable(ACTIONS_WHITELIST[level1][level2]):
|
if callable(ACTIONS_WHITELIST[level1][level2]) and request_data['Actions'][level1][level2] != SHARING_ACTIONS_DELETE_VALUE:
|
||||||
try:
|
try:
|
||||||
value = ACTIONS_WHITELIST[level1][level2](request_data['Actions'][level1][level2])
|
value = ACTIONS_WHITELIST[level1][level2](request_data['Actions'][level1][level2])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@@ -1253,6 +1253,32 @@ class BaseSharing:
|
|||||||
logger.trace("" + api_info + ": clear property %r", prop)
|
logger.trace("" + api_info + ": clear property %r", prop)
|
||||||
del Properties[prop]
|
del Properties[prop]
|
||||||
|
|
||||||
|
if 'Actions' in request_data:
|
||||||
|
if Actions is None:
|
||||||
|
# clear actions
|
||||||
|
Actions = {}
|
||||||
|
elif Actions == {}:
|
||||||
|
# empty, nothing to do
|
||||||
|
pass
|
||||||
|
elif share['Actions'] is not None:
|
||||||
|
# replace properties
|
||||||
|
for level1 in share['Actions']:
|
||||||
|
if level1 not in Actions:
|
||||||
|
Actions[level1] = {} # initialize level1
|
||||||
|
for level2 in share['Actions'][level1]:
|
||||||
|
logger.trace("" + api_info + ": check for existing Actions entry %r->%r", level1, level2)
|
||||||
|
if level2 not in Actions[level1]:
|
||||||
|
logger.trace("" + api_info + ": overtake Actions entry %r->%r", level1, level2)
|
||||||
|
Actions[level1][level2] = share['Actions'][level1][level2]
|
||||||
|
elif Actions[level1][level2] == SHARING_ACTIONS_DELETE_VALUE:
|
||||||
|
# unset, do nothing
|
||||||
|
logger.trace("" + api_info + ": delete Actions entry %r->%r", level1, level2)
|
||||||
|
del Actions[level1][level2]
|
||||||
|
if len(Actions[level1]) == 0:
|
||||||
|
logger.trace("" + api_info + ": delete Actions entry %r", level1)
|
||||||
|
# unset level1
|
||||||
|
del Actions[level1]
|
||||||
|
|
||||||
if Permissions is not None and share['Conversion'] is not None:
|
if Permissions is not None and share['Conversion'] is not None:
|
||||||
Permissions = str(Permissions)
|
Permissions = str(Permissions)
|
||||||
if share['Conversion'] == "bday":
|
if share['Conversion'] == "bday":
|
||||||
|
|||||||
@@ -5199,6 +5199,115 @@ permissions: RrWw""")
|
|||||||
}}
|
}}
|
||||||
_, headers, answer = self._sharing_api_json("map", "update", check=400, login="owner:ownerpw", json_dict=json_dict)
|
_, headers, answer = self._sharing_api_json("map", "update", check=400, login="owner:ownerpw", json_dict=json_dict)
|
||||||
|
|
||||||
|
self.configure({
|
||||||
|
"sharing": {"conversion_bday_description_template": sharing.SHARING_BDAY_DESCRIPTION_TEMPLATE_DEFAULT,
|
||||||
|
"conversion_bday_alarm_trigger_template": "",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
# update template
|
||||||
|
logging.info("\n*** update map(bday) user/owner:r with valid description template -> 200")
|
||||||
|
json_dict = {}
|
||||||
|
json_dict['User'] = "user"
|
||||||
|
json_dict['PathMapped'] = path_mapped
|
||||||
|
json_dict['PathOrToken'] = path_shared_r
|
||||||
|
json_dict['Actions'] = {"config": {
|
||||||
|
"conversion_bday_summary_template": "{fn} ({year})",
|
||||||
|
"conversion_bday_description_template": "Birthday={year}-{month}-{day}"
|
||||||
|
}}
|
||||||
|
_, headers, answer = self._sharing_api_json("map", "update", check=200, login="owner:ownerpw", json_dict=json_dict)
|
||||||
|
|
||||||
|
logging.info("\n*** GET collection user format: description -> ok")
|
||||||
|
_, headers, answer = self.request("GET", path_shared_3, login="user:userpw")
|
||||||
|
assert "DESCRIPTION:Birthday=1990-01-01" in answer
|
||||||
|
assert "SUMMARY:Test-FN-C3 (1990)" in answer
|
||||||
|
|
||||||
|
# update template
|
||||||
|
logging.info("\n*** update map(bday) user/owner:r with valid empty description template -> 200")
|
||||||
|
json_dict = {}
|
||||||
|
json_dict['User'] = "user"
|
||||||
|
json_dict['PathMapped'] = path_mapped
|
||||||
|
json_dict['PathOrToken'] = path_shared_r
|
||||||
|
json_dict['Actions'] = {"config": {
|
||||||
|
"conversion_bday_description_template": ""
|
||||||
|
}}
|
||||||
|
_, headers, answer = self._sharing_api_json("map", "update", check=200, login="owner:ownerpw", json_dict=json_dict)
|
||||||
|
|
||||||
|
logging.info("\n*** GET collection user format: description -> ok")
|
||||||
|
_, headers, answer = self.request("GET", path_shared_3, login="user:userpw")
|
||||||
|
assert "DESCRIPTION:Birthday=" not in answer
|
||||||
|
assert "DESCRIPTION:BDAY=" not in answer
|
||||||
|
assert "SUMMARY:Test-FN-C3 (1990)" in answer
|
||||||
|
|
||||||
|
# update template
|
||||||
|
logging.info("\n*** update map(bday) user/owner:r DEL description template -> 200")
|
||||||
|
json_dict = {}
|
||||||
|
json_dict['User'] = "user"
|
||||||
|
json_dict['PathMapped'] = path_mapped
|
||||||
|
json_dict['PathOrToken'] = path_shared_r
|
||||||
|
json_dict['Actions'] = {"config": {
|
||||||
|
"conversion_bday_description_template": sharing.SHARING_ACTIONS_DELETE_VALUE
|
||||||
|
}}
|
||||||
|
_, headers, answer = self._sharing_api_json("map", "update", check=200, login="owner:ownerpw", json_dict=json_dict)
|
||||||
|
|
||||||
|
logging.info("\n*** GET collection user format: description -> ok")
|
||||||
|
_, headers, answer = self.request("GET", path_shared_3, login="user:userpw")
|
||||||
|
assert "DESCRIPTION:Birthday=" not in answer
|
||||||
|
assert "DESCRIPTION:BDAY=" in answer
|
||||||
|
assert "SUMMARY:Test-FN-C3 (1990)" in answer
|
||||||
|
|
||||||
|
# update template
|
||||||
|
logging.info("\n*** update map(bday) user/owner:r DEL summary template -> 200")
|
||||||
|
json_dict = {}
|
||||||
|
json_dict['User'] = "user"
|
||||||
|
json_dict['PathMapped'] = path_mapped
|
||||||
|
json_dict['PathOrToken'] = path_shared_r
|
||||||
|
json_dict['Actions'] = {"config": {
|
||||||
|
"conversion_bday_summary_template": sharing.SHARING_ACTIONS_DELETE_VALUE
|
||||||
|
}}
|
||||||
|
_, headers, answer = self._sharing_api_json("map", "update", check=200, login="owner:ownerpw", json_dict=json_dict)
|
||||||
|
|
||||||
|
logging.info("\n*** GET collection user format: description -> ok")
|
||||||
|
_, headers, answer = self.request("GET", path_shared_3, login="user:userpw")
|
||||||
|
assert "DESCRIPTION:Birthday=" not in answer
|
||||||
|
assert "DESCRIPTION:BDAY=" in answer
|
||||||
|
assert "SUMMARY:Family3Test Given3Test !n:a! (Birthday)" in answer
|
||||||
|
|
||||||
|
# update template
|
||||||
|
logging.info("\n*** update map(bday) user/owner:r with valid age max -> 200")
|
||||||
|
json_dict = {}
|
||||||
|
json_dict['User'] = "user"
|
||||||
|
json_dict['PathMapped'] = path_mapped
|
||||||
|
json_dict['PathOrToken'] = path_shared_r
|
||||||
|
json_dict['Actions'] = {"config": {
|
||||||
|
"conversion_bday_age_max": 5,
|
||||||
|
"conversion_bday_summary_template": "{fn} ({year}/{age})",
|
||||||
|
}}
|
||||||
|
_, headers, answer = self._sharing_api_json("map", "update", check=200, login="owner:ownerpw", json_dict=json_dict)
|
||||||
|
|
||||||
|
logging.info("\n*** GET collection user format: summary with age -> ok")
|
||||||
|
_, headers, answer = self.request("GET", path_shared_3, login="user:userpw")
|
||||||
|
assert "Test-FN-C3 (1990/0)" in answer
|
||||||
|
assert "Test-FN-C3 (1990/5)" in answer
|
||||||
|
assert "Test-FN-C3 (1990/6)" not in answer
|
||||||
|
|
||||||
|
# update template
|
||||||
|
logging.info("\n*** update map(bday) user/owner:r with valid age max -> 200")
|
||||||
|
json_dict = {}
|
||||||
|
json_dict['User'] = "user"
|
||||||
|
json_dict['PathMapped'] = path_mapped
|
||||||
|
json_dict['PathOrToken'] = path_shared_r
|
||||||
|
json_dict['Actions'] = {"config": {
|
||||||
|
"conversion_bday_age_max": sharing.SHARING_ACTIONS_DELETE_VALUE
|
||||||
|
}}
|
||||||
|
_, headers, answer = self._sharing_api_json("map", "update", check=200, login="owner:ownerpw", json_dict=json_dict)
|
||||||
|
|
||||||
|
logging.info("\n*** GET collection user format: summary with age -> ok")
|
||||||
|
_, headers, answer = self.request("GET", path_shared_3, login="user:userpw")
|
||||||
|
assert "Test-FN-C3 (1990/0)" in answer
|
||||||
|
assert "Test-FN-C3 (1990/5)" in answer
|
||||||
|
assert "Test-FN-C3 (1990/6)" in answer
|
||||||
|
|
||||||
def test_sharing_api_map_vcf_bday_age_template(self) -> None:
|
def test_sharing_api_map_vcf_bday_age_template(self) -> None:
|
||||||
"""share-by-map with conversion=bday template tests with age."""
|
"""share-by-map with conversion=bday template tests with age."""
|
||||||
self.configure({"auth": {"type": "htpasswd",
|
self.configure({"auth": {"type": "htpasswd",
|
||||||
|
|||||||
Reference in New Issue
Block a user