Merge branch 'main' of pv-svartalfheim-git:fenris/munin
This commit is contained in:
commit
27d263a52a
29
ivaldi.json
Normal file
29
ivaldi.json
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"name": "munin",
|
||||||
|
"libs": [
|
||||||
|
{
|
||||||
|
"kind": "plankton",
|
||||||
|
"data": {
|
||||||
|
"modules": [
|
||||||
|
"pit",
|
||||||
|
"http",
|
||||||
|
"ical",
|
||||||
|
"telegram",
|
||||||
|
"conf",
|
||||||
|
"log",
|
||||||
|
"args"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sources": [
|
||||||
|
"types.ts",
|
||||||
|
"sources/kalender_digital.ts",
|
||||||
|
"sources/_functions.ts",
|
||||||
|
"targets/telegram_bot.ts",
|
||||||
|
"targets/_functions.ts",
|
||||||
|
"conf.ts",
|
||||||
|
"main.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
31
libs/plankton/plankton.d.ts
vendored
31
libs/plankton/plankton.d.ts
vendored
|
@ -1,11 +1,11 @@
|
||||||
/**
|
/**
|
||||||
* @author fenris
|
* @author fenris
|
||||||
*/
|
*/
|
||||||
type int = number;
|
declare type int = number;
|
||||||
/**
|
/**
|
||||||
* @author fenris
|
* @author fenris
|
||||||
*/
|
*/
|
||||||
type float = number;
|
declare type float = number;
|
||||||
declare var process: any;
|
declare var process: any;
|
||||||
declare var require: any;
|
declare var require: any;
|
||||||
declare class Buffer {
|
declare class Buffer {
|
||||||
|
@ -22,7 +22,7 @@ declare namespace lib_plankton.base {
|
||||||
/**
|
/**
|
||||||
* @author fenris
|
* @author fenris
|
||||||
*/
|
*/
|
||||||
type type_pseudopointer<type_value> = {
|
declare type type_pseudopointer<type_value> = {
|
||||||
value: type_value;
|
value: type_value;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
|
@ -1205,6 +1205,9 @@ declare namespace lib_plankton.pit {
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
function is_before(pit: type_pit, reference: type_pit): boolean;
|
function is_before(pit: type_pit, reference: type_pit): boolean;
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function is_after(pit: type_pit, reference: type_pit): boolean;
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
function is_between(pit: type_pit, reference_left: type_pit, reference_right: type_pit): boolean;
|
function is_between(pit: type_pit, reference_left: type_pit, reference_right: type_pit): boolean;
|
||||||
|
@ -1217,9 +1220,27 @@ declare namespace lib_plankton.pit {
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
function shift_week(pit: type_pit, increment: int): type_pit;
|
function shift_week(pit: type_pit, increment: int): type_pit;
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function shift_year(pit: type_pit, increment: int): type_pit;
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function trunc_minute(pit: type_pit): type_pit;
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function trunc_hour(pit: type_pit): type_pit;
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function trunc_day(pit: type_pit): type_pit;
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
function trunc_week(pit: type_pit): type_pit;
|
function trunc_week(pit: type_pit): type_pit;
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function trunc_month(pit: type_pit): type_pit;
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function trunc_year(pit: type_pit): type_pit;
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
function now(): type_pit;
|
function now(): type_pit;
|
||||||
|
@ -2237,7 +2258,9 @@ declare namespace lib_plankton.telegram {
|
||||||
/**
|
/**
|
||||||
* @see https://core.telegram.org/bots/api#sendmessage
|
* @see https://core.telegram.org/bots/api#sendmessage
|
||||||
*/
|
*/
|
||||||
function bot_call_send_message(token: string, chat_id: (int | string), text: string): Promise<void>;
|
function bot_call_send_message(token: string, chat_id: (int | string), text: string, { "parse_mode": parse_mode, }?: {
|
||||||
|
parse_mode?: (null | string);
|
||||||
|
}): Promise<void>;
|
||||||
}
|
}
|
||||||
declare namespace lib_plankton.file {
|
declare namespace lib_plankton.file {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1476,7 +1476,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||||
function verb(n) { return function (v) { return step([n, v]); }; }
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||||
function step(op) {
|
function step(op) {
|
||||||
if (f) throw new TypeError("Generator is already executing.");
|
if (f) throw new TypeError("Generator is already executing.");
|
||||||
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
while (_) try {
|
||||||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||||
if (y = 0, t) op = [op[0] & 2, t.value];
|
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||||
switch (op[0]) {
|
switch (op[0]) {
|
||||||
|
@ -3637,6 +3637,7 @@ var lib_plankton;
|
||||||
function is_after(pit, reference) {
|
function is_after(pit, reference) {
|
||||||
return (pit > reference);
|
return (pit > reference);
|
||||||
}
|
}
|
||||||
|
pit_1.is_after = is_after;
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
function is_between(pit, reference_left, reference_right) {
|
function is_between(pit, reference_left, reference_right) {
|
||||||
|
@ -3668,6 +3669,7 @@ var lib_plankton;
|
||||||
function shift_year(pit, increment) {
|
function shift_year(pit, increment) {
|
||||||
return (pit + (60 * 60 * 24 * 365 * increment));
|
return (pit + (60 * 60 * 24 * 365 * increment));
|
||||||
}
|
}
|
||||||
|
pit_1.shift_year = shift_year;
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
function trunc_minute(pit) {
|
function trunc_minute(pit) {
|
||||||
|
@ -3695,6 +3697,7 @@ var lib_plankton;
|
||||||
};
|
};
|
||||||
return from_datetime(datetime_output);
|
return from_datetime(datetime_output);
|
||||||
}
|
}
|
||||||
|
pit_1.trunc_minute = trunc_minute;
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
function trunc_hour(pit) {
|
function trunc_hour(pit) {
|
||||||
|
@ -3718,6 +3721,7 @@ var lib_plankton;
|
||||||
};
|
};
|
||||||
return from_datetime(datetime_output);
|
return from_datetime(datetime_output);
|
||||||
}
|
}
|
||||||
|
pit_1.trunc_hour = trunc_hour;
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
function trunc_day(pit) {
|
function trunc_day(pit) {
|
||||||
|
@ -3737,6 +3741,7 @@ var lib_plankton;
|
||||||
};
|
};
|
||||||
return from_datetime(datetime_output);
|
return from_datetime(datetime_output);
|
||||||
}
|
}
|
||||||
|
pit_1.trunc_day = trunc_day;
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
function trunc_week(pit) {
|
function trunc_week(pit) {
|
||||||
|
@ -3768,6 +3773,7 @@ var lib_plankton;
|
||||||
};
|
};
|
||||||
return from_datetime(datetime_output);
|
return from_datetime(datetime_output);
|
||||||
}
|
}
|
||||||
|
pit_1.trunc_month = trunc_month;
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
function trunc_year(pit) {
|
function trunc_year(pit) {
|
||||||
|
@ -3787,6 +3793,7 @@ var lib_plankton;
|
||||||
};
|
};
|
||||||
return from_datetime(datetime_output);
|
return from_datetime(datetime_output);
|
||||||
}
|
}
|
||||||
|
pit_1.trunc_year = trunc_year;
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
function now() {
|
function now() {
|
||||||
|
@ -6236,10 +6243,11 @@ var lib_plankton;
|
||||||
/**
|
/**
|
||||||
* @see https://core.telegram.org/bots/api#sendmessage
|
* @see https://core.telegram.org/bots/api#sendmessage
|
||||||
*/
|
*/
|
||||||
async function bot_call_send_message(token, chat_id, text) {
|
async function bot_call_send_message(token, chat_id, text, { "parse_mode": parse_mode = null, } = {}) {
|
||||||
const output = await bot_call_generic(token, "sendMessage", {
|
const output = await bot_call_generic(token, "sendMessage", {
|
||||||
"chat_id": chat_id,
|
"chat_id": chat_id,
|
||||||
"text": text,
|
"text": text,
|
||||||
|
"parse_mode": (parse_mode ?? undefined),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
telegram.bot_call_send_message = bot_call_send_message;
|
telegram.bot_call_send_message = bot_call_send_message;
|
||||||
|
|
26
readme.md
26
readme.md
|
@ -2,3 +2,29 @@
|
||||||
|
|
||||||
Sendet Erinnerungen an Termine
|
Sendet Erinnerungen an Termine
|
||||||
|
|
||||||
|
|
||||||
|
## Erstellung
|
||||||
|
|
||||||
|
### Erfordernisse
|
||||||
|
|
||||||
|
- GNU Make
|
||||||
|
- Typescript Compiler
|
||||||
|
|
||||||
|
|
||||||
|
### Anweisungen
|
||||||
|
|
||||||
|
- `tools/build`
|
||||||
|
|
||||||
|
|
||||||
|
## Verwendung
|
||||||
|
|
||||||
|
### Erfordernisse
|
||||||
|
|
||||||
|
- NodeJS
|
||||||
|
|
||||||
|
|
||||||
|
### Anweisungen
|
||||||
|
|
||||||
|
siehe `munin -h`
|
||||||
|
|
||||||
|
|
||||||
|
|
177
source/conf.ts
177
source/conf.ts
|
@ -1,16 +1,38 @@
|
||||||
namespace _lixer_event_reminder.conf
|
/*
|
||||||
|
This file is part of »munin«.
|
||||||
|
|
||||||
|
Copyright 2025 'Fenris Wolf' <fenris@folksprak.org>
|
||||||
|
|
||||||
|
»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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo versioning
|
||||||
|
*/
|
||||||
|
namespace _munin.conf
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export type type_conf = {
|
export type type_conf = {
|
||||||
bot_token : string;
|
|
||||||
sources : Array<
|
sources : Array<
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
kind : "kalender_digital",
|
kind : "kalender_digital",
|
||||||
data : {
|
data : {
|
||||||
id : string;
|
path : string;
|
||||||
filtration : {
|
filtration : {
|
||||||
category_blacklist : Array<string>;
|
category_blacklist : Array<string>;
|
||||||
title_blacklist : Array<string>;
|
title_blacklist : Array<string>;
|
||||||
|
@ -20,11 +42,30 @@ namespace _lixer_event_reminder.conf
|
||||||
)
|
)
|
||||||
>;
|
>;
|
||||||
targets : Array<
|
targets : Array<
|
||||||
{
|
(
|
||||||
chat_id : int;
|
{
|
||||||
interval : Array<int>;
|
kind : "telegram_bot",
|
||||||
}
|
data : {
|
||||||
|
bot_token : string;
|
||||||
|
chat_id : int;
|
||||||
|
/**
|
||||||
|
* in hours
|
||||||
|
*/
|
||||||
|
interval : Array<int>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
>;
|
>;
|
||||||
|
/**
|
||||||
|
* in hours
|
||||||
|
*/
|
||||||
|
frequency : float;
|
||||||
|
labels : {
|
||||||
|
head : string;
|
||||||
|
title : string;
|
||||||
|
time : string;
|
||||||
|
location : string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,10 +79,6 @@ namespace _lixer_event_reminder.conf
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
},
|
},
|
||||||
"bot_token": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"sources": {
|
"sources": {
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -60,7 +97,7 @@ namespace _lixer_event_reminder.conf
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"path": {
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -74,7 +111,8 @@ namespace _lixer_event_reminder.conf
|
||||||
"items": {
|
"items": {
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
}
|
},
|
||||||
|
"default": [],
|
||||||
},
|
},
|
||||||
"title_blacklist": {
|
"title_blacklist": {
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
|
@ -82,20 +120,19 @@ namespace _lixer_event_reminder.conf
|
||||||
"items": {
|
"items": {
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
}
|
},
|
||||||
|
"default": [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": [
|
"required": [
|
||||||
"category_blacklist",
|
],
|
||||||
"title_blacklist",
|
"default": {}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": [
|
"required": [
|
||||||
"id",
|
"id",
|
||||||
"filtration",
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -113,35 +150,95 @@ namespace _lixer_event_reminder.conf
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"type": "object",
|
"anyOf": [
|
||||||
"properties": {
|
{
|
||||||
"chat_id": {
|
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"type": "integer",
|
"type": "object",
|
||||||
},
|
"properties": {
|
||||||
"interval": {
|
"kind": {
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"type": "array",
|
"type": "string",
|
||||||
"items": {
|
"enum": ["telegram_bot"]
|
||||||
"nullable": false,
|
},
|
||||||
"type": "integer"
|
"data": {
|
||||||
}
|
"nullable": false,
|
||||||
},
|
"type": "object",
|
||||||
},
|
"properties": {
|
||||||
"additionalProperties": false,
|
"bot_token": {
|
||||||
"required": [
|
"nullable": false,
|
||||||
"chat_id",
|
"type": "string",
|
||||||
"interval",
|
},
|
||||||
]
|
"chat_id": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "integer",
|
||||||
|
},
|
||||||
|
"interval": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"default": [24.0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"bot_token",
|
||||||
|
"chat_id",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"data",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"frequency": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "number",
|
||||||
|
"default": 1.0,
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"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": {}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": [
|
"required": [
|
||||||
"version",
|
"version",
|
||||||
"bot_token",
|
"sources",
|
||||||
"chat_id",
|
"targets",
|
||||||
"intval",
|
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
310
source/main.ts
310
source/main.ts
|
@ -1,6 +1,143 @@
|
||||||
namespace _lixer_event_reminder
|
/*
|
||||||
|
This file is part of »munin«.
|
||||||
|
|
||||||
|
Copyright 2025 'Fenris Wolf' <fenris@folksprak.org>
|
||||||
|
|
||||||
|
»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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
namespace _munin
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
async function run_iteration(
|
||||||
|
conf : _munin.conf.type_conf,
|
||||||
|
sources : Array<_munin.type_source>,
|
||||||
|
targets : Array<_munin.type_target>,
|
||||||
|
{
|
||||||
|
"dry_run": dry_run = false,
|
||||||
|
} : {
|
||||||
|
dry_run ?: boolean;
|
||||||
|
} = {
|
||||||
|
}
|
||||||
|
) : Promise<void>
|
||||||
|
{
|
||||||
|
const now : lib_plankton.pit.type_pit = lib_plankton.pit.now();
|
||||||
|
const events : Array<_munin.type_event> = (
|
||||||
|
(await Promise.all(sources.map(source => source.fetch())))
|
||||||
|
.reduce((x, y) => x.concat(y), [])
|
||||||
|
);
|
||||||
|
for (const target of targets) {
|
||||||
|
lib_plankton.log._info(
|
||||||
|
"munin.run.iteration",
|
||||||
|
{
|
||||||
|
"details": {
|
||||||
|
"target": target,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
for (const hours of target.interval) {
|
||||||
|
const window_from : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour(
|
||||||
|
now,
|
||||||
|
hours + 0
|
||||||
|
);
|
||||||
|
const window_to : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour(
|
||||||
|
now,
|
||||||
|
hours + (conf.frequency / 2)
|
||||||
|
);
|
||||||
|
for (const event of events) {
|
||||||
|
const event_begin : lib_plankton.pit.type_pit = lib_plankton.pit.from_datetime(event.begin);
|
||||||
|
lib_plankton.log._debug(
|
||||||
|
"munin.run.check_dueness",
|
||||||
|
{
|
||||||
|
"details": {
|
||||||
|
"event_begin": lib_plankton.pit.datetime_format(lib_plankton.pit.to_datetime(event_begin)),
|
||||||
|
"window_from": lib_plankton.pit.datetime_format(lib_plankton.pit.to_datetime(window_from)),
|
||||||
|
"window_to": lib_plankton.pit.datetime_format(lib_plankton.pit.to_datetime(window_to)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const remind : boolean = lib_plankton.pit.is_between(
|
||||||
|
event_begin,
|
||||||
|
window_from,
|
||||||
|
window_to
|
||||||
|
);
|
||||||
|
if (! remind) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lib_plankton.log._info(
|
||||||
|
"munin.remind",
|
||||||
|
{
|
||||||
|
"details": {
|
||||||
|
"event": event,
|
||||||
|
"target": target,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (dry_run) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
await target.send(conf.labels, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function run(
|
||||||
|
conf : _munin.conf.type_conf,
|
||||||
|
{
|
||||||
|
"dry_run": dry_run = false,
|
||||||
|
} : {
|
||||||
|
dry_run ?: boolean;
|
||||||
|
} = {
|
||||||
|
}
|
||||||
|
) : void
|
||||||
|
{
|
||||||
|
const sources : Array<_munin.type_source> = conf.sources.map(
|
||||||
|
source_raw => _munin.sources.factory(source_raw)
|
||||||
|
);
|
||||||
|
const targets : Array<_munin.type_target> = conf.targets.map(
|
||||||
|
target_raw => _munin.targets.factory(target_raw)
|
||||||
|
);
|
||||||
|
lib_plankton.log._info(
|
||||||
|
"munin.run.start",
|
||||||
|
{
|
||||||
|
"details": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
run_iteration(conf, sources, targets, {"dry_run": dry_run});
|
||||||
|
/**
|
||||||
|
* outsource setInterval logic
|
||||||
|
*/
|
||||||
|
setInterval(
|
||||||
|
() => {run_iteration(conf, sources, targets, {"dry_run": dry_run});},
|
||||||
|
(conf.frequency * 60 * 60 * 1000)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export async function main(
|
export async function main(
|
||||||
|
@ -27,14 +164,32 @@ namespace _lixer_event_reminder
|
||||||
"info": "path to configuration file",
|
"info": "path to configuration file",
|
||||||
"name": "conf-path",
|
"name": "conf-path",
|
||||||
}),
|
}),
|
||||||
"message": lib_plankton.args.class_argument.volatile({
|
"conf_expose": lib_plankton.args.class_argument.volatile({
|
||||||
"indicators_long": ["message"],
|
"indicators_long": ["conf-expose"],
|
||||||
"indicators_short": ["m"],
|
"indicators_short": ["e"],
|
||||||
|
"type": lib_plankton.args.enum_type.boolean,
|
||||||
|
"mode": lib_plankton.args.enum_mode.replace,
|
||||||
|
"default": false,
|
||||||
|
"info": "whether to expose the full configuration",
|
||||||
|
"name": "conf-expose",
|
||||||
|
}),
|
||||||
|
"verbosity": lib_plankton.args.class_argument.volatile({
|
||||||
|
"indicators_long": ["verbosity"],
|
||||||
|
"indicators_short": ["v"],
|
||||||
"type": lib_plankton.args.enum_type.string,
|
"type": lib_plankton.args.enum_type.string,
|
||||||
"mode": lib_plankton.args.enum_mode.replace,
|
"mode": lib_plankton.args.enum_mode.replace,
|
||||||
"default": "test",
|
"default": "notice",
|
||||||
"info": "message to send",
|
"info": "error | warning | notice | info | debug",
|
||||||
"name": "message",
|
"name": "verbosity",
|
||||||
|
}),
|
||||||
|
"dry_run": lib_plankton.args.class_argument.volatile({
|
||||||
|
"indicators_long": ["dry-run"],
|
||||||
|
"indicators_short": ["q"],
|
||||||
|
"type": lib_plankton.args.enum_type.boolean,
|
||||||
|
"mode": lib_plankton.args.enum_mode.replace,
|
||||||
|
"default": false,
|
||||||
|
"info": "whether to not skip the sending of reminders (logs will be written)",
|
||||||
|
"name": "dry-run",
|
||||||
}),
|
}),
|
||||||
"help": lib_plankton.args.class_argument.volatile({
|
"help": lib_plankton.args.class_argument.volatile({
|
||||||
"indicators_long": ["help"],
|
"indicators_long": ["help"],
|
||||||
|
@ -52,102 +207,81 @@ namespace _lixer_event_reminder
|
||||||
args_raw.join(" ")
|
args_raw.join(" ")
|
||||||
);
|
);
|
||||||
|
|
||||||
// init
|
|
||||||
const conf : _lixer_event_reminder.conf.type_conf = await lib_plankton.conf.load<_lixer_event_reminder.conf.type_conf>(
|
|
||||||
_lixer_event_reminder.conf.schema,
|
|
||||||
args.conf_path
|
|
||||||
);
|
|
||||||
|
|
||||||
// exec
|
|
||||||
if (args.help || (args.action === "help")) {
|
if (args.help || (args.action === "help")) {
|
||||||
process.stdout.write(
|
process.stdout.write(
|
||||||
arg_handler.generate_help(
|
arg_handler.generate_help(
|
||||||
{
|
{
|
||||||
"programname": "lixer-event-reminder",
|
"programname": "munin",
|
||||||
"description": "a telegram bot, which sends reminders about upcoming events",
|
"description": "sends reminders about upcoming events",
|
||||||
"executable": "node build/event-reminder",
|
"executable": "node build/munin",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// init
|
||||||
|
const conf : _munin.conf.type_conf = await lib_plankton.conf.load<_munin.conf.type_conf>(
|
||||||
|
_munin.conf.schema,
|
||||||
|
args.conf_path
|
||||||
|
);
|
||||||
|
lib_plankton.log.set_main_logger(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"kind": "filtered",
|
||||||
|
"data": {
|
||||||
|
"core": {
|
||||||
|
"kind": "std",
|
||||||
|
"data": {
|
||||||
|
"target": "stdout",
|
||||||
|
"format": {
|
||||||
|
"kind": "human_readable",
|
||||||
|
"data": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"predicate": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"kind": "level",
|
||||||
|
"data": {
|
||||||
|
"threshold": args.verbosity,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// exec
|
||||||
|
if (args.conf_expose) {
|
||||||
|
process.stdout.write(
|
||||||
|
lib_plankton.json.encode(
|
||||||
|
conf,
|
||||||
|
{
|
||||||
|
"formatted": true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
+
|
||||||
|
"\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
switch (args.action) {
|
switch (args.action) {
|
||||||
default: {
|
default: {
|
||||||
throw (new Error("unhandled action: " + args.action));
|
throw (new Error("unhandled action: " + args.action));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "fetch": {
|
|
||||||
const updates : Array<any> = await lib_plankton.telegram.bot_call_get_updates(
|
|
||||||
conf.bot_token
|
|
||||||
);
|
|
||||||
process.stdout.write(JSON.stringify(updates, undefined, "\t") + "\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "send": {
|
|
||||||
for (const target of conf.targets) {
|
|
||||||
const message = await lib_plankton.telegram.bot_call_send_message(
|
|
||||||
conf.bot_token,
|
|
||||||
target.chat_id,
|
|
||||||
args.message
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "run": {
|
case "run": {
|
||||||
const sources : Array<_lixer_event_reminder.type_source> = conf.sources.map(
|
run(
|
||||||
source_raw => _lixer_event_reminder.sources.factory(source_raw)
|
conf,
|
||||||
);
|
{
|
||||||
const targets : Array<_lixer_event_reminder.type_target> = conf.targets.map(
|
"dry_run": args.dry_run,
|
||||||
target_raw => target_raw
|
|
||||||
);
|
|
||||||
const now : lib_plankton.pit.type_pit = lib_plankton.pit.now();
|
|
||||||
|
|
||||||
const events : Array<_lixer_event_reminder.type_event> = (
|
|
||||||
(await Promise.all(sources.map(source => source.fetch())))
|
|
||||||
.reduce((x, y) => x.concat(y), [])
|
|
||||||
);
|
|
||||||
for (const event of events) {
|
|
||||||
const begin : lib_plankton.pit.type_pit = lib_plankton.pit.from_datetime(event.begin);
|
|
||||||
for (const target of targets) {
|
|
||||||
for (const hours of target.interval) {
|
|
||||||
const remind : boolean = lib_plankton.pit.is_between(
|
|
||||||
lib_plankton.pit.shift_hour(begin, hours),
|
|
||||||
now,
|
|
||||||
/**
|
|
||||||
* @todo parametrize window
|
|
||||||
*/
|
|
||||||
lib_plankton.pit.shift_hour(now, +24)
|
|
||||||
);
|
|
||||||
if (remind) {
|
|
||||||
lib_plankton.log._info(
|
|
||||||
"remind",
|
|
||||||
{
|
|
||||||
"details": {
|
|
||||||
"event": event,
|
|
||||||
"target": target,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
/**
|
|
||||||
* @todo activate
|
|
||||||
* @todo format better
|
|
||||||
*/
|
|
||||||
const message = await lib_plankton.telegram.bot_call_send_message(
|
|
||||||
conf.bot_token,
|
|
||||||
target.chat_id,
|
|
||||||
lib_plankton.string.coin(
|
|
||||||
"{{title}} | {{begin}}",
|
|
||||||
{
|
|
||||||
"title": event.title,
|
|
||||||
"begin": lib_plankton.pit.datetime_format(event.begin),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,7 +291,7 @@ namespace _lixer_event_reminder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_lixer_event_reminder.main(process.argv.slice(2))
|
_munin.main(process.argv.slice(2))
|
||||||
.then(() => {})
|
.then(() => {})
|
||||||
.catch((reason) => {process.stderr.write(String(reason) + "\n");})
|
.catch((reason) => {process.stderr.write(String(reason) + "\n");})
|
||||||
;
|
;
|
||||||
|
|
|
@ -1,4 +1,24 @@
|
||||||
namespace _lixer_event_reminder.sources
|
/*
|
||||||
|
This file is part of »munin«.
|
||||||
|
|
||||||
|
Copyright 2025 'Fenris Wolf' <fenris@folksprak.org>
|
||||||
|
|
||||||
|
»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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
namespace _munin.sources
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,7 +28,7 @@ namespace _lixer_event_reminder.sources
|
||||||
kind : string,
|
kind : string,
|
||||||
data : any
|
data : any
|
||||||
}
|
}
|
||||||
) : type_source
|
) : _munin.type_source
|
||||||
{
|
{
|
||||||
switch (description.kind) {
|
switch (description.kind) {
|
||||||
default: {
|
default: {
|
||||||
|
@ -16,8 +36,8 @@ namespace _lixer_event_reminder.sources
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "kalender_digital": {
|
case "kalender_digital": {
|
||||||
return _lixer_event_reminder.sources.kalender_digital.implementation_source(
|
return _munin.sources.kalender_digital.implementation_source(
|
||||||
description.data as _lixer_event_reminder.sources.kalender_digital.type_parameters
|
description.data as _munin.sources.kalender_digital.type_parameters
|
||||||
);
|
);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
namespace _lixer_event_reminder.sources.kalender_digital
|
namespace _munin.sources.kalender_digital
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export type type_parameters = {
|
export type type_parameters = {
|
||||||
id : string;
|
path : string;
|
||||||
filtration : {
|
filtration : {
|
||||||
category_blacklist : Array<string>;
|
category_blacklist : Array<string>;
|
||||||
title_blacklist : Array<string>;
|
title_blacklist : Array<string>;
|
||||||
|
@ -16,15 +16,15 @@ namespace _lixer_event_reminder.sources.kalender_digital
|
||||||
*/
|
*/
|
||||||
async function fetch(
|
async function fetch(
|
||||||
parameters : type_parameters
|
parameters : type_parameters
|
||||||
) : Promise<Array<_lixer_event_reminder.type_event>>
|
) : Promise<Array<_munin.type_event>>
|
||||||
{
|
{
|
||||||
const http_request : lib_plankton.http.type_request = {
|
const http_request : lib_plankton.http.type_request = {
|
||||||
"scheme": "https",
|
"scheme": "https",
|
||||||
"host": "export.kalender.digital",
|
"host": "export.kalender.digital",
|
||||||
"path": lib_plankton.string.coin(
|
"path": lib_plankton.string.coin(
|
||||||
"/ics/0/{{id}}/gesamterkalender.ics",
|
"/ics/{{path}}.ics",
|
||||||
{
|
{
|
||||||
"id": parameters.id,
|
"path": parameters.path,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
"version": "HTTP/2",
|
"version": "HTTP/2",
|
||||||
|
@ -33,7 +33,10 @@ namespace _lixer_event_reminder.sources.kalender_digital
|
||||||
"?past_months={{past_months}}&future_months={{future_months}}",
|
"?past_months={{past_months}}&future_months={{future_months}}",
|
||||||
{
|
{
|
||||||
"past_months": (0).toFixed(0),
|
"past_months": (0).toFixed(0),
|
||||||
"future_months": (2).toFixed(0),
|
/**
|
||||||
|
* anpassen an frequency?
|
||||||
|
*/
|
||||||
|
"future_months": (1).toFixed(0),
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
"headers": {},
|
"headers": {},
|
||||||
|
@ -42,13 +45,34 @@ namespace _lixer_event_reminder.sources.kalender_digital
|
||||||
const http_response : lib_plankton.http.type_response = await lib_plankton.http.call(http_request);
|
const http_response : lib_plankton.http.type_response = await lib_plankton.http.call(http_request);
|
||||||
const ics : string = http_response.body.toString();
|
const ics : string = http_response.body.toString();
|
||||||
const vcalendar : lib_plankton.ical.type_vcalendar = lib_plankton.ical.ics_decode(ics);
|
const vcalendar : lib_plankton.ical.type_vcalendar = lib_plankton.ical.ics_decode(ics);
|
||||||
const events : Array<_lixer_event_reminder.type_event> = (
|
const events : Array<_munin.type_event> = (
|
||||||
vcalendar.vevents
|
vcalendar.vevents
|
||||||
.filter(
|
.filter(
|
||||||
vevent => (
|
vevent => (
|
||||||
vevent.categories.every(category => ! parameters.filtration.category_blacklist.includes(category))
|
// category
|
||||||
|
(
|
||||||
|
vevent.categories.every(
|
||||||
|
category => (
|
||||||
|
! (
|
||||||
|
parameters.filtration.category_blacklist
|
||||||
|
.map(category_ => category_.toLowerCase())
|
||||||
|
.includes(category.toLowerCase())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
&&
|
&&
|
||||||
parameters.filtration.title_blacklist.every(title => ! vevent.summary.toLowerCase().includes(title.toLowerCase()))
|
// title
|
||||||
|
(
|
||||||
|
parameters.filtration.title_blacklist.every(
|
||||||
|
title => (
|
||||||
|
! (
|
||||||
|
vevent.summary.toLowerCase()
|
||||||
|
.includes(title.toLowerCase())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.map(
|
.map(
|
||||||
|
@ -63,11 +87,11 @@ namespace _lixer_event_reminder.sources.kalender_digital
|
||||||
"date": vevent.dtend.value.date,
|
"date": vevent.dtend.value.date,
|
||||||
"time": vevent.dtend.value.time,
|
"time": vevent.dtend.value.time,
|
||||||
};
|
};
|
||||||
const event : _lixer_event_reminder.type_event = {
|
const event : _munin.type_event = {
|
||||||
"title": vevent.summary,
|
"title": vevent.summary,
|
||||||
"begin": begin,
|
"begin": begin,
|
||||||
"end": end,
|
"end": end,
|
||||||
"location": vevent.location,
|
"location": (vevent.location ?? null),
|
||||||
};
|
};
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
@ -81,7 +105,7 @@ namespace _lixer_event_reminder.sources.kalender_digital
|
||||||
*/
|
*/
|
||||||
export function implementation_source(
|
export function implementation_source(
|
||||||
parameters : type_parameters
|
parameters : type_parameters
|
||||||
) : _lixer_event_reminder.type_source
|
) : _munin.type_source
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
"fetch": () => fetch(parameters),
|
"fetch": () => fetch(parameters),
|
||||||
|
|
48
source/targets/_functions.ts
Normal file
48
source/targets/_functions.ts
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
This file is part of »munin«.
|
||||||
|
|
||||||
|
Copyright 2025 'Fenris Wolf' <fenris@folksprak.org>
|
||||||
|
|
||||||
|
»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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
namespace _munin.targets
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export function factory(
|
||||||
|
description : {
|
||||||
|
kind : string,
|
||||||
|
data : any
|
||||||
|
}
|
||||||
|
) : _munin.type_target
|
||||||
|
{
|
||||||
|
switch (description.kind) {
|
||||||
|
default: {
|
||||||
|
throw (new Error("unhandled target kind: " + description.kind));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "telegram_bot": {
|
||||||
|
return _munin.targets.telegram_bot.implementation_target(
|
||||||
|
description.data as _munin.targets.telegram_bot.type_parameters
|
||||||
|
);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
87
source/targets/telegram_bot.ts
Normal file
87
source/targets/telegram_bot.ts
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
This file is part of »munin«.
|
||||||
|
|
||||||
|
Copyright 2025 'Fenris Wolf' <fenris@folksprak.org>
|
||||||
|
|
||||||
|
»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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
namespace _munin.targets.telegram_bot
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export type type_parameters = {
|
||||||
|
bot_token : string;
|
||||||
|
chat_id : int;
|
||||||
|
interval : Array<int>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
async function send(
|
||||||
|
parameters : type_parameters,
|
||||||
|
labels : _munin.type_labels,
|
||||||
|
event : _munin.type_event
|
||||||
|
) : Promise<void>
|
||||||
|
{
|
||||||
|
await lib_plankton.telegram.bot_call_send_message(
|
||||||
|
parameters.bot_token,
|
||||||
|
parameters.chat_id,
|
||||||
|
lib_plankton.string.coin(
|
||||||
|
"*{{head}}*\n\n\{{title_label}} | {{title_value}}\n{{time_label}} | {{time_value}}{{macro_location}}",
|
||||||
|
{
|
||||||
|
"head": labels.head,
|
||||||
|
"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),
|
||||||
|
"macro_location": (
|
||||||
|
(event.location === null)
|
||||||
|
?
|
||||||
|
""
|
||||||
|
:
|
||||||
|
lib_plankton.string.coin(
|
||||||
|
"\n{{location_label}} | {{location_value}}",
|
||||||
|
{
|
||||||
|
"location_label": labels.location.toUpperCase(),
|
||||||
|
"location_value": event.location,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
{
|
||||||
|
"parse_mode": "markdown",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export function implementation_target(
|
||||||
|
parameters : type_parameters
|
||||||
|
) : _munin.type_target
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"interval": parameters.interval,
|
||||||
|
"send": (labels, event) => send(parameters, labels, event),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,16 @@
|
||||||
namespace _lixer_event_reminder
|
namespace _munin
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export type type_labels = {
|
||||||
|
head : string;
|
||||||
|
title : string;
|
||||||
|
time : string;
|
||||||
|
location : string;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export type type_event = {
|
export type type_event = {
|
||||||
|
@ -14,15 +24,27 @@ namespace _lixer_event_reminder
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export type type_source = {
|
export type type_source = {
|
||||||
fetch : (() => Promise<Array<type_event>>);
|
fetch : (
|
||||||
|
(
|
||||||
|
)
|
||||||
|
=>
|
||||||
|
Promise<Array<type_event>>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export type type_target = {
|
export type type_target = {
|
||||||
chat_id : int;
|
|
||||||
interval : Array<int>;
|
interval : Array<int>;
|
||||||
|
send : (
|
||||||
|
(
|
||||||
|
labels : type_labels,
|
||||||
|
event : type_event
|
||||||
|
)
|
||||||
|
=>
|
||||||
|
Promise<void>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
16
tools/build
16
tools/build
|
@ -1,16 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
import os as _os
|
tools/ivaldi build
|
||||||
import argparse as _argparse
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
argument_parser = _argparse.ArgumentParser(
|
|
||||||
)
|
|
||||||
args = argument_parser.parse_args()
|
|
||||||
|
|
||||||
if True:
|
|
||||||
_os.system("make -f tools/makefile")
|
|
||||||
|
|
||||||
|
|
||||||
main()
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
rm -r -f temp
|
tools/ivaldi clear $@
|
||||||
rm -r -f build
|
|
||||||
|
|
||||||
|
|
16
tools/deploy
16
tools/deploy
|
@ -1,18 +1,4 @@
|
||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
## args
|
tools/ivaldi deploy $@
|
||||||
|
|
||||||
# if [ $# -ge 1 ] ; then target=$1 ; else target="pv-svartalfheim-user:~/skripte" ; fi
|
|
||||||
target=$1
|
|
||||||
|
|
||||||
|
|
||||||
## exec
|
|
||||||
|
|
||||||
rsync \
|
|
||||||
--recursive \
|
|
||||||
--update \
|
|
||||||
--delete \
|
|
||||||
--verbose \
|
|
||||||
--rsh=ssh \
|
|
||||||
build/ \
|
|
||||||
${target}
|
|
||||||
|
|
5461
tools/ivaldi
Executable file
5461
tools/ivaldi
Executable file
File diff suppressed because it is too large
Load diff
|
@ -1,40 +0,0 @@
|
||||||
## commands
|
|
||||||
|
|
||||||
cmd_mkdir := mkdir -p
|
|
||||||
cmd_cp := cp -r -u
|
|
||||||
cmd_tsc := tsc
|
|
||||||
cmd_log := echo "--"
|
|
||||||
cmd_cat := cat
|
|
||||||
cmd_echo := echo
|
|
||||||
cmd_chmod := chmod
|
|
||||||
|
|
||||||
|
|
||||||
## rules
|
|
||||||
|
|
||||||
.PHONY: _default
|
|
||||||
_default: _root
|
|
||||||
|
|
||||||
temp/termine-reminder-unlinked.js: \
|
|
||||||
libs/plankton/plankton.d.ts \
|
|
||||||
source/types.ts \
|
|
||||||
source/sources/kalender_digital.ts \
|
|
||||||
source/sources/_functions.ts \
|
|
||||||
source/conf.ts \
|
|
||||||
source/main.ts
|
|
||||||
@ ${cmd_log} "compiling logic …"
|
|
||||||
@ ${cmd_mkdir} temp
|
|
||||||
@ ${cmd_tsc} $^ --lib es2020,dom --target es6 --outFile $@
|
|
||||||
|
|
||||||
build/termine-reminder: libs/plankton/plankton.js temp/termine-reminder-unlinked.js
|
|
||||||
@ ${cmd_log} "linking …"
|
|
||||||
@ ${cmd_echo} "#!/usr/bin/env node" > temp/head.js
|
|
||||||
@ ${cmd_mkdir} build
|
|
||||||
@ ${cmd_cat} temp/head.js $^ > $@
|
|
||||||
@ ${cmd_chmod} +x $@
|
|
||||||
|
|
||||||
.PHONY: sources
|
|
||||||
sources: build/termine-reminder
|
|
||||||
|
|
||||||
.PHONY: _root
|
|
||||||
_root: sources
|
|
||||||
|
|
4
tools/update-ivaldi
Executable file
4
tools/update-ivaldi
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
cp -u -v ../ivaldi/build/ivaldi tools/ivaldi
|
||||||
|
|
4
tools/update-libs
Executable file
4
tools/update-libs
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
tools/ivaldi fetch $@
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
## consts
|
|
||||||
|
|
||||||
dir="libs/plankton"
|
|
||||||
|
|
||||||
|
|
||||||
## vars
|
|
||||||
|
|
||||||
modules=""
|
|
||||||
modules="${modules} pit"
|
|
||||||
modules="${modules} http"
|
|
||||||
modules="${modules} ical"
|
|
||||||
modules="${modules} telegram"
|
|
||||||
modules="${modules} conf"
|
|
||||||
modules="${modules} args"
|
|
||||||
|
|
||||||
|
|
||||||
## exec
|
|
||||||
|
|
||||||
mkdir -p ${dir}
|
|
||||||
cd ${dir}
|
|
||||||
ptk bundle node ${modules}
|
|
Loading…
Reference in a new issue