/* This file is part of »munin«. Copyright 2025 'Fenris Wolf' »munin« is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. »munin« is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with »munin«. If not, see . */ /** * @todo versioning */ namespace _munin.conf { /** */ type type_reminder_raw = { frequency : ( "hourly" | "daily" | "weekly" | "monthly" ); offset : int; from : int; to : int; }; /** */ type type_conf_v1 = { sources : Array< ( { kind : "kalender_digital"; data : { path : string; filtration : { category_blacklist : Array; title_blacklist : Array; }; }; } ) >; targets : Array< ( { kind : "telegram_bot"; data : { bot_token : string; chat_id : int; /** * in hours */ interval : Array; } } ) >; frequency : float; labels : { head : string; title : string; time : string; location : string; }; }; /** */ type type_conf_v2 = { sources : Array< ( { kind : "ical_feed"; data : { url : string; filtration : { category_blacklist : Array; title_blacklist : Array; } } } ) >; targets : Array< ( { kind : "telegram_bot"; data : { bot_token : string; chat_id : int; /** * in hours */ reminders : Array; } } ) >; settings : { interval : float; }; labels : { head : string; title : string; time : string; location : string; }; }; /** */ type type_conf_v3 = { sources : Array< ( { kind : "ical_feed"; data : { url : string; filtration : { category_blacklist : Array; title_blacklist : Array; } } } ) >; targets : Array< ( { kind : "email"; data : { smtp_host : string; smtp_port : int; smtp_username : string; smtp_password : string; sender : string; receivers : Array; /** * in hours */ reminders : Array; } } | { kind : "telegram_bot"; data : { bot_token : string; chat_id : int; /** * in hours */ reminders : Array; } } ) >; settings : { interval : float; }; labels : { head : string; title : string; time : string; location : string; }; }; /** */ type type_conf_v4 = { sources : Array< ( { kind : "ical_feed"; data : { url : string; filtration : { category_whitelist : (null | Array); category_blacklist : (null | Array); title_whitelist : (null | Array); title_blacklist : (null | Array); } } } ) >; targets : Array< ( { kind : "email"; data : { smtp_host : string; smtp_port : int; smtp_username : string; smtp_password : string; sender : string; receivers : Array; hide_tags : boolean; /** * in hours */ reminders : Array; } } | { kind : "telegram_bot"; data : { bot_token : string; chat_id : int; hide_tags : boolean; /** * in hours */ reminders : Array; } } ) >; settings : { interval : float; }; labels : { head : string; title : string; time : string; location : string; }; }; /** */ type type_conf_v5 = { sources : Array< ( { kind : "ical_feed"; data : { url : string; filtration : { category_whitelist : (null | Array); category_blacklist : (null | Array); title_whitelist : (null | Array); title_blacklist : (null | Array); } } } ) >; targets : Array< ( { kind : "email"; data : { smtp_host : string; smtp_port : int; smtp_username : string; smtp_password : string; sender : string; receivers : Array; hide_tags : boolean; /** * in hours */ reminders : Array; } } | { kind : "telegram_bot"; data : { bot_token : string; chat_id : int; hide_tags : boolean; /** * in hours */ reminders : Array; } } ) >; settings : { interval : float; }; labels : { head : string; title : string; time : string; location : string; }; }; /** */ export type type_conf = type_conf_v5; /** */ function convert_from_v1( conf_v1 : type_conf_v1 ) : type_conf_v2 { return { "sources": conf_v1.sources.map( source => { switch (source.kind) { case "kalender_digital": { return { "kind": "ical_feed", "data": { "url": lib_plankton.url.encode( { "scheme": "https", "host": "export.kalender.digital", "username": null, "password": null, "port": null, "path": ("/ics/" + source.data.path + ".ics"), "query": "past_months=0&future_months=1", "hash": null, } ), "filtration": source.data.filtration, } }; break; } default: { // return source; throw (new Error("unhandled source kind: " + source.kind)); break; } } } ), "targets": conf_v1.targets.map( target => { switch (target.kind) { case "telegram_bot": { return { "kind": "telegram_bot", "data": { "bot_token": target.data.bot_token, "chat_id": target.data.chat_id, "reminders": target.data.interval, }, }; break; } default: { // return target; throw (new Error("unhandled target kind: " + target.kind)); break; } } } ), "settings": { "interval": conf_v1.frequency, }, "labels": conf_v1.labels, }; } /** */ function convert_from_v2( conf_v2 : type_conf_v2 ) : type_conf_v3 { return conf_v2; } /** */ function convert_from_v3( conf_v3 : type_conf_v3 ) : type_conf_v4 { return { "sources": conf_v3.sources.map( source => { switch (source.kind) { case "ical_feed": { return { "kind": "ical_feed", "data": { "url": source.data.url, "filtration": { "category_whitelist": null, "category_blacklist": source.data.filtration.category_blacklist, "title_whitelist": null, "title_blacklist": source.data.filtration.category_blacklist, }, } }; break; } default: { // return source; throw (new Error("unhandled source kind: " + source.kind)); break; } } } ), "targets": conf_v3.targets.map( target => { switch (target.kind) { case "email": { return { "kind": "email", "data": { "smtp_host": target.data.smtp_host, "smtp_port": target.data.smtp_port, "smtp_username": target.data.smtp_username, "smtp_password": target.data.smtp_password, "sender": target.data.sender, "receivers": target.data.receivers, "hide_tags": false, "reminders": target.data.reminders, }, }; break; } case "telegram_bot": { return { "kind": "telegram_bot", "data": { "bot_token": target.data.bot_token, "chat_id": target.data.chat_id, "hide_tags": false, "reminders": target.data.reminders, }, }; break; } default: { // return target; throw (new Error("unhandled target kind: " + String(target))); break; } } } ), "settings": conf_v3.settings, "labels": conf_v3.labels, }; } /** */ function convert_from_v4( conf_v4 : type_conf_v4 ) : type_conf_v5 { const map_reminder = hours => ({ "frequency": "hourly", "offset": 0, "from": hours, "to": (hours + 1), } as type_reminder_raw); return { "sources": conf_v4.sources, "targets": conf_v4.targets.map( target => { switch (target.kind) { case "email": { return { "kind": "email", "data": { "smtp_host": target.data.smtp_host, "smtp_port": target.data.smtp_port, "smtp_username": target.data.smtp_username, "smtp_password": target.data.smtp_password, "sender": target.data.sender, "receivers": target.data.receivers, "hide_tags": target.data.hide_tags, "reminders": target.data.reminders.map(map_reminder), }, }; break; } case "telegram_bot": { return { "kind": "telegram_bot", "data": { "bot_token": target.data.bot_token, "chat_id": target.data.chat_id, "hide_tags": target.data.hide_tags, "reminders": target.data.reminders.map(map_reminder), }, }; break; } default: { // return target; throw (new Error("unhandled target kind: " + String(target))); break; } } } ), "settings": conf_v4.settings, "labels": conf_v4.labels, }; } /** */ function schema_source_kalender_digital( version : string ) : lib_plankton.conf.type_schema { return { "type": "object", "properties": { "kind": { "nullable": false, "type": "string", "enum": ["kalender_digital"] }, "data": { "nullable": false, "type": "object", "properties": { "path": { "nullable": false, "type": "string" }, "filtration": { "nullable": false, "type": "object", "properties": { "category_blacklist": { "nullable": true, "type": "array", "items": { "nullable": false, "type": "string", }, "default": [], }, "title_blacklist": { "nullable": true, "type": "array", "items": { "nullable": false, "type": "string", }, "default": [], }, }, "additionalProperties": false, "required": [ ], "default": {} }, }, "additionalProperties": false, "required": [ "path", ] } }, "additionalProperties": false, "required": [ "kind", "data", ] }; } /** */ function schema_source_ical_feed( version : string ) : lib_plankton.conf.type_schema { return { "type": "object", "properties": { "kind": { "nullable": false, "type": "string", "enum": ["ical_feed"] }, "data": { "nullable": false, "type": "object", "properties": { "url": { "nullable": false, "type": "string" }, "filtration": { "nullable": false, "type": "object", "properties": { "category_whitelist": { "nullable": true, "type": "array", "items": { "nullable": false, "type": "string", }, "default": null, }, "category_blacklist": { "nullable": true, "type": "array", "items": { "nullable": false, "type": "string", }, "default": null, }, "title_whitelist": { "nullable": true, "type": "array", "items": { "nullable": false, "type": "string", }, "default": null, }, "title_blacklist": { "nullable": true, "type": "array", "items": { "nullable": false, "type": "string", }, "default": null, }, }, "additionalProperties": false, "required": [ ], "default": {} }, }, "additionalProperties": false, "required": [ "url", ] } }, "additionalProperties": false, "required": [ "kind", "data", ] }; } /** */ function schema_sources( version : string ) : lib_plankton.conf.type_schema { switch (version) { case "1": { return { "nullable": false, "type": "array", "items": { "nullable": false, "anyOf": [ schema_source_kalender_digital(version), ], } }; break; } default: case "2": { return { "nullable": false, "type": "array", "items": { "nullable": false, "anyOf": [ schema_source_ical_feed(version), ], } }; break; } } } /** */ function schema_reminder( version : string ) : lib_plankton.conf.type_schema { switch (version) { case "1": case "2": case "3": case "4": { return { "type": "integer", }; } case "5": default: { return { "nullable": false, "type": "object", "properties": { "frequency": { "nullable": false, "type": "string", "enum": [ "hourly", "daily", "weekly", "monthly", ] }, "offset": { "nullable": false, "type": "integer", "default": 0 }, "from": { "nullable": false, "type": "integer" }, "to": { "nullable": false, "type": "integer" }, }, "additionalProperties": false, "required": [ "frequency", "from", "to", ] }; break; } } } /** */ function default_reminder( version : string ) : any { switch (version) { case "1": case "2": case "3": case "4": { return [24]; } case "5": default: { return [ { "frequency": "hourly", "from": 24, "to": 25 } ]; break; } } } /** */ function schema_target_email( version : string ) : lib_plankton.conf.type_schema { return { "nullable": false, "type": "object", "properties": { "kind": { "nullable": false, "type": "string", "enum": ["email"] }, "data": { "nullable": false, "type": "object", "properties": { "smtp_host": { "nullable": false, "type": "string", }, "smtp_port": { "nullable": false, "type": "integer", }, "smtp_username": { "nullable": false, "type": "string", }, "smtp_password": { "nullable": false, "type": "string", }, "sender": { "nullable": false, "type": "string", "default": "munin" }, "receivers": { "nullable": false, "type": "array", "items": { "nullable": false, "type": "string", } }, "hide_tags": { "nullable": false, "type": "boolean", "default": false, }, "reminders": { "nullable": false, "type": "array", "items": schema_reminder(version), "default": default_reminder(version), }, }, "additionalProperties": false, "required": [ "smtp_host", "smtp_port", "smtp_username", "smtp_password", "receivers", ] } }, "additionalProperties": false, "required": [ "kind", "data", ] }; } /** */ function schema_target_telegram_bot( version : string ) : lib_plankton.conf.type_schema { return { "nullable": false, "type": "object", "properties": { "kind": { "nullable": false, "type": "string", "enum": ["telegram_bot"] }, "data": { "nullable": false, "type": "object", "properties": { "bot_token": { "nullable": false, "type": "string", }, "chat_id": { "nullable": false, "type": "integer", }, "hide_tags": { "nullable": false, "type": "boolean", "default": false, }, "reminders": { "nullable": false, "type": "array", "items": schema_reminder(version), "default": default_reminder(version), }, }, "additionalProperties": false, "required": [ "bot_token", "chat_id", ] } }, "additionalProperties": false, "required": [ "kind", "data", ] }; } /** */ function schema_targets( version : string ) : lib_plankton.conf.type_schema { return { "nullable": false, "type": "array", "items": { "nullable": false, "anyOf": (() => { switch (version) { case "1": case "2": { return [ schema_target_telegram_bot(version), ]; break; } case "4": case "5": default: { return [ schema_target_email(version), schema_target_telegram_bot(version), ]; break; } } }) (), } }; } /** */ function schema_settings( version : string ) : lib_plankton.conf.type_schema { return { "nullable": false, "type": "object", "properties": { "interval": { "nullable": false, "type": "number", "default": 1.0 } }, "additionalProperties": false, "required": [ ], "default": { } }; } /** */ function schema_labels( version : string ) : lib_plankton.conf.type_schema { return { "nullable": false, "type": "object", "properties": { "head": { "nullable": false, "type": "string", "default": "Termin-Erinnerung" }, "title": { "nullable": false, "type": "string", "default": "was" }, "time": { "nullable": false, "type": "string", "default": "wann" }, "location": { "nullable": false, "type": "string", "default": "wo" }, }, "additionalProperties": false, "required": [ ], "default": {} }; } /** */ export function schema( version : string = "5" ) : lib_plankton.conf.type_schema { switch (version) { case "1": { return { "nullable": false, "type": "object", "properties": { "sources": schema_sources(version), "targets": schema_targets(version), "frequency": { "nullable": false, "type": "number", "default": 1.0, }, "labels": schema_labels(version), }, "additionalProperties": false, "required": [ "sources", "targets", ], }; break; } case "2": case "3": case "4": case "5": { return { "nullable": false, "type": "object", "properties": { "sources": schema_sources(version), "targets": schema_targets(version), "settings": schema_settings(version), "labels": schema_labels(version), }, "additionalProperties": false, "required": [ "sources", "targets", ], }; break; } } } /** */ export async function load( path : string ) : Promise { const conf_raw : {version : string; content : any} = await lib_plankton.conf.load_versioned( path, schema, { "1": {"target": "2", "function": convert_from_v1}, "2": {"target": "3", "function": convert_from_v2}, "3": {"target": "4", "function": convert_from_v3}, "4": {"target": "5", "function": convert_from_v4}, "5": null, } ); /* switch (conf_raw.version) { case "1": { const conf_v1 : type_conf_v1 = (conf_raw.content as type_conf_v1); const conf_v2 : type_conf_v2 = convert_from_v1(conf_v1); const conf_v3 : type_conf_v3 = convert_from_v2(conf_v2); const conf_v4 : type_conf_v4 = convert_from_v3(conf_v3); return conf_v4; break; } case "2": { const conf_v2 : type_conf_v2 = (conf_raw.content as type_conf_v2); const conf_v3 : type_conf_v3 = convert_from_v2(conf_v2); const conf_v4 : type_conf_v4 = convert_from_v3(conf_v3); return conf_v4; break; } case "3": { const conf_v3 : type_conf_v3 = (conf_raw.content as type_conf_v3); const conf_v4 : type_conf_v4 = convert_from_v3(conf_v3); return conf_v4; break; } case "4": { const conf_v4 : type_conf_v4 = (conf_raw.content as type_conf_v4); return conf_v4; break; } default: { throw (new Error("invalid version: " + conf_raw.version)); break; } } */ return (conf_raw.content as type_conf_v5); } }