[task-340] soweit fertig

This commit is contained in:
fenris 2025-06-30 13:02:06 +02:00
parent 37f7a27e95
commit 21c2d9945c
9 changed files with 546 additions and 483 deletions

View file

@ -0,0 +1,218 @@
[
{
"name": "reminder_check.dueness-1",
"input": {
"reminder": {
"frequency": "daily",
"offset": 16,
"from": 24,
"to": 48
},
"events": [
],
"datetime": {
"timezone_shift": 0,
"date": {
"year": 2025,
"month": 6,
"day": 27
},
"time": {
"hour": 15,
"minute": 30,
"second": 0
}
},
"interval": 1
},
"output": null
},
{
"name": "reminder_check.dueness-2",
"input": {
"reminder": {
"frequency": "daily",
"offset": 16,
"from": 24,
"to": 48
},
"events": [
],
"datetime": {
"timezone_shift": 0,
"date": {
"year": 2025,
"month": 6,
"day": 27
},
"time": {
"hour": 16,
"minute": 30,
"second": 0
}
},
"interval": 1
},
"output": []
},
{
"name": "reminder_check.dueness-3",
"input": {
"reminder": {
"frequency": "daily",
"offset": 16,
"from": 24,
"to": 48
},
"events": [
],
"datetime": {
"timezone_shift": 0,
"date": {
"year": 2025,
"month": 6,
"day": 27
},
"time": {
"hour": 17,
"minute": 30,
"second": 0
}
},
"interval": 1
},
"output": null
},
{
"name": "reminder_check.events-1",
"input": {
"reminder": {
"frequency": "daily",
"offset": 16,
"from": 24,
"to": 48
},
"events": [
{
"title": "e1",
"begin": {
"timezone_shift": 0,
"date": {
"year": 2025,
"month": 6,
"day": 27
},
"time": {
"hour": 12,
"minute": 0,
"second": 0
}
}
}
],
"datetime": {
"timezone_shift": 0,
"date": {
"year": 2025,
"month": 6,
"day": 27
},
"time": {
"hour": 16,
"minute": 30,
"second": 0
}
},
"interval": 1
},
"output": []
},
{
"name": "reminder_check.events-2",
"input": {
"reminder": {
"frequency": "daily",
"offset": 16,
"from": 24,
"to": 48
},
"events": [
{
"title": "e1",
"begin": {
"timezone_shift": 0,
"date": {
"year": 2025,
"month": 6,
"day": 28
},
"time": {
"hour": 12,
"minute": 0,
"second": 0
}
}
}
],
"datetime": {
"timezone_shift": 0,
"date": {
"year": 2025,
"month": 6,
"day": 27
},
"time": {
"hour": 16,
"minute": 30,
"second": 0
}
},
"interval": 1
},
"output": ["e1"]
},
{
"name": "reminder_check.events-3",
"input": {
"reminder": {
"frequency": "daily",
"offset": 16,
"from": 24,
"to": 48
},
"events": [
{
"title": "e1",
"begin": {
"timezone_shift": 0,
"date": {
"year": 2025,
"month": 6,
"day": 29
},
"time": {
"hour": 12,
"minute": 0,
"second": 0
}
}
}
],
"datetime": {
"timezone_shift": 0,
"date": {
"year": 2025,
"month": 6,
"day": 27
},
"time": {
"hour": 16,
"minute": 30,
"second": 0
}
},
"interval": 1
},
"output": []
}
]

View file

