From 27064a9c61637235f0fbfec00162842ec54eddf6 Mon Sep 17 00:00:00 2001 From: xelast418 Date: Wed, 20 Sep 2023 20:50:37 +1200 Subject: [PATCH] Adds support for extending a calendar config with another calendar config. --- README.md | 16 ++++++++++++++ app/tools/tools.py | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/README.md b/README.md index 4059092..03043f8 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,11 @@ The JSON configuration file should look like the following. ```json [ + { + "conf": true, + "extends": "str", + "extendFail": "str", + }, { "url":"str", "name":"str", @@ -104,9 +109,20 @@ Only the `url` and the `name` field are mandatory. - `redactAs`: Replaces the content of the field with the specified string If multiple calendars are specified in the configuration list, their events will be merged in the resulting ics feed. +The first dataset with {"conf": true,} specifies options that are globally applied to all calenders in the conf. Omit this set to disable. Options +- `extends`: string specifying the name (excluding .json) of another config file to extend. +- `extendFail`: string speciying the action to take if an extend fails, either "fail" or "ignore". Default is "fail". ## Usage Once the config file is created, the corresponding HTTP endpoint is accessible. For example, if the file `app/config/my-calendar.json` contains the configuration, the HTTP endpoint will be `http://localhost:8088/my-calendar`. +A config can extend another config file, to do this the extended config should contain begin with`{ + "conf": true, + "extends": , + "extendFail": "fail", + },` +For an extend to work calendars MUST share the same name between the configs +An extending config cannot remove data from a base calendar but can modify fields + ## Limitations Currently, the application only merges events of the ics feeds, the alarms and todos are not supported. diff --git a/app/tools/tools.py b/app/tools/tools.py index 91f253d..ca5ec91 100644 --- a/app/tools/tools.py +++ b/app/tools/tools.py @@ -348,6 +348,26 @@ def process(path: str, from_cache: bool = True) -> Calendar: data = [] for entry in config: + if entry.get("conf", False) == True: + if entry.get("extends", None) is not None: + try: + o = "app/config/" + sanitize_filename(entry["extends"]) + ".json" + print("Try to open " + o) + file = open(o, "r") + baseConfig = json.loads(file.read()) + file.close() + extendingConfig = config + try: + config = merge_json(baseConfig, extendingConfig) + except: + config = extendingConfig + + except: + if entry.get("extendFail", "fail") == "fail": + raise FileNotFoundError("The calendar is not cached") + else: + pass + continue cal = load_cal(entry) @@ -448,3 +468,35 @@ def horodate(cal: Calendar, prefix='') -> Calendar: if event.description is not None else prefix + ' ' + now return cal + +def merge_json(base, extention): + """Merges two config files by updating the value of base with the values in extention. + + + :param base: the base config file + :type base: dict + + :param extention: the config file to merge with the base + :type extention: dict + + :return: the merged config file + :rtype: dict + + """ + + newJson = base.copy() + + def update_json(target, source): + + for key, value in source.items(): + if isinstance(value, dict) and key in target and isinstance(target[key], dict): + update_json(target[key], value) + else: + target[key] = value + + for dataset in newJson: + for dset in extention: + if newJson["name"] == dset["name"]: + update_json(newJson, dset) + + return newJson \ No newline at end of file