From e5acc4fd1df8518a044d36b05138304eab6a2146 Mon Sep 17 00:00:00 2001 From: xelast418 Date: Mon, 18 Sep 2023 10:29:44 +1200 Subject: [PATCH 1/2] Minor updates: - Updates README.md with redactAs - Updates .gitignore to exclude developement files - Updates tools.py to reword the horodate prefix from "Downloaded at" to "Event last fetched" --- .gitignore | 2 +- README.md | 9 ++++++--- app/tools/tools.py | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 40a69eb..72cc436 100644 --- a/.gitignore +++ b/.gitignore @@ -133,6 +133,6 @@ dmypy.json app/config/calendar.json /app/cache/ -#development directories +# Development directories /app/config/ .vscode diff --git a/README.md b/README.md index e8ac8f9..4059092 100644 --- a/README.md +++ b/README.md @@ -59,15 +59,18 @@ The JSON configuration file should look like the following. }, "name":{ "addPrefix":"str", - "addSuffix":"str" + "addSuffix":"str", + "redactAs":"str" }, "description":{ "addPrefix":"str", - "addSuffix":"str" + "addSuffix":"str", + "redactAs":"str" }, "location":{ "addPrefix":"str", - "addSuffix":"str" + "addSuffix":"str", + "redactAs":"str" } } } diff --git a/app/tools/tools.py b/app/tools/tools.py index 262666b..91f253d 100644 --- a/app/tools/tools.py +++ b/app/tools/tools.py @@ -422,7 +422,7 @@ def load_cal(entry: dict) -> Calendar: else: cal = Calendar(imports=r.content.decode()) - cal = horodate(cal, 'Downloaded at') + cal = horodate(cal, 'Event last fetched: ') return cal From 27064a9c61637235f0fbfec00162842ec54eddf6 Mon Sep 17 00:00:00 2001 From: xelast418 Date: Wed, 20 Sep 2023 20:50:37 +1200 Subject: [PATCH 2/2] 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