@ -1,122 +0,0 @@
[
{
"input": {
"reminder": {
"frequency": "daily",
"offset": 0,
"from": 24,
"to": 48
},
"event": {
"begin": {
"timezone_shift": 0,
"date": {
"year": 2025,
"month": 6,
"day": 25
},
"time": {
"hour": 12,
"minute": 0,
"second": 0
}
}
},
"datetime": {
"timezone_shift": 0,
"date": {
"year": 2025,
"month": 6,
"day": 23
},
"time": {
"hour": 10,
"minute": 0,
"second": 0
}
},
"interval": 1
},
"output": false
},
{
"input": {
"reminder": {
"frequency": "daily",
"offset": 0,
"from": 24,
"to": 48
},
"event": {
"begin": {
"timezone_shift": 0,
"date": {
"year": 2025,
"month": 6,
"day": 25
},
"time": {
"hour": 12,
"minute": 0,
"second": 0
}
}
},
"datetime": {
"timezone_shift": 0,
"date": {
"year": 2025,
"month": 6,
"day": 24
},
"time": {
"hour": 10,
"minute": 0,
"second": 0
}
},
"interval": 1
},
"output": true
},
{
"input": {
"reminder": {
"frequency": "daily",
"offset": 0,
"from": 24,
"to": 48
},
"event": {
"begin": {
"timezone_shift": 0,
"date": {
"year": 2025,
"month": 6,
"day": 25
},
"time": {
"hour": 12,
"minute": 0,
"second": 0
}
}
},
"datetime": {
"timezone_shift": 0,
"date": {
"year": 2025,
"month": 6,
"day": 25
},
"time": {
"hour": 10,
"minute": 0,
"second": 0
}
},
"interval": 1
},
"output": false
}
]

View file

@ -1,77 +0,0 @@
[
{
"input": {
"reminder": {
"frequency": "daily",
"offset": 16,
"from": 24,
"to": 48
},
"datetime": {
"timezone_shift": 0,
"date": {
"year": 2025,
"month": 6,
"day": 27
},
"time": {
"hour": 15,
"minute": 30,
"second": 0
}
},
"interval": 1
},
"output": false
},
{
"input": {
"reminder": {
"frequency": "daily",
"offset": 16,
"from": 24,
"to": 48
},
"datetime": {
"timezone_shift": 0,
"date": {
"year": 2025,
"month": 6,
"day": 27
},
"time": {
"hour": 16,
"minute": 30,
"second": 0
}
},
"interval": 1
},
"output": true
},
{
"input": {
"reminder": {
"frequency": "daily",
"offset": 16,
"from": 24,
"to": 48
},
"datetime": {
"timezone_shift": 0,
"date": {
"year": 2025,
"month": 6,
"day": 27
},
"time": {
"hour": 17,
"minute": 30,
"second": 0
}
},
"interval": 1
},
"output": false
}
]

View file

