From ad42f00a27e70ce8c9b895019df6d70cd7d88b4a Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Sat, 30 May 2026 09:12:43 +0200 Subject: [PATCH] sharing/bday/age: add test cases --- radicale/tests/test_sharing.py | 174 +++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) diff --git a/radicale/tests/test_sharing.py b/radicale/tests/test_sharing.py index c66707fd..34939c9d 100644 --- a/radicale/tests/test_sharing.py +++ b/radicale/tests/test_sharing.py @@ -5068,6 +5068,180 @@ permissions: RrWw""") assert "TRIGGER:-PT12H" in answer assert "TRIGGER:PT12H" in answer + def test_sharing_api_map_vcf_bday_age_template(self) -> None: + """share-by-map with conversion=bday template tests with age.""" + self.configure({"auth": {"type": "htpasswd", + "htpasswd_filename": self.htpasswd_file_path, + "htpasswd_encryption": "plain"}, + "sharing": { + "type": "csv", + "permit_create_map": True, + "permit_properties_overlay": "True", + "enforce_properties_overlay": "True", + "collection_by_map": "True"}, + "logging": {"request_header_on_debug": "False", + "response_content_on_debug": "True", + "response_header_on_debug": "True", + "request_content_on_debug": "True"}, + "rights": {"type": "owner_only"}}) + + json_dict: dict + + logging.info("\n*** prepare and test access") + + for db_type in list(filter(lambda item: item != "none", sharing.INTERNAL_TYPES)): + logging.info("\n*** test: %s", db_type) + self.configure({"sharing": {"type": db_type}}) + + path_mapped = "/owner/adressbook-" + db_type + ".vcf/" + path_shared_r = "/user/calendar-bday-abook-shared-by-owner-r-" + db_type + ".ics/" + self.create_addressbook(path_mapped, login="owner:ownerpw") + + contact2 = get_file_content("contact2-with-bday.vcf") + path2 = path_mapped + "/contact2-with-bday.vcf" + path_shared_2 = path_shared_r + "/contact2-with-bday.vcf" + self.put(path2, contact2, login="owner:ownerpw") + + # create map + logging.info("\n*** create map(bday) user/owner:r -> ok") + json_dict = {} + json_dict['User'] = "user" + json_dict['PathMapped'] = path_mapped + json_dict['PathOrToken'] = path_shared_r + json_dict['Conversion'] = "bday" + json_dict['Permissions'] = "rP" + json_dict['Enabled'] = True + json_dict['Enabled'] = True + json_dict['Hidden'] = False + json_dict['Properties'] = {"D:displayname": "Test-BDAY"} + _, 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" + + # enable map by user + logging.info("\n*** enable map(bday) by user") + json_dict = {} + json_dict['User'] = "user" + json_dict['PathMapped'] = path_mapped + json_dict['PathOrToken'] = path_shared_r + _, headers, answer = self._sharing_api_json("map", "enable", check=200, login="user:userpw", json_dict=json_dict) + + self.configure({"sharing": { + "conversion_bday_summary_template": "[{fn}|{n:f} {n:g} {n:a}|{nickname}] (BDAY)", + "conversion_bday_description_template": "BDAY={year}-{month}-{day}", + }}) + + # verify content as user + logging.info("\n*** GET collection user format:default -> ok") + _, headers, answer = self.request("GET", path_shared_2, login="user:userpw") + assert "SUMMARY:Test-FN (BDAY)" in answer + + self.configure({"sharing": { + "conversion_bday_summary_template": "[{fn}|{n:f} {n:g} {n:a}|{nickname}] ({age}. Birthday)", + }}) + logging.info("\n*** GET collection user format:text -> ok") + _, headers, answer = self.request("GET", path_shared_2, login="user:userpw") + assert "SUMMARY:Test-FN (0. Birthday)" in answer + assert "SUMMARY:Test-FN (1. Birthday)" in answer + assert "SUMMARY:Test-FN (99. Birthday)" in answer + assert "SUMMARY:Test-FN (100. Birthday)" not in answer + + self.configure({"sharing": { + "conversion_bday_summary_template": "[{fn}|{n:f} {n:g} {n:a}|{nickname}] (BDAY)", + "conversion_bday_description_template": "AGE={age}", + }}) + logging.info("\n*** GET collection user format:text -> ok") + _, headers, answer = self.request("GET", path_shared_2, login="user:userpw") + assert "SUMMARY:Test-FN (BDAY)" in answer + assert "DESCRIPTION:AGE=0" in answer + assert "DESCRIPTION:AGE=1" in answer + assert "DESCRIPTION:AGE=99" in answer + assert "DESCRIPTION:AGE=100" not in answer + + self.configure({"sharing": { + "conversion_bday_summary_template": "[{fn}|{n:f} {n:g} {n:a}|{nickname}] (BDAY)", + "conversion_bday_description_template": "BDAY={year}-{month}-{day}", + "conversion_bday_alarm_trigger_template": "-15H;alarm {fn} {age}. birthday", + }}) + logging.info("\n*** GET collection user format:text -> ok") + _, headers, answer = self.request("GET", path_shared_2, login="user:userpw") + assert "SUMMARY:Test-FN (BDAY)" in answer + assert "DESCRIPTION:BDAY=1970-01-01" in answer + assert "DESCRIPTION:alarm Test-FN 0. birthday" in answer + assert "DESCRIPTION:alarm Test-FN 1. birthday" in answer + assert "DESCRIPTION:alarm Test-FN 99. birthday" in answer + assert "DESCRIPTION:alarm Test-FN 100. birthday" not in answer + + # update template + logging.info("\n*** update map(bday) user/owner:r -> ok") + json_dict = {} + json_dict['User'] = "user" + json_dict['PathMapped'] = path_mapped + json_dict['PathOrToken'] = path_shared_r + json_dict['Actions'] = {"limit": { + "conversion_bday_age_max": 5, + }} + _, headers, answer = self._sharing_api_json("map", "update", check=200, login="owner:ownerpw", json_dict=json_dict) + answer_dict = json.loads(answer) + assert answer_dict['Status'] == "success" + + logging.info("\n*** GET collection user format:text -> ok") + _, headers, answer = self.request("GET", path_shared_2, login="user:userpw") + assert "SUMMARY:Test-FN (BDAY)" in answer + assert "DESCRIPTION:BDAY=1970-01-01" in answer + assert "DESCRIPTION:alarm Test-FN 0. birthday" in answer + assert "DESCRIPTION:alarm Test-FN 1. birthday" in answer + assert "DESCRIPTION:alarm Test-FN 5. birthday" in answer + assert "DESCRIPTION:alarm Test-FN 6. birthday" not in answer + assert "DESCRIPTION:alarm Test-FN 99. birthday" not in answer + assert "DESCRIPTION:alarm Test-FN 100. birthday" not in answer + + self.configure({"sharing": { + "conversion_bday_summary_template": "[{fn}|{n:f} {n:g} {n:a}|{nickname}] (BDAY)", + "conversion_bday_description_template": "AGE={age}", + "conversion_bday_alarm_trigger_template": "", + }}) + logging.info("\n*** GET collection user limit age to 5 -> ok") + _, headers, answer = self.request("GET", path_shared_2, login="user:userpw") + assert "SUMMARY:Test-FN (BDAY)" in answer + assert "DESCRIPTION:AGE=0" in answer + assert "DESCRIPTION:AGE=1" in answer + assert "DESCRIPTION:AGE=5" in answer + assert "DESCRIPTION:AGE=6" not in answer + assert "DESCRIPTION:AGE=99" not in answer + assert "DESCRIPTION:AGE=100" not in answer + + # update template with invalid data test + logging.info("\n*** update map(bday) user/owner:r -> age_max not negative") + json_dict = {} + json_dict['User'] = "user" + json_dict['PathMapped'] = path_mapped + json_dict['PathOrToken'] = path_shared_r + json_dict['Actions'] = {"limit": { + "conversion_bday_age_max": -1, + }} + _, headers, answer = self._sharing_api_json("map", "update", check=400, login="owner:ownerpw", json_dict=json_dict) + + logging.info("\n*** update map(bday) user/owner:r -> unsupported level 1") + json_dict = {} + json_dict['User'] = "user" + json_dict['PathMapped'] = path_mapped + json_dict['PathOrToken'] = path_shared_r + json_dict['Actions'] = {"level1": { + "level2": "test", + }} + _, headers, answer = self._sharing_api_json("map", "update", check=400, login="owner:ownerpw", json_dict=json_dict) + + logging.info("\n*** update map(bday) user/owner:r -> unsupported level 2") + json_dict = {} + json_dict['User'] = "user" + json_dict['PathMapped'] = path_mapped + json_dict['PathOrToken'] = path_shared_r + json_dict['Actions'] = {"limit": { + "level2": "test", + }} + _, headers, answer = self._sharing_api_json("map", "update", check=400, login="owner:ownerpw", json_dict=json_dict) + def test_sharing_api_map_vcf_bday_per_share_template(self) -> None: """share-by-map with conversion=bday template per share tests.""" self.configure({"auth": {"type": "htpasswd",