From fd57411a9d17c74a965b4dbdfe68148ca59033aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Thu, 20 Jun 2024 16:32:59 +0200 Subject: [PATCH 01/11] [mod] member management: auto_register option --- source/api/actions/member_project.ts | 15 +++++ source/conf.ts | 6 +- source/data/localization/deu.loc.json | 3 +- source/data/localization/eng.loc.json | 3 +- source/services/member.ts | 85 +++++++++++++++++---------- 5 files changed, 76 insertions(+), 36 deletions(-) diff --git a/source/api/actions/member_project.ts b/source/api/actions/member_project.ts index 99caab2..3d8f60c 100644 --- a/source/api/actions/member_project.ts +++ b/source/api/actions/member_project.ts @@ -105,6 +105,21 @@ namespace _espe.api ), } ); + if (! _espe.conf.get().settings.misc.auto_register) { + // do nothing + } + else { + // TODO: Werte in Konfiguration auslagern + await _espe.service.member.register( + member_id, + { + "email_use_veiled_address": false, + "email_use_nominal_address": false, + "email_redirect_to_private_address": false, + "password": null, + } + ); + } return Promise.resolve({ "status_code": 201, "data": member_id diff --git a/source/conf.ts b/source/conf.ts index 87febc9..b7e154f 100644 --- a/source/conf.ts +++ b/source/conf.ts @@ -22,8 +22,6 @@ namespace _espe.conf general : { language : (null | string); verbosity : ( - "none" - | "debug" | "notice" @@ -33,6 +31,8 @@ namespace _espe.conf "warning" | "error" + | + "none" ); verification_secret : (null | string); }; @@ -102,6 +102,7 @@ namespace _espe.conf misc : { prefix_for_veiled_email_addresses : string; facultative_membership_number : boolean; + auto_register : boolean; }; summon_email : { remark : string; @@ -258,6 +259,7 @@ namespace _espe.conf ((node_settings_misc) => ({ "prefix_for_veiled_email_addresses": (node_settings_misc["prefix_for_veiled_email_addresses"] ?? "member-"), "facultative_membership_number": (node_settings_misc["facultative_membership_number"] ?? false), + "auto_register": (node_settings_misc["auto_register"] ?? false), })) (node_settings["misc"] ?? {}) ), "summon_email": ( diff --git a/source/data/localization/deu.loc.json b/source/data/localization/deu.loc.json index 3508bd2..2d0abaa 100644 --- a/source/data/localization/deu.loc.json +++ b/source/data/localization/deu.loc.json @@ -8,7 +8,8 @@ "email.registration.subject": "Registrierung erfolgt", "email.registration.body": "Das Mitglied '{{name_display}}' hat sich soeben registriert:\n\n{{url}}", "email.activation.subject": "Freischaltung erfolgt", - "email.activation.body": "Hi, {{name_display}}\n\nDein Mitglieder-Konto wurde gerade freigeschalten. Du kannst dich nun anmelden:\n\nURL: {{url}}\nAnmelde-Name: {{name_login}}", + "email.activation.body": "Hi, {{name_display}}\n\nDein Mitglieder-Konto wurde gerade freigeschalten. Du kannst dich nun anmelden:\n\nURL: {{url}}\nAnmelde-Name: {{name_login}}\n{{password_info}}", + "email.activation.password_info": "Passwort: {{password}}\n\nBitte ändere dein Passwort zeitnah!", "email.password_change.initialization.subject": "Passwort-Änderung eingeleitet", "email.password_change.initialization.body": "Hi, {{name}}\n\nDie Funktion zum Ändern deines Passwortes wurde aufgerufen. Wenn du dein Passwort ändern willst, rufe folgenden Link auf:\n\n{{url}}\n", "email.password_change.execution.subject": "Passwort-Änderung abgeschlossen", diff --git a/source/data/localization/eng.loc.json b/source/data/localization/eng.loc.json index b646b39..80e2d64 100644 --- a/source/data/localization/eng.loc.json +++ b/source/data/localization/eng.loc.json @@ -8,7 +8,8 @@ "email.registration.subject": "Registration received", "email.registration.body": "The member '{{name_display}}' just registered:\n\n{{url}}", "email.activation.subject": "Activated", - "email.activation.body": "Hi, {{name_display}}\n\nYour account has just been activated. You may login now:\n\nURL: {{url}}\nLogin name: {{name_login}}", + "email.activation.body": "Hi, {{name_display}}\n\nYour account has just been activated. You may login now:\n\nURL: {{url}}\nLogin name: {{name_login}}\n{{password_info}}", + "email.activation.password_info": "Password: {{password}}\n\Please change your password soon!", "email.password_change.initialization.subject": "Password change initialized", "email.password_change.initialization.body": "Hi, {{name}}\n\nThe function for changing your password has been triggered. If you want to change your password, open the folloling link:\n\n{{url}}", "email.password_change.execution.subject": "Password change concluded", diff --git a/source/services/member.ts b/source/services/member.ts index 3f3619b..12d7bd2 100644 --- a/source/services/member.ts +++ b/source/services/member.ts @@ -191,9 +191,18 @@ namespace _espe.service.member /** */ async function send_activation_email( - member_object : _espe.type.member_object + member_object : _espe.type.member_object, + options : { + password ?: (null | string); + } = {} ) : Promise { + options = Object.assign( + { + "password": null, + }, + options + ); if (! member_object.enabled) { // do nothing } @@ -219,6 +228,20 @@ namespace _espe.service.member "name_display": name_display(member_object), "name_login": name_login(member_object), "url": (_espe.conf.get().settings.connections.login_url ?? "--"), + "password_info": ( + ( + (options.password === undefined) + || + (options.password === null) + ) + ? "" + : lib_plankton.string.coin( + lib_plankton.translate.get("email.activation.body"), + { + "password": options.password, + } + ) + ), } ) ); @@ -424,28 +447,31 @@ namespace _espe.service.member ); const member_object : _espe.type.member_object = await get(member_id); + let flaws : Array<{incident : string; details : Record;}> = []; - const password_set : boolean = ( - (data.password !== null) - && - (data.password !== "") - ); + let password_value : string; + let password_generated : boolean; if (member_object.registered) { flaws.push({"incident": "already_registered", "details": {}}); + password_value = ""; + password_generated = false; } else { if ( - password_set - && (data.password !== null) + && + (data.password !== "") ) { flaws = flaws.concat( validate_password(data.password) .map(flaw => ({"incident": ("password_" + flaw.incident), "details": flaw.details})) ); + password_value = data.password; + password_generated = false; } else { - // do nothing + password_value = generate_password(); + password_generated = true; } } @@ -456,7 +482,7 @@ namespace _espe.service.member member_object.email_use_veiled_address = data.email_use_veiled_address; member_object.email_use_nominal_address = data.email_use_nominal_address; member_object.email_redirect_to_private_address = data.email_redirect_to_private_address; - member_object.password_image = await password_image(data.password); + member_object.password_image = await password_image(password_value); member_object.registered = true; await _espe.repository.member.update(member_id, member_object); signal_change(); @@ -475,29 +501,24 @@ namespace _espe.service.member } ) ); - if (url === null) { - // do nothing - } - else { - /*await*/ _espe.helpers.notify_admins( - lib_plankton.string.coin( - "{{head}} | {{core}}", - { - "head": _espe.conf.get().settings.organisation.name, - "core": lib_plankton.translate.get("email.registration.subject"), - } - ), - lib_plankton.string.coin( - lib_plankton.translate.get("email.registration.body"), - { - "name_display": name_display(member_object), - "url": url, - } - ) - ); - } + /*await*/ _espe.helpers.notify_admins( + lib_plankton.string.coin( + "{{head}} | {{core}}", + { + "head": _espe.conf.get().settings.organisation.name, + "core": lib_plankton.translate.get("email.registration.subject"), + } + ), + lib_plankton.string.coin( + lib_plankton.translate.get("email.registration.body"), + { + "name_display": name_display(member_object), + "url": (url ?? "?"), + } + ) + ); } - /*await*/ send_activation_email(member_object); + /*await*/ send_activation_email(member_object, {"password": password_generated ? password_value : null}); } return Promise.resolve(flaws); From 8d761e4ebcaff61bb3b8fc14d06cd43b262c2437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Sun, 23 Jun 2024 11:44:41 +0200 Subject: [PATCH 02/11] [mod] tools:deploy:exclude database file --- tools/deploy | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/deploy b/tools/deploy index 95c223d..f3285e2 100755 --- a/tools/deploy +++ b/tools/deploy @@ -46,6 +46,7 @@ def main(): "--update", "--verbose", "--exclude='conf.json'", + "--exclude='data.sqlite'", ("%s/" % args.build_directory), ( ("%s" % args.target_directory) From 73ca87a6c672c7be17d766fdde05d19ae5bcc31d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Sun, 23 Jun 2024 11:45:24 +0200 Subject: [PATCH 03/11] [mod] api:action:member_project:parameter for notifcation url --- source/api/actions/member_project.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/api/actions/member_project.ts b/source/api/actions/member_project.ts index 3d8f60c..293cebb 100644 --- a/source/api/actions/member_project.ts +++ b/source/api/actions/member_project.ts @@ -27,6 +27,7 @@ namespace _espe.api membership_number : (null | string); name_real_value : string; email_address_private : (null | string); + notification_target_url_template ?: (null | string); }, ( string @@ -59,6 +60,11 @@ namespace _espe.api "nullable": true, "description": "private E-Mail-Adresse" }, + "notification_target_url_template": { + "type": "string", + "nullable": true, + "description": "Platz-Halter: id" + }, }, "required": [ "membership_number", @@ -117,6 +123,9 @@ namespace _espe.api "email_use_nominal_address": false, "email_redirect_to_private_address": false, "password": null, + }, + { + "notification_target_url_template": input.notification_target_url_template, } ); } From 3d5aedd3c9698cec63f9636a6ba081c076ff17b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Sun, 23 Jun 2024 11:45:47 +0200 Subject: [PATCH 04/11] [fix] loc:eng --- source/data/localization/eng.loc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/data/localization/eng.loc.json b/source/data/localization/eng.loc.json index 2a19508..2121971 100644 --- a/source/data/localization/eng.loc.json +++ b/source/data/localization/eng.loc.json @@ -9,7 +9,7 @@ "email.registration.body": "The member '{{name_display}}' just registered:\n\n{{url}}", "email.activation.subject": "Activated", "email.activation.body": "Hi, {{name_display}}\n\nYour account has just been activated. You may login now:\n\nURL: {{url}}\nLogin name: {{name_login}}\n{{password_info}}", - "email.activation.password_info": "Password: {{password}}\n\Please change your password soon!", + "email.activation.password_info": "Password: {{password}}\n\nPlease change your password soon!", "email.password_change.initialization.subject": "Password change initialized", "email.password_change.initialization.body": "Hi, {{name}}\n\nThe function for changing your password has been triggered. If you want to change your password, open the folloling link:\n\n{{url}}", "email.password_change.execution.subject": "Password change concluded", From 56d84c88489eb94ebfc30b2cb60d27b4d0a3a1a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Sun, 23 Jun 2024 11:46:30 +0200 Subject: [PATCH 05/11] [mod] conf:default values --- source/conf.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/conf.ts b/source/conf.ts index b7e154f..c8e919f 100644 --- a/source/conf.ts +++ b/source/conf.ts @@ -161,7 +161,7 @@ namespace _espe.conf ), "server": ( ((node_server) => ({ - "port": (node_server["port"] ?? 3593), + "port": (node_server["port"] ?? 4916), "path_base": (node_server["path_base"] ?? ""), })) (conf_raw["server"] ?? {}) ), @@ -195,7 +195,7 @@ namespace _espe.conf ), "email_sending": ( ((node_email_sending) => { - const kind : string = (node_email_sending["kind"] ?? "regular"); + const kind : string = (node_email_sending["kind"] ?? "console"); const data_raw = (node_email_sending["data"] ?? {}); switch (kind) { case "regular": { @@ -291,8 +291,8 @@ namespace _espe.conf ), "name_index": ( ((node_settings_password_policy) => ({ - "veil": (node_settings_password_policy["veil"] ?? false), - "salt": (node_settings_password_policy["salt"] ?? null), + "veil": (node_settings_password_policy["veil"] ?? true), + "salt": (node_settings_password_policy["salt"] ?? ""), })) (node_settings["name_index"] ?? {}) ), "connections": ( From 099505b3b8476df92cdf072ce3f4401d5310644f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Sun, 23 Jun 2024 11:46:44 +0200 Subject: [PATCH 06/11] [mod] main:todo --- source/main.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/source/main.ts b/source/main.ts index 9c252a9..e513c8f 100644 --- a/source/main.ts +++ b/source/main.ts @@ -25,6 +25,7 @@ async function main( { "verbosity": 1, "packages": [ + // TODO: error handling JSON.parse(await lib_plankton.file.read("data/localization/deu.loc.json")), JSON.parse(await lib_plankton.file.read("data/localization/eng.loc.json")), ], From 949f1e504088db514de2ab9acc88306c1a790b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Sun, 23 Jun 2024 11:47:28 +0200 Subject: [PATCH 07/11] [fix] service:member:activation email [fix] service:member:delete --- source/services/member.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/source/services/member.ts b/source/services/member.ts index 12d7bd2..8363318 100644 --- a/source/services/member.ts +++ b/source/services/member.ts @@ -236,7 +236,7 @@ namespace _espe.service.member ) ? "" : lib_plankton.string.coin( - lib_plankton.translate.get("email.activation.body"), + lib_plankton.translate.get("email.activation.password_info"), { "password": options.password, } @@ -559,6 +559,17 @@ namespace _espe.service.member } + /** + */ + export async function remove( + id : _espe.type.member_id + ) : Promise + { + await _espe.repository.member.delete_(id); + signal_change(); + } + + /** * bereitet eine Passwort-Rücksetzung für Mitglieder vor * @@ -762,17 +773,6 @@ namespace _espe.service.member } - /* - export async function remove( - id : _espe.type.member_id - ) : Promise - { - await _espe.repository.member.delete(id); - signal_change(); - } - */ - - /** * @todo check validity (e.g. username characters) */ From 1ec6fd96b69e0f807a6b0f5162acd392d9e7f89a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Sun, 23 Jun 2024 11:47:50 +0200 Subject: [PATCH 08/11] [add] api:action:member_delete --- source/api/actions/member_delete.ts | 6 +++--- source/api/functions.ts | 2 +- tools/makefile | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/source/api/actions/member_delete.ts b/source/api/actions/member_delete.ts index a720c87..d261f06 100644 --- a/source/api/actions/member_delete.ts +++ b/source/api/actions/member_delete.ts @@ -22,15 +22,15 @@ namespace _espe.api rest_subject : lib_plankton.rest.type_rest ) : void { - register<_espe.service.member.type_value, null>( + register( rest_subject, lib_plankton.http.enum_method.delete, - "/member/:id", + "/member/delete/:id", { "description": "löscht ein vorhandenes Mitglied", "restriction": restriction_logged_in, "execution": async ({"path_parameters": path_parameters}) => { - const member_id : _espe.service.member.type_id = parseInt(path_parameters["id"]); + const member_id : _espe.type.member_id = parseInt(path_parameters["id"]); await _espe.service.member.remove(member_id); return Promise.resolve({ "status_code": 200, diff --git a/source/api/functions.ts b/source/api/functions.ts index 8ae3427..3a34e22 100644 --- a/source/api/functions.ts +++ b/source/api/functions.ts @@ -52,7 +52,7 @@ namespace _espe.api _espe.api.register_member_list(rest_subject); _espe.api.register_member_read(rest_subject); _espe.api.register_member_modify(rest_subject); - // _espe.api.register_member_delete(rest_subject); + _espe.api.register_member_delete(rest_subject); // password_change { _espe.api.register_member_password_change_initialize(rest_subject); diff --git a/tools/makefile b/tools/makefile index 471c6f6..77cce12 100644 --- a/tools/makefile +++ b/tools/makefile @@ -65,6 +65,7 @@ ${dir_temp}/espe-core.js ${dir_temp}/espe-core.d.ts: \ ${dir_source}/api/actions/member_list.ts \ ${dir_source}/api/actions/member_read.ts \ ${dir_source}/api/actions/member_modify.ts \ + ${dir_source}/api/actions/member_delete.ts \ ${dir_source}/api/actions/member_password_change_initialize.ts \ ${dir_source}/api/actions/member_password_change_execute.ts \ ${dir_source}/api/functions.ts \ From 75c9f8456cfe6163393aaaee185b9d180c99fa3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Sun, 23 Jun 2024 11:48:33 +0200 Subject: [PATCH 09/11] [add] example conf --- misc/conf.example.json | 69 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 misc/conf.example.json diff --git a/misc/conf.example.json b/misc/conf.example.json new file mode 100644 index 0000000..806201f --- /dev/null +++ b/misc/conf.example.json @@ -0,0 +1,69 @@ +{ + "general": { + "language": null, + "verbosity": "info", + "verification_secret": null + }, + "server": { + "port": 4916, + "path_base": "" + }, + "database": { + "kind": "sqlite", + "data": { + "path": "data.sqlite" + } + }, + "email_sending": { + "kind": "console", + "data": { + } + }, + "session_management": { + "in_memory": false, + "drop_all_at_start": false, + "lifetime": 7200 + }, + "settings": { + "organisation": { + "name": "Example Orginsation", + "domain": "example.org" + }, + "misc": { + "prefix_for_veiled_email_addresses": "member-", + "facultative_membership_number": true, + "auto_register": true + }, + "summon_email": { + "remark": null + }, + "password_policy": { + "minimum_length": 4, + "maximum_length": 12, + "must_contain_letter": true, + "must_contain_number": false, + "must_contain_special_character": false + }, + "password_change": { + "cooldown_time": 300 + }, + "name_index": { + "veil": false, + "salt": null + }, + "connections": { + "frontend_url_base": null, + "login_url": null + } + }, + "admins": [ + { + "name": "admin", + "password_image": "$2b$12$xOa6iWPOMjiwJ3oIOZWDGu/w2Ca/eKLHWE7aDItkNsP/79nJk065i", + "email_address": "espe-admin@example.org" + } + ], + "output": { + "authelia": "/tmp/authelia-users.yml" + } +} From 50d24c9841aa17803b1d45e5db2eb5f6a2c35347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Sun, 23 Jun 2024 13:52:59 +0200 Subject: [PATCH 10/11] [upd] plankton --- lib/plankton/plankton.d.ts | 42 +++++++- lib/plankton/plankton.js | 211 +++++++++++++++++++++++++++++++++---- tools/update-plankton | 1 + 3 files changed, 231 insertions(+), 23 deletions(-) diff --git a/lib/plankton/plankton.d.ts b/lib/plankton/plankton.d.ts index 369e0a7..33915fb 100644 --- a/lib/plankton/plankton.d.ts +++ b/lib/plankton/plankton.d.ts @@ -923,6 +923,16 @@ declare namespace lib_plankton.file { */ function delete_(path: string): Promise; } +declare namespace lib_plankton.email { + /** + */ + function send(smtp_credentials: { + host: string; + port: int; + username: string; + password: string; + }, sender: string, receivers: Array, subject: string, content: string): Promise; +} declare namespace lib_plankton.log { /** */ @@ -996,10 +1006,40 @@ declare namespace lib_plankton.log { * the path of the log file */ private path; + /** + */ + private human_readable; /** * [constructor] */ - constructor(path: string); + constructor(path: string, human_readable: boolean); + /** + */ + add(entry: type_entry): void; + } +} +declare namespace lib_plankton.log { + /** + */ + class class_channel_email extends class_channel { + /** + */ + private smtp_credentials; + /** + */ + private sender; + /** + */ + private receivers; + /** + * [constructor] + */ + constructor(smtp_credentials: { + host: string; + port: int; + username: string; + password: string; + }, sender: string, receivers: Array); /** */ add(entry: type_entry): void; diff --git a/lib/plankton/plankton.js b/lib/plankton/plankton.js index 04c766d..8dea427 100644 --- a/lib/plankton/plankton.js +++ b/lib/plankton/plankton.js @@ -2173,6 +2173,100 @@ var lib_plankton; file.delete_ = delete_; })(file = lib_plankton.file || (lib_plankton.file = {})); })(lib_plankton || (lib_plankton = {})); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + 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 (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +/* +This file is part of »bacterio-plankton:email«. + +Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:email« 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. + +»bacterio-plankton:lang« 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 »bacterio-plankton:email«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var email; + (function (email) { + /** + */ + function send(smtp_credentials, sender, receivers, subject, content) { + return __awaiter(this, void 0, void 0, function () { + var nm_nodemailer, transporter, info; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + nm_nodemailer = require("nodemailer"); + transporter = nm_nodemailer.createTransport({ + "host": smtp_credentials.host, + "port": smtp_credentials.port, + "secure": false, + "auth": { + "user": smtp_credentials.username, + "pass": smtp_credentials.password + }, + "debug": true + }); + return [4 /*yield*/, transporter.sendMail({ + "from": sender, + "to": receivers.join(", "), + "subject": subject, + "text": content + })]; + case 1: + info = _a.sent(); + return [2 /*return*/]; + } + }); + }); + } + email.send = send; + })(email = lib_plankton.email || (lib_plankton.email = {})); +})(lib_plankton || (lib_plankton = {})); var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || @@ -2445,9 +2539,10 @@ var lib_plankton; /** * [constructor] */ - function class_channel_file(path) { + function class_channel_file(path, human_readable) { var _this = _super.call(this) || this; _this.path = path; + _this.human_readable = human_readable; return _this; } /** @@ -2455,24 +2550,40 @@ var lib_plankton; class_channel_file.prototype.add = function (entry) { var _this = this; var nm_fs = require("fs"); - nm_fs.writeFile(this.path, { + var line = (this.human_readable + ? (("<" + (new Date(Date.now())).toISOString().slice(0, 19) + ">") + + + " " + + + ("[" + log.level_show(entry.level) + "]") + + + " " + + + ("" + entry.incident + "") + + + ": " + + + JSON.stringify(entry.details, undefined, " ") + + + "\n") + : (JSON.stringify({ + "timestamp": lib_plankton.base.get_current_timestamp(), + "level_number": entry.level, + "level_name": log.level_show(entry.level), + "incident": entry.incident, + "details": entry.details + }) + + + "\n")); + nm_fs.writeFile(this.path, line, { "flag": "a+" - }, (("<" + (new Date(Date.now())).toISOString().slice(0, 19) + ">") - + - " " - + - ("[" + log.level_show(entry.level) + "]") - + - " " - + - ("" + entry.incident + "") - + - ": " - + - JSON.stringify(entry.details, undefined, " ") - + - "\n"), function (error) { - process.stderr.write('-- [plankton] could not add log entry to file ' + _this.path + "\n"); + }, function (error) { + if (error !== null) { + process.stderr.write('-- [plankton] could not add log entry to file ' + _this.path + "\n"); + } + else { + // do nothing + } }); }; return class_channel_file; @@ -2496,6 +2607,58 @@ 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 »bacterio-plankton:log«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var log; + (function (log) { + /** + */ + var class_channel_email = /** @class */ (function (_super) { + __extends(class_channel_email, _super); + /** + * [constructor] + */ + function class_channel_email(smtp_credentials, sender, receivers) { + var _this = _super.call(this) || this; + _this.smtp_credentials = smtp_credentials; + _this.sender = sender; + _this.receivers = receivers; + return _this; + } + /** + */ + class_channel_email.prototype.add = function (entry) { + var nm_fs = require("fs"); + lib_plankton.email.send(this.smtp_credentials, this.sender, this.receivers, (("[" + log.level_show(entry.level) + "]") + + + " " + + + ("" + entry.incident + "")), JSON.stringify(entry.details, undefined, " ")); + }; + return class_channel_email; + }(log.class_channel)); + log.class_channel_email = class_channel_email; + })(log = lib_plankton.log || (lib_plankton.log = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:log«. + +Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:log« 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. + +»bacterio-plankton:lang« 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 »bacterio-plankton:log«. If not, see . */ @@ -2635,7 +2798,7 @@ var lib_plankton; /** */ function channel_make(description) { - var _a, _b, _c, _d; + var _a, _b, _c, _d, _e; switch (description.kind) { default: { throw (new Error("unhandled log channel kind: " + description.kind)); @@ -2646,11 +2809,15 @@ var lib_plankton; break; } case "file": { - return (new log.class_channel_minlevel(new log.class_channel_file((_b = description.data["path"]) !== null && _b !== void 0 ? _b : "/tmp/plankton.log"), translate_level((_c = description.data["threshold"]) !== null && _c !== void 0 ? _c : "debug"))); + return (new log.class_channel_minlevel(new log.class_channel_file(((_b = description.data["path"]) !== null && _b !== void 0 ? _b : "/tmp/plankton.log"), false), translate_level((_c = description.data["threshold"]) !== null && _c !== void 0 ? _c : "debug"))); + break; + } + case "email": { + return (new log.class_channel_minlevel(new log.class_channel_email(description.data["smtp_credentials"], description.data["sender"], description.data["receivers"]), translate_level((_d = description.data["threshold"]) !== null && _d !== void 0 ? _d : "debug"))); break; } case "notify": { - return (new log.class_channel_minlevel(new log.class_channel_notify(), translate_level((_d = description.data["threshold"]) !== null && _d !== void 0 ? _d : "debug"))); + return (new log.class_channel_minlevel(new log.class_channel_notify(), translate_level((_e = description.data["threshold"]) !== null && _e !== void 0 ? _e : "debug"))); break; } } @@ -10453,7 +10620,7 @@ var lib_plankton; // "input_shape": options.input_type, // "output_shape": options.output_type, }); - lib_plankton.log.info("rest_route_added", { + lib_plankton.log.debug("rest_route_added", { "http_method": http_method, "path": path, // "routetree": rest.routetree, diff --git a/tools/update-plankton b/tools/update-plankton index 06d768b..0be60a7 100755 --- a/tools/update-plankton +++ b/tools/update-plankton @@ -19,6 +19,7 @@ modules="${modules} api" modules="${modules} rest" modules="${modules} http" modules="${modules} server" +modules="${modules} email" modules="${modules} args" modules="${modules} translate" modules="${modules} log" From 339c9a9572a7604a5f1dc08ee4f8501c35514059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Sun, 23 Jun 2024 13:53:26 +0200 Subject: [PATCH 11/11] [mod] email-sending and logging --- source/conf.ts | 571 +++++++++++++++++++++++++++++++++------------- source/helpers.ts | 71 +----- source/main.ts | 85 +++++-- 3 files changed, 475 insertions(+), 252 deletions(-) diff --git a/source/conf.ts b/source/conf.ts index c8e919f..a491920 100644 --- a/source/conf.ts +++ b/source/conf.ts @@ -16,26 +16,68 @@ You should have received a copy of the GNU General Public License along with thi namespace _espe.conf { + /** + */ + type type_log_threshold = ( + "debug" + | + "info" + | + "notice" + | + "warning" + | + "error" + ); + + + /** + */ + type type_log_format = ( + "jsonl" + | + "human_readable" + ); + + /** */ export type type_conf = { general : { language : (null | string); - verbosity : ( - "debug" - | - "notice" - | - "info" - | - "warning" - | - "error" - | - "none" - ); verification_secret : (null | string); }; + log : Array< + { + kind : "stdout"; + data : { + threshold : type_log_threshold; + }; + } + | + { + kind : "file"; + data : { + threshold : type_log_threshold; + path : string; + }; + } + | + { + kind : "email"; + data : { + threshold : type_log_threshold; + smtp_credentials : { + host : string; + port : int; + username : string; + password : string; + }; + sender : string; + receivers : Array; + }; + } + >; server : { port : int; path_base : string; @@ -151,165 +193,366 @@ namespace _espe.conf conf_raw : any ) : void { - _data = { - "general": ( - ((node_general) => ({ - "language": (node_general["language"] ?? null), - "verbosity": (node_general["verbosity"] ?? "notice"), - "verification_secret": (node_general["verification_secret"] ?? null), - })) (conf_raw["general"] ?? {}) - ), - "server": ( - ((node_server) => ({ - "port": (node_server["port"] ?? 4916), - "path_base": (node_server["path_base"] ?? ""), - })) (conf_raw["server"] ?? {}) - ), - "database": ( - ((node_database) => { - const kind : string = (node_database["kind"] ?? "sqlite"); - const node_database_data_raw = (node_database["data"] ?? {}); - switch (kind) { - case "sqlite": { - return { - "kind": kind, - "data": { - "path": (node_database_data_raw["path"] ?? "data.sqlite"), - } - }; - break; - } - case "postgresql": { - return { - "kind": kind, - "data": node_database_data_raw, - }; - break; - } - default: { - throw (new Error("unhandled")); - break; - } - } - }) (conf_raw["database"] ?? {}) - ), - "email_sending": ( - ((node_email_sending) => { - const kind : string = (node_email_sending["kind"] ?? "console"); - const data_raw = (node_email_sending["data"] ?? {}); - switch (kind) { - case "regular": { - return { - "kind": kind, - "data": { - "smtp_credentials": (data_raw["smtp_credentials"] ?? null), - "sender": data_raw["sender"], - } - }; - break; - } - case "redirect": { - return { - "kind": kind, - "data": { - "smtp_credentials": (data_raw["smtp_credentials"] ?? null), - "sender": data_raw["sender"], - "target": data_raw["target"], - } - }; - break; - } - case "console": { - return { - "kind": kind, - "data": { - } - }; - break; - } - case "drop": { - return { - "kind": kind, - "data": { - } - }; - break; - } - default: { - throw (new Error("unhandled")); - break; - } - } - }) (conf_raw["email_sending"] ?? {}) - ), - "session_management": ( - ((node_session_management) => ({ - "in_memory": (node_session_management["in_memory"] ?? true), - "drop_all_at_start": (node_session_management["drop_all_at_start"] ?? true), - "lifetime": (node_session_management["lifetime"] ?? 900), - })) (conf_raw["session_management"] ?? {}) - ), - "settings": ( - ((node_settings) => ({ - "organisation": { - "name": ((node_settings["organisation"] ?? {})["name"] ?? "Example Orginsation"), // TODO: mandatory? - "domain": ((node_settings["organisation"] ?? {})["domain"] ?? "example.org"), // TODO: mandatory? - }, - "misc": ( - ((node_settings_misc) => ({ - "prefix_for_veiled_email_addresses": (node_settings_misc["prefix_for_veiled_email_addresses"] ?? "member-"), - "facultative_membership_number": (node_settings_misc["facultative_membership_number"] ?? false), - "auto_register": (node_settings_misc["auto_register"] ?? false), - })) (node_settings["misc"] ?? {}) + switch (conf_raw["version"]) { + case 1: { + _data = { + "general": ( + ((node_general) => ({ + "language": (node_general["language"] ?? null), + "verification_secret": (node_general["verification_secret"] ?? null), + })) (conf_raw["general"] ?? {}) ), - "summon_email": ( - ((node_settings_summon_email) => ({ - "remark": (node_settings_summon_email["remark"] ?? null), - })) (node_settings["summon_email"] ?? {}) + "log": [ + { + "kind": "stdout", + "data": { + "threshold": ((conf_raw["general"] ?? {})["verbosity"] ?? "notice"), + } + }, + ], + "server": ( + ((node_server) => ({ + "port": (node_server["port"] ?? 4916), + "path_base": (node_server["path_base"] ?? ""), + })) (conf_raw["server"] ?? {}) ), - "password_policy": ( - ((node_settings_password_policy) => ({ - "minimum_length": ( - ("minimum_length" in node_settings_password_policy) - ? node_settings_password_policy["minimum_length"] - : 8 + "database": ( + ((node_database) => { + const kind : string = (node_database["kind"] ?? "sqlite"); + const node_database_data_raw = (node_database["data"] ?? {}); + switch (kind) { + case "sqlite": { + return { + "kind": kind, + "data": { + "path": (node_database_data_raw["path"] ?? "data.sqlite"), + } + }; + break; + } + case "postgresql": { + return { + "kind": kind, + "data": node_database_data_raw, + }; + break; + } + default: { + throw (new Error("unhandled")); + break; + } + } + }) (conf_raw["database"] ?? {}) + ), + "email_sending": ( + ((node_email_sending) => { + const kind : string = (node_email_sending["kind"] ?? "console"); + const data_raw = (node_email_sending["data"] ?? {}); + switch (kind) { + case "regular": { + return { + "kind": kind, + "data": { + "smtp_credentials": (data_raw["smtp_credentials"] ?? null), + "sender": data_raw["sender"], + } + }; + break; + } + case "redirect": { + return { + "kind": kind, + "data": { + "smtp_credentials": (data_raw["smtp_credentials"] ?? null), + "sender": data_raw["sender"], + "target": data_raw["target"], + } + }; + break; + } + case "console": { + return { + "kind": kind, + "data": { + } + }; + break; + } + case "drop": { + return { + "kind": kind, + "data": { + } + }; + break; + } + default: { + throw (new Error("unhandled")); + break; + } + } + }) (conf_raw["email_sending"] ?? {}) + ), + "session_management": ( + ((node_session_management) => ({ + "in_memory": (node_session_management["in_memory"] ?? true), + "drop_all_at_start": (node_session_management["drop_all_at_start"] ?? true), + "lifetime": (node_session_management["lifetime"] ?? 900), + })) (conf_raw["session_management"] ?? {}) + ), + "settings": ( + ((node_settings) => ({ + "organisation": { + "name": ((node_settings["organisation"] ?? {})["name"] ?? "Example Orginsation"), // TODO: mandatory? + "domain": ((node_settings["organisation"] ?? {})["domain"] ?? "example.org"), // TODO: mandatory? + }, + "misc": ( + ((node_settings_misc) => ({ + "prefix_for_veiled_email_addresses": (node_settings_misc["prefix_for_veiled_email_addresses"] ?? "member-"), + "facultative_membership_number": (node_settings_misc["facultative_membership_number"] ?? false), + "auto_register": (node_settings_misc["auto_register"] ?? false), + })) (node_settings["misc"] ?? {}) ), - "maximum_length": ( - ("maximum_length" in node_settings_password_policy) - ? node_settings_password_policy["maximum_length"] - : 240 + "summon_email": ( + ((node_settings_summon_email) => ({ + "remark": (node_settings_summon_email["remark"] ?? null), + })) (node_settings["summon_email"] ?? {}) ), - "must_contain_letter": (node_settings_password_policy["must_contain_letter"] ?? true), - "must_contain_number": (node_settings_password_policy["must_contain_number"] ?? true), - "must_contain_special_character": (node_settings_password_policy["must_contain_special_character"] ?? true), - })) (node_settings["password_policy"] ?? {}) + "password_policy": ( + ((node_settings_password_policy) => ({ + "minimum_length": ( + ("minimum_length" in node_settings_password_policy) + ? node_settings_password_policy["minimum_length"] + : 8 + ), + "maximum_length": ( + ("maximum_length" in node_settings_password_policy) + ? node_settings_password_policy["maximum_length"] + : 240 + ), + "must_contain_letter": (node_settings_password_policy["must_contain_letter"] ?? true), + "must_contain_number": (node_settings_password_policy["must_contain_number"] ?? true), + "must_contain_special_character": (node_settings_password_policy["must_contain_special_character"] ?? true), + })) (node_settings["password_policy"] ?? {}) + ), + "password_change": ( + ((node_settings_password_change) => ({ + "cooldown_time": (node_settings_password_change["cooldown_time"] ?? 86400), + })) (node_settings["password_change"] ?? {}) + ), + "name_index": ( + ((node_settings_password_policy) => ({ + "veil": (node_settings_password_policy["veil"] ?? true), + "salt": (node_settings_password_policy["salt"] ?? ""), + })) (node_settings["name_index"] ?? {}) + ), + "connections": ( + ((node_settings_connections) => ({ + "frontend_url_base": (node_settings_connections["frontend_url_base"] ?? null), + "login_url": (node_settings_connections["login_url"] ?? null), + })) (node_settings["connections"] ?? {}) + ), + })) (conf_raw["settings"] ?? {}) ), - "password_change": ( - ((node_settings_password_change) => ({ - "cooldown_time": (node_settings_password_change["cooldown_time"] ?? 86400), - })) (node_settings["password_change"] ?? {}) + "admins": (conf_raw["admins"] ?? []), + "output": ( + ((node_session_output) => ({ + "authelia": (node_session_output["authelia"] ?? null), + })) (conf_raw["output"] ?? {}) ), - "name_index": ( - ((node_settings_password_policy) => ({ - "veil": (node_settings_password_policy["veil"] ?? true), - "salt": (node_settings_password_policy["salt"] ?? ""), - })) (node_settings["name_index"] ?? {}) + }; + break; + } + case 2: { + _data = { + "general": ( + ((node_general) => ({ + "language": (node_general["language"] ?? null), + "verification_secret": (node_general["verification_secret"] ?? null), + })) (conf_raw["general"] ?? {}) ), - "connections": ( - ((node_settings_connections) => ({ - "frontend_url_base": (node_settings_connections["frontend_url_base"] ?? null), - "login_url": (node_settings_connections["login_url"] ?? null), - })) (node_settings["connections"] ?? {}) + "log": ( + ((node_log) => node_log.map( + (node_log_entry : any) => ({ + "kind": node_log_entry["kind"], + "data": Object.assign( + { + "format": "human_readable", + "threshold": "notice", + }, + (node_log_entry["data"] ?? {}) + ) + }) + )) ( + conf_raw["log"] + ?? + [ + { + "kind": "console", + "data": { + } + }, + ] + ) ), - })) (conf_raw["settings"] ?? {}) - ), - "admins": (conf_raw["admins"] ?? []), - "output": ( - ((node_session_output) => ({ - "authelia": (node_session_output["authelia"] ?? null), - })) (conf_raw["output"] ?? {}) - ), - }; + "server": ( + ((node_server) => ({ + "port": (node_server["port"] ?? 4916), + "path_base": (node_server["path_base"] ?? ""), + })) (conf_raw["server"] ?? {}) + ), + "database": ( + ((node_database) => { + const kind : string = (node_database["kind"] ?? "sqlite"); + const node_database_data_raw = (node_database["data"] ?? {}); + switch (kind) { + case "sqlite": { + return { + "kind": kind, + "data": { + "path": (node_database_data_raw["path"] ?? "data.sqlite"), + } + }; + break; + } + case "postgresql": { + return { + "kind": kind, + "data": node_database_data_raw, + }; + break; + } + default: { + throw (new Error("unhandled")); + break; + } + } + }) (conf_raw["database"] ?? {}) + ), + "email_sending": ( + ((node_email_sending) => { + const kind : string = (node_email_sending["kind"] ?? "console"); + const data_raw = (node_email_sending["data"] ?? {}); + switch (kind) { + case "regular": { + return { + "kind": kind, + "data": { + "smtp_credentials": (data_raw["smtp_credentials"] ?? null), + "sender": data_raw["sender"], + } + }; + break; + } + case "redirect": { + return { + "kind": kind, + "data": { + "smtp_credentials": (data_raw["smtp_credentials"] ?? null), + "sender": data_raw["sender"], + "target": data_raw["target"], + } + }; + break; + } + case "console": { + return { + "kind": kind, + "data": { + } + }; + break; + } + case "drop": { + return { + "kind": kind, + "data": { + } + }; + break; + } + default: { + throw (new Error("unhandled")); + break; + } + } + }) (conf_raw["email_sending"] ?? {}) + ), + "session_management": ( + ((node_session_management) => ({ + "in_memory": (node_session_management["in_memory"] ?? true), + "drop_all_at_start": (node_session_management["drop_all_at_start"] ?? true), + "lifetime": (node_session_management["lifetime"] ?? 900), + })) (conf_raw["session_management"] ?? {}) + ), + "settings": ( + ((node_settings) => ({ + "organisation": { + "name": ((node_settings["organisation"] ?? {})["name"] ?? "Example Orginsation"), // TODO: mandatory? + "domain": ((node_settings["organisation"] ?? {})["domain"] ?? "example.org"), // TODO: mandatory? + }, + "misc": ( + ((node_settings_misc) => ({ + "prefix_for_veiled_email_addresses": (node_settings_misc["prefix_for_veiled_email_addresses"] ?? "member-"), + "facultative_membership_number": (node_settings_misc["facultative_membership_number"] ?? false), + "auto_register": (node_settings_misc["auto_register"] ?? false), + })) (node_settings["misc"] ?? {}) + ), + "summon_email": ( + ((node_settings_summon_email) => ({ + "remark": (node_settings_summon_email["remark"] ?? null), + })) (node_settings["summon_email"] ?? {}) + ), + "password_policy": ( + ((node_settings_password_policy) => ({ + "minimum_length": ( + ("minimum_length" in node_settings_password_policy) + ? node_settings_password_policy["minimum_length"] + : 8 + ), + "maximum_length": ( + ("maximum_length" in node_settings_password_policy) + ? node_settings_password_policy["maximum_length"] + : 240 + ), + "must_contain_letter": (node_settings_password_policy["must_contain_letter"] ?? true), + "must_contain_number": (node_settings_password_policy["must_contain_number"] ?? true), + "must_contain_special_character": (node_settings_password_policy["must_contain_special_character"] ?? true), + })) (node_settings["password_policy"] ?? {}) + ), + "password_change": ( + ((node_settings_password_change) => ({ + "cooldown_time": (node_settings_password_change["cooldown_time"] ?? 86400), + })) (node_settings["password_change"] ?? {}) + ), + "name_index": ( + ((node_settings_password_policy) => ({ + "veil": (node_settings_password_policy["veil"] ?? true), + "salt": (node_settings_password_policy["salt"] ?? ""), + })) (node_settings["name_index"] ?? {}) + ), + "connections": ( + ((node_settings_connections) => ({ + "frontend_url_base": (node_settings_connections["frontend_url_base"] ?? null), + "login_url": (node_settings_connections["login_url"] ?? null), + })) (node_settings["connections"] ?? {}) + ), + })) (conf_raw["settings"] ?? {}) + ), + "admins": (conf_raw["admins"] ?? []), + "output": ( + ((node_session_output) => ({ + "authelia": (node_session_output["authelia"] ?? null), + })) (conf_raw["output"] ?? {}) + ), + }; + break; + } + default: { + throw (new Error("invalid conf version: " + conf_raw["version"])); + break; + } + } } diff --git a/source/helpers.ts b/source/helpers.ts index 4896501..134e811 100644 --- a/source/helpers.ts +++ b/source/helpers.ts @@ -124,61 +124,6 @@ namespace _espe.helpers } - /** - * @todo outsource? - */ - async function email_send_real( - smtp_credentials : { - host : string; - port : int; - username : string; - password : string; - }, - receivers : Array, - subject : string, - content : string, - options : { - sender ?: (null | string); - } = {} - ) : Promise - { - options = Object.assign( - { - "sender": /*null*/"admin@example.org", - }, - options - ); - lib_plankton.log.info( - "email_send_real", - { - "receivers": receivers, - "subject": subject, - } - ); - const nm_nodemailer = require("nodemailer"); - const transporter = nm_nodemailer.createTransport( - { - "host": smtp_credentials.host, - "port": smtp_credentials.port, - "secure": false, - "auth": { - "user": smtp_credentials.username, - "pass": smtp_credentials.password, - }, - "debug": true, - } - ); - const info = await transporter.sendMail( - { - "from": (options.sender ?? ""), - "to": receivers.join(", "), - "subject": subject, - "text": content, - } - ) - } - - /** */ export async function email_send( @@ -207,14 +152,12 @@ namespace _espe.helpers return Promise.reject("no smtp credentials specified; add in conf as 'email_sending.data.smtp_credentials'!"); } else { - return email_send_real( + return lib_plankton.email.send( parameters.smtp_credentials, + parameters.sender, receivers, subject, - content, - { - "sender": parameters.sender, - } + content ); } break; @@ -230,8 +173,9 @@ namespace _espe.helpers return Promise.reject("no smtp credentials specified; add in conf as 'email_sending.data.smtp_credentials'!"); } else { - return email_send_real( + return lib_plankton.email.send( parameters.smtp_credentials, + parameters.sender, [parameters.target], lib_plankton.string.coin( "[REDIRECTION] {{receivers}} | {{original_subject}}", @@ -240,10 +184,7 @@ namespace _espe.helpers "original_subject": subject } ), - content, - { - "sender": parameters.sender, - } + content ); } break; diff --git a/source/main.ts b/source/main.ts index e513c8f..898d7b1 100644 --- a/source/main.ts +++ b/source/main.ts @@ -21,17 +21,61 @@ async function main( ) : Promise { // init - await lib_plankton.translate.initialize( - { - "verbosity": 1, - "packages": [ - // TODO: error handling - JSON.parse(await lib_plankton.file.read("data/localization/deu.loc.json")), - JSON.parse(await lib_plankton.file.read("data/localization/eng.loc.json")), - ], - "order": ["deu", "eng"], - "autopromote": false, - } + lib_plankton.log.conf_push( + [ + lib_plankton.log.channel_make( + { + "kind": "stdout", + "data": { + "threshold": "notice", + // "format": "human_readable", + } + } + ), + ] + ); + const language_codes : Array = [ + "deu", + "eng", + ]; + await ( + Promise.all( + language_codes + .map( + language_code => ( + lib_plankton.file.read( + lib_plankton.string.coin( + "data/localization/{{language_code}}.loc.json", + { + "language_code": language_code, + } + ) + ) + .then( + content => (new Promise( + (resolve, reject) => { + try { + resolve(JSON.parse(content)); + } + catch (error) { + reject(error); + } + } + )) + ) + ) + ) + ) + .then( + packages => lib_plankton.translate.initialize( + { + "verbosity": 1, + "packages": packages, + "order": language_codes, + "autopromote": false, + } + ) + ) ); // args @@ -139,19 +183,14 @@ async function main( lib_plankton.translate.promote(_espe.conf.get().general.language); } lib_plankton.log.conf_push( - [ - new lib_plankton.log.class_channel_minlevel( - new lib_plankton.log.class_channel_stdout(), + _espe.conf.get().log.map( + log_output => lib_plankton.log.channel_make( { - "none": lib_plankton.log.enum_level.error, - "error": lib_plankton.log.enum_level.error, - "warning": lib_plankton.log.enum_level.warning, - "notice": lib_plankton.log.enum_level.notice, - "info": lib_plankton.log.enum_level.info, - "debug":lib_plankton.log.enum_level.debug, - }[_espe.conf.get().general.verbosity] - ), - ] + "kind": log_output.kind, + "data": log_output.data + } + ) + ) ); // exec