@ -312,6 +312,7 @@ namespace _munin.conf
title : string; title : string;
time : string; time : string;
location : string; location : string;
events : string;
}; };
}; };
@ -532,7 +533,7 @@ namespace _munin.conf
} }
), ),
"settings": conf_v4.settings, "settings": conf_v4.settings,
"labels": conf_v4.labels, "labels": Object.assign({"events": "Termine"}, conf_v4.labels),
}; };
} }
@ -1044,6 +1045,11 @@ namespace _munin.conf
"type": "string", "type": "string",
"default": "wo" "default": "wo"
}, },
"events": {
"nullable": false,
"type": "string",
"default": "Termine"
},
}, },
"additionalProperties": false, "additionalProperties": false,
"required": [ "required": [

View file

@ -67,101 +67,64 @@ namespace _munin.logic
/** /**
*/ */
export function reminder_due( export function reminder_check(
reminder : type_reminder, reminder : type_reminder,
events_all : Array<_munin.type_event>,
{ {
"pit": pit = lib_plankton.pit.now(), "pit": pit = lib_plankton.pit.now(),
"interval": interval = 1, "interval": interval = 1,
} : { }
: {
pit ?: lib_plankton.pit.type_pit; pit ?: lib_plankton.pit.type_pit;
interval ?: int; interval ?: int;
} = {
} }
) : boolean = {
}
) : (null | Array<_munin.type_event>)
{ {
const anchor : lib_plankton.pit.type_pit = frequency_anchor( const anchor : lib_plankton.pit.type_pit = frequency_anchor(
reminder.frequency, reminder.frequency,
{"pit": pit} {"pit": pit}
); );
const window_from : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour( const dueness_window_from : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour(
anchor, anchor,
(reminder.offset + 0) (reminder.offset + 0)
); );
const window_to : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour( const dueness_window_to : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour(
anchor, anchor,
(reminder.offset + interval) (reminder.offset + interval)
); );
const result : boolean = lib_plankton.pit.is_between( const due : boolean = lib_plankton.pit.is_between(
pit, pit,
window_from, dueness_window_from,
window_to dueness_window_to
); );
lib_plankton.log._info( if (! due)
"munin.logic.reminder_due",
{
"details": {
"reminder": reminder,
"datetime": lib_plankton.pit.to_datetime(pit),
"interval": interval,
"anchor": lib_plankton.pit.to_datetime(anchor),
"window_from": lib_plankton.pit.to_datetime(window_from),
"window_to": lib_plankton.pit.to_datetime(window_to),
"result": result,
}
}
);
return result;
}
/**
*/
export function reminder_covers_event(
reminder : type_reminder,
event : _munin.type_event,
{ {
"pit": pit = lib_plankton.pit.now(), return null;
} : { }
pit ?: lib_plankton.pit.type_pit; else
} = { {
const events_window_from : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour(
anchor,
reminder.from
);
const events_window_to : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour(
anchor,
reminder.to
);
const events : Array<_munin.type_event> = (
events_all
.filter(
(event) => lib_plankton.pit.is_between(
lib_plankton.pit.from_datetime(event.begin),
events_window_from,
events_window_to
)
)
);
return events;
} }
) : boolean
{
const anchor : lib_plankton.pit.type_pit = frequency_anchor(
reminder.frequency,
{"pit": pit}
);
const window_from : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour(
anchor,
reminder.from
);
const window_to : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour(
anchor,
reminder.to
);
const event_begin : lib_plankton.pit.type_pit = lib_plankton.pit.from_datetime(
event.begin
);
const result : boolean = lib_plankton.pit.is_between(
event_begin,
window_from,
window_to
);
lib_plankton.log._info(
"munin.logic.reminder_covers_event",
{
"details": {
"reminder": reminder,
"event": event,
"datetime": lib_plankton.pit.to_datetime(pit),
"anchor": lib_plankton.pit.to_datetime(anchor),
"window_from": lib_plankton.pit.to_datetime(window_from),
"window_to": lib_plankton.pit.to_datetime(window_to),
"result": result,
}
}
);
return result;
} }
@ -173,76 +136,85 @@ namespace _munin.logic
targets : Array<_munin.type_target>, targets : Array<_munin.type_target>,
{ {
"dry_run": dry_run = false, "dry_run": dry_run = false,
} : { }
: {
dry_run ?: boolean; dry_run ?: boolean;
} = { }
= {
} }
) : Promise<void> ) : Promise<void>
{ {
const now : lib_plankton.pit.type_pit = lib_plankton.pit.now(); const now : lib_plankton.pit.type_pit = lib_plankton.pit.now();
const events : Array<_munin.type_event> = ( const events_all : Array<_munin.type_event> = (
(await Promise.all(sources.map(source => source.fetch()))) (await Promise.all(sources.map(source => source.fetch())))
.reduce((x, y) => x.concat(y), []) .reduce((x, y) => x.concat(y), [])
); );
for (const target of targets) { for (const target of targets)
for (const reminder of target.reminders) { {
const due : boolean = reminder_due( for (const reminder of target.reminders)
{
const events : Array<_munin.type_event> = reminder_check(
reminder, reminder,
events_all,
{ {
"pit": now, "pit": now,
"interval": conf.settings.interval, "interval": conf.settings.interval,
} }
); );
if (! due) if (events === null)
{ {
// do nothing lib_plankton.log._info(
} "munin.run_iteration.reminder_not_due",
else {
{ "details": {
const events_matching : Array<_munin.type_event> = events.filter( "reminder": reminder,
event => reminder_covers_event(
reminder,
event,
{
"pit": now,
} }
) }
);
}
else {
if (events.length <= 0)
{
lib_plankton.log._info(
"munin.run_iteration.no_matching_events",
{
"details": {
"reminder": reminder,
}
}
); );
if (events_matching.length <= 0) {
// do nothing
} }
else { else {
lib_plankton.log._info( lib_plankton.log._info(
"munin.remind.do", "munin.run_iteration.remind",
{ {
"details": { "details": {
"reminder": reminder,
"events": events, "events": events,
"target": target.show(), "target": target.show(),
} }
} }
); );
if (dry_run) { if (dry_run)
{
// do nothing // do nothing
} }
else { else
/** {
* @todo bundle? try
*/
for (const event of events_matching)
{ {
try { await target.send(conf.labels, events);
await target.send(conf.labels, event); }
} catch (error)
catch (error) { {
lib_plankton.log.error( lib_plankton.log.error(
"munin.remind.error", "munin.remind.error",
{ {
"details": { "details": {
"message": String(error), "message": String(error),
}
} }
); }
} );
} }
} }
} }

View file

@ -37,10 +37,97 @@ namespace _munin.targets.email
/** /**
*/ */
async function send( function summarize_event(
parameters : type_parameters, parameters : type_parameters,
labels : _munin.type_labels, labels : _munin.type_labels,
event : _munin.type_event event : _munin.type_event
) : string
{
return lib_plankton.string.coin(
"[{{head}}] {{date}} : {{macro_tags}}{{title}}",
{
"head": labels.head,
"date": lib_plankton.pit.date_format(
event.begin.date
),
"macro_tags": (
(event.tags === null)
?
""
:
(event.tags.map(tag => ("{" + tag + "}")).join(" ") + " ")
),
"title": event.title,
}
);
}
/**
*/
function render_event(
parameters : type_parameters,
labels : _munin.type_labels,
event : _munin.type_event
) : string
{
return lib_plankton.string.coin(
"{{title_label}} | {{macro_tags}}{{title_value}}\n{{time_label}} | {{time_value}}{{macro_location}}{{macro_description}}",
{
"title_label": labels.title.toUpperCase(),
"macro_tags": (
(parameters.hide_tags || (event.tags === null))
?
""
:
(event.tags.map(tag => ("{" + tag + "}")).join(" ") + " ")
),
"title_value": event.title,
"time_label": labels.time.toUpperCase(),
"time_value": lib_plankton.pit.timespan_format(
event.begin,
event.end,
{
"adjust_to_ce": true,
}
),
"macro_location": (
(event.location === null)
?
""
:
lib_plankton.string.coin(
"\n{{location_label}} | {{location_value}}",
{
"location_label": labels.location.toUpperCase(),
"location_value": event.location,
}
)
),
"macro_description": (
(event.description === null)
?
""
:
lib_plankton.string.coin(
"\n\n{{description_value}}",
{
"description_value": event.description,
}
)
),
}
);
}
/**
*/
async function send(
parameters : type_parameters,
labels : _munin.type_labels,
events : Array<_munin.type_event>
) : Promise<void> ) : Promise<void>
{ {
await lib_plankton.email.send( await lib_plankton.email.send(
@ -52,69 +139,24 @@ namespace _munin.targets.email
}, },
parameters.sender, parameters.sender,
parameters.receivers, parameters.receivers,
lib_plankton.string.coin( (
"[{{head}}] {{date}} : {{macro_tags}}{{title}}", (events.length === 1)
{ ?
"head": labels.head, summarize_event(parameters, labels, events[0])
"date": lib_plankton.pit.date_format( :
event.begin.date lib_plankton.string.coin(
), "[{{head}}] {{count}} {{events}}",
"macro_tags": ( {
(event.tags === null) "head": labels.head,
? "count": events.length.toFixed(0),
"" "events": labels.events,
: }
(event.tags.map(tag => ("{" + tag + "}")).join(" ") + " ") )
),
"title": event.title,
}
), ),
lib_plankton.string.coin( (
"{{title_label}} | {{macro_tags}}{{title_value}}\n{{time_label}} | {{time_value}}{{macro_location}}{{macro_description}}", events
{ .map(event => render_event(parameters, labels, event))
"title_label": labels.title.toUpperCase(), .join("\n\n---\n\n")
"macro_tags": (
(parameters.hide_tags || (event.tags === null))
?
""
:
(event.tags.map(tag => ("{" + tag + "}")).join(" ") + " ")
),
"title_value": event.title,
"time_label": labels.time.toUpperCase(),
"time_value": lib_plankton.pit.timespan_format(
event.begin,
event.end,
{
"adjust_to_ce": true,
}
),
"macro_location": (
(event.location === null)
?
""
:
lib_plankton.string.coin(
"\n{{location_label}} | {{location_value}}",
{
"location_label": labels.location.toUpperCase(),
"location_value": event.location,
}
)
),
"macro_description": (
(event.description === null)
?
""
:
lib_plankton.string.coin(
"\n\n{{description_value}}",
{
"description_value": event.description,
}
)
),
}
) )
); );
} }
@ -134,7 +176,7 @@ namespace _munin.targets.email
"receivers": parameters.receivers.join(","), "receivers": parameters.receivers.join(","),
} }
), ),
"send": (labels, event) => send(parameters, labels, event), "send": (labels, events) => send(parameters, labels, events),
}; };
} }

View file

@ -33,60 +33,94 @@ namespace _munin.targets.telegram_bot
/** /**
*/ */
async function send( function render_event(
parameters : type_parameters, parameters : type_parameters,
labels : _munin.type_labels, labels : _munin.type_labels,
event : _munin.type_event event : _munin.type_event
) : string
{
return lib_plankton.string.coin(
"{{title_label}} | {{macro_tags}}{{title_value}}\n{{time_label}} | {{time_value}}{{macro_location}}{{macro_description}}",
{
"macro_tags": (
(parameters.hide_tags || (event.tags === null))
?
""
:
(event.tags.map(tag => ("{" + tag + "}")).join(" ") + " ")
),
"title_label": labels.title.toUpperCase(),
"title_value": event.title,
"time_label": labels.time.toUpperCase(),
"time_value": lib_plankton.pit.timespan_format(
event.begin,
event.end,
{
"adjust_to_ce": true,
}
),
"macro_location": (
(event.location === null)
?
""
:
lib_plankton.string.coin(
"\n{{location_label}} | {{location_value}}",
{
"location_label": labels.location.toUpperCase(),
"location_value": event.location,
}
)
),
"macro_description": (
(event.description === null)
?
""
:
lib_plankton.string.coin(
"\n\n{{description_value}}",
{
"description_value": event.description,
}
)
),
}
);
}
/**
*/
async function send(
parameters : type_parameters,
labels : _munin.type_labels,
events : Array<_munin.type_event>
) : Promise<void> ) : Promise<void>
{ {
await lib_plankton.telegram.bot_call_send_message( await lib_plankton.telegram.bot_call_send_message(
parameters.bot_token, parameters.bot_token,
parameters.chat_id, parameters.chat_id,
lib_plankton.string.coin( lib_plankton.string.coin(
"*{{head}}*\n\n\{{title_label}} | {{macro_tags}}{{title_value}}\n{{time_label}} | {{time_value}}{{macro_location}}{{macro_description}}", "*{{head_core}}{{head_extra}}*\n\n{{events}}",
{ {
"head": labels.head, "head_core": labels.head,
"macro_tags": ( "head_extra": (
(parameters.hide_tags || (event.tags === null)) (events.length <= 1)
?
""
:
(event.tags.map(tag => ("{" + tag + "}")).join(" ") + " ")
),
"title_label": labels.title.toUpperCase(),
"title_value": event.title,
"time_label": labels.time.toUpperCase(),
"time_value": lib_plankton.pit.timespan_format(
event.begin,
event.end,
{
"adjust_to_ce": true,
}
),
"macro_location": (
(event.location === null)
? ?
"" ""
: :
lib_plankton.string.coin( lib_plankton.string.coin(
"\n{{location_label}} | {{location_value}}", " ({{count}} {{events}})",
{ {
"location_label": labels.location.toUpperCase(), "count": events.length.toFixed(0),
"location_value": event.location, "events": labels.events,
} }
) )
), ),
"macro_description": ( "events": (
(event.description === null) events
? .map(event => render_event(parameters, labels, event))
"" .join("\n\n---\n\n")
:
lib_plankton.string.coin(
"\n\n{{description_value}}",
{
"description_value": event.description,
}
)
), ),
} }
), ),
@ -111,7 +145,7 @@ namespace _munin.targets.telegram_bot
"chat_id": parameters.chat_id.toFixed(0), "chat_id": parameters.chat_id.toFixed(0),
} }
), ),
"send": (labels, event) => send(parameters, labels, event), "send": (labels, events) => send(parameters, labels, events),
}; };
} }

View file

@ -20,10 +20,28 @@ along with »munin«. If not, see <http://www.gnu.org/licenses/>.
namespace _munin.test namespace _munin.test
{ {
/**
* @todo outsource?
*/
function lists_equal<type_element>(
list1 : Array<type_element>,
list2 : Array<type_element>
) : boolean
{
return (
(list1.length === list2.length)
&&
list1.every(
(element, index) => (element === list2[index])
)
);
}
/** /**
*/ */
async function reminder_due( async function reminder_check(
) : Promise<void> ) : Promise<void>
{ {
type type_input = { type type_input = {
@ -33,73 +51,23 @@ namespace _munin.test
from : int; from : int;
to : int; to : int;
}; };
datetime : lib_plankton.pit.type_datetime; events : Array<
interval : int;
};
type type_output = boolean;
const testcases : Array<
_munin.helpers.test.type_testcase<
type_input,
type_output
>
> = await _munin.helpers.test.get_data<type_input, type_output>(
"data/reminder_due.testdata.json",
{
}
);
for (const testcase of testcases)
{
_munin.helpers.test.start(testcase.name);
// execution
const result : boolean = _munin.logic.reminder_due(
{ {
"frequency": _munin.logic.frequency_decode(testcase.input.reminder.frequency), title : string;
"offset": testcase.input.reminder.offset, begin : lib_plankton.pit.type_datetime;
"from": testcase.input.reminder.from,
"to": testcase.input.reminder.to,
},
{
"pit": lib_plankton.pit.from_datetime(testcase.input.datetime),
"interval": testcase.input.interval,
} }
); >;
// assertions
if (result !== testcase.output)
{
_munin.helpers.test.fail(testcase.name);
}
}
}
/**
*/
async function reminder_covers_event(
) : Promise<void>
{
type type_input = {
reminder : {
frequency : string;
offset : int;
from : int;
to : int;
};
event : {
begin : lib_plankton.pit.type_datetime;
};
datetime : lib_plankton.pit.type_datetime; datetime : lib_plankton.pit.type_datetime;
interval : int; interval : int;
}; };
type type_output = boolean; type type_output = (null | Array<string>);
const testcases : Array< const testcases : Array<
_munin.helpers.test.type_testcase< _munin.helpers.test.type_testcase<
type_input, type_input,
type_output type_output
> >
> = await _munin.helpers.test.get_data<type_input, type_output>( > = await _munin.helpers.test.get_data<type_input, type_output>(
"data/reminder_covers_event.testdata.json", "data/reminder_check.testdata.json",
{ {
} }
); );
@ -109,28 +77,50 @@ namespace _munin.test
_munin.helpers.test.start(testcase.name); _munin.helpers.test.start(testcase.name);
// execution // execution
const result : boolean = _munin.logic.reminder_covers_event( const result : (null | Array<_munin.type_event>) = _munin.logic.reminder_check(
{ {
"frequency": _munin.logic.frequency_decode(testcase.input.reminder.frequency), "frequency": _munin.logic.frequency_decode(testcase.input.reminder.frequency),
"offset": testcase.input.reminder.offset, "offset": testcase.input.reminder.offset,
"from": testcase.input.reminder.from, "from": testcase.input.reminder.from,
"to": testcase.input.reminder.to, "to": testcase.input.reminder.to,
}, },
{ testcase.input.events.map(
"title": "test", event_raw => ({
"begin": testcase.input.event.begin, "title": event_raw.title,
"end": null, "begin": event_raw.begin,
"description": null, "end": null,
"location": null, "description": null,
"tags": null, "location": null,
}, "tags": null,
})
),
{ {
"pit": lib_plankton.pit.from_datetime(testcase.input.datetime), "pit": lib_plankton.pit.from_datetime(testcase.input.datetime),
"interval": testcase.input.interval,
} }
); );
// assertions // assertions
if (result !== testcase.output) if (
(
(testcase.output === null)
&&
(result === null)
)
||
(
(testcase.output !== null)
&&
lists_equal<string>(
result.map(event => event.title),
testcase.output
)
)
)
{
// success
}
else
{ {
_munin.helpers.test.fail(testcase.name); _munin.helpers.test.fail(testcase.name);
} }
@ -143,8 +133,7 @@ namespace _munin.test
export async function all( export async function all(
) : Promise<void> ) : Promise<void>
{ {
await reminder_due(); await reminder_check();
await reminder_covers_event();
} }
} }

View file

@ -38,6 +38,7 @@ namespace _munin
title : string; title : string;
time : string; time : string;
location : string; location : string;
events : string;
}; };
@ -84,7 +85,7 @@ namespace _munin
send : ( send : (
( (
labels : type_labels, labels : type_labels,
event : type_event events : Array<type_event>
) )
=> =>
Promise<void> Promise<void>