Compare commits
4 commits
main
...
dev-plankt
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2793aa1ba4 | ||
|
|
d3f9a88958 | ||
|
|
eb74ecd66f | ||
|
|
1bd8a9fe36 |
|
|
@ -2,7 +2,7 @@
|
||||||
"general": {
|
"general": {
|
||||||
"language": null,
|
"language": null,
|
||||||
"verbosity": "info",
|
"verbosity": "info",
|
||||||
"verification_secret": "foobar"
|
"verification_secret": null
|
||||||
},
|
},
|
||||||
"log": [
|
"log": [
|
||||||
{
|
{
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
"database": {
|
"database": {
|
||||||
"kind": "sqlite",
|
"kind": "sqlite",
|
||||||
"data": {
|
"data": {
|
||||||
"path": "../espe.sqlite"
|
"path": "data.sqlite"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"email_sending": {
|
"email_sending": {
|
||||||
|
|
@ -44,6 +44,14 @@
|
||||||
"name": "Example Orginsation",
|
"name": "Example Orginsation",
|
||||||
"domain": "example.org"
|
"domain": "example.org"
|
||||||
},
|
},
|
||||||
|
"misc": {
|
||||||
|
"prefix_for_veiled_email_addresses": "member-",
|
||||||
|
"facultative_membership_number": true,
|
||||||
|
"auto_register": true
|
||||||
|
},
|
||||||
|
"summon_email": {
|
||||||
|
"remark": null
|
||||||
|
},
|
||||||
"password_policy": {
|
"password_policy": {
|
||||||
"minimum_length": 4,
|
"minimum_length": 4,
|
||||||
"maximum_length": 12,
|
"maximum_length": 12,
|
||||||
|
|
@ -54,11 +62,13 @@
|
||||||
"password_change": {
|
"password_change": {
|
||||||
"cooldown_time": 300
|
"cooldown_time": 300
|
||||||
},
|
},
|
||||||
|
"name_index": {
|
||||||
|
"veil": false,
|
||||||
|
"salt": null
|
||||||
|
},
|
||||||
"connections": {
|
"connections": {
|
||||||
"frontend_url_base": "http://localhost:8888",
|
"frontend_url_base": null,
|
||||||
"frontend_path_template_invitation_handle": "/#invitation_handle,key={{key}}",
|
"login_url": null
|
||||||
"frontend_path_template_password_change": "/#password_change_exec,id={{id}},key={{key}}",
|
|
||||||
"login_url": "https://login.example.org"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
{
|
|
||||||
"groups": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"name": "auto",
|
|
||||||
"label": "Auto"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 2,
|
|
||||||
"name": "zug",
|
|
||||||
"label": "Zug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 3,
|
|
||||||
"name": "flugzeug",
|
|
||||||
"label": "Flugzeug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 4,
|
|
||||||
"name": "fahrrad",
|
|
||||||
"label": "Fahrrad"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 5,
|
|
||||||
"name": "zu_fusz",
|
|
||||||
"label": "zu Fuß"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"admins": [
|
|
||||||
{
|
|
||||||
"name": "admin",
|
|
||||||
"email_address": "admin@example.org",
|
|
||||||
"password": "admin"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"members": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"name": "alexandra",
|
|
||||||
"label": "Alexandra Ahorn",
|
|
||||||
"email_address": "alex-rockt@example.org",
|
|
||||||
"groups": [1, 2, 3],
|
|
||||||
"password": "aaa111"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 2,
|
|
||||||
"name": "berthold",
|
|
||||||
"label": "Berthold Buche",
|
|
||||||
"email_address": "bert-ohne-ernie@example.org",
|
|
||||||
"groups": [4, 5, 2],
|
|
||||||
"password": "bbb222"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 3,
|
|
||||||
"name": "charlotte",
|
|
||||||
"label": "Charlotte Castania",
|
|
||||||
"email_address": "charly-the-unicorn@example.org",
|
|
||||||
"groups": [4, 1],
|
|
||||||
"password": "ccc333"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"invitations": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"name_changeable": false,
|
|
||||||
"name_value": "daniel",
|
|
||||||
"label_changeable": true,
|
|
||||||
"label_value": "Daniel Distel",
|
|
||||||
"email_address_changeable": true,
|
|
||||||
"email_address_value": "duesentrieb@example.org",
|
|
||||||
"groups_changeable": false,
|
|
||||||
"groups_value": [3, 5]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
## Beschreibung
|
## Beschreibung
|
||||||
|
|
||||||
- Hintergrund-Dienst für [Espe](/espe/meta)
|
- Hintergrund-Dienst für [Espe](https://gitlab.die-linke.cloud/espe/documentation)
|
||||||
|
|
||||||
|
|
||||||
## Erstellung
|
## Erstellung
|
||||||
|
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
/*
|
|
||||||
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
|
||||||
Copyright (C) 2024 Christian Fraß
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
|
||||||
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with this program. If not, see
|
|
||||||
<https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace _espe.api
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export function register_group_add(
|
|
||||||
rest_subject : lib_plankton.rest_http.type_rest
|
|
||||||
) : void
|
|
||||||
{
|
|
||||||
lib_plankton.rest_http.register<
|
|
||||||
{
|
|
||||||
name : string;
|
|
||||||
label : string;
|
|
||||||
},
|
|
||||||
(string | _espe.type.group_id)
|
|
||||||
>(
|
|
||||||
rest_subject,
|
|
||||||
lib_plankton.http.enum_method.post,
|
|
||||||
_espe.api.full_path("/group/add"),
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @todo translation
|
|
||||||
*/
|
|
||||||
"description": () => "erstellt eine Gruppe",
|
|
||||||
"input_schema": () => ({
|
|
||||||
"nullable": false,
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"label": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"additionalProperties": false,
|
|
||||||
"required": [
|
|
||||||
"name",
|
|
||||||
"label",
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
"output_schema": () => ({
|
|
||||||
"nullable": false,
|
|
||||||
"type": "number",
|
|
||||||
}),
|
|
||||||
"restriction": () => restriction_logged_in,
|
|
||||||
"execution": () => async ({"input": input}) => {
|
|
||||||
if (input === null) {
|
|
||||||
return Promise.resolve({
|
|
||||||
"status_code": 400,
|
|
||||||
"data": ""
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const data = await _espe.service.group.add(
|
|
||||||
{
|
|
||||||
"name": input["name"],
|
|
||||||
"label": input["label"]
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return Promise.resolve({
|
|
||||||
"status_code": 200,
|
|
||||||
"data": data
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,94 +0,0 @@
|
||||||
/*
|
|
||||||
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
|
||||||
Copyright (C) 2024 Christian Fraß
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
|
||||||
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with this program. If not, see
|
|
||||||
<https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace _espe.api
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export function register_group_list(
|
|
||||||
rest_subject : lib_plankton.rest_http.type_rest
|
|
||||||
) : void
|
|
||||||
{
|
|
||||||
lib_plankton.rest_http.register<
|
|
||||||
null,
|
|
||||||
Array<
|
|
||||||
{
|
|
||||||
id : _espe.type.invitation_id;
|
|
||||||
preview : {
|
|
||||||
name : string;
|
|
||||||
label : string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
>
|
|
||||||
>(
|
|
||||||
rest_subject,
|
|
||||||
lib_plankton.http.enum_method.get,
|
|
||||||
_espe.api.full_path("/group/list"),
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @todo translation
|
|
||||||
*/
|
|
||||||
"description": () => "listet alle Gruppen auf",
|
|
||||||
"output_schema": () => ({
|
|
||||||
"type": "object",
|
|
||||||
"nullable": false,
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "intiger",
|
|
||||||
"description": "ID"
|
|
||||||
},
|
|
||||||
"preview": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "string",
|
|
||||||
"description": "Name"
|
|
||||||
},
|
|
||||||
"label": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "string",
|
|
||||||
"description": "Beschriftung"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"additionalProperties": false,
|
|
||||||
"required": [
|
|
||||||
"name",
|
|
||||||
"label",
|
|
||||||
]
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"id",
|
|
||||||
"preview",
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
"restriction": () => restriction_none,
|
|
||||||
"execution": () => async ({}) => {
|
|
||||||
const data = await _espe.service.group.list();
|
|
||||||
return Promise.resolve({
|
|
||||||
"status_code": 200,
|
|
||||||
"data": data,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
/*
|
|
||||||
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
|
||||||
Copyright (C) 2024 Christian Fraß
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
|
||||||
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with this program. If not, see
|
|
||||||
<https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace _espe.api
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export function register_group_modify(
|
|
||||||
rest_subject : lib_plankton.rest_http.type_rest
|
|
||||||
) : void
|
|
||||||
{
|
|
||||||
lib_plankton.rest_http.register<
|
|
||||||
{
|
|
||||||
label : string;
|
|
||||||
},
|
|
||||||
null
|
|
||||||
>(
|
|
||||||
rest_subject,
|
|
||||||
lib_plankton.http.enum_method.patch,
|
|
||||||
_espe.api.full_path("/group/modify/:id"),
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @todo translation
|
|
||||||
*/
|
|
||||||
"description": () => "ändert eine Gruppe",
|
|
||||||
"input_schema": () => ({
|
|
||||||
"nullable": false,
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"label": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"additionalProperties": false,
|
|
||||||
"required": [
|
|
||||||
"label",
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
"output_schema": () => ({
|
|
||||||
"nullable": true,
|
|
||||||
}),
|
|
||||||
"restriction": () => restriction_logged_in,
|
|
||||||
"execution": () => async ({"path_parameters": path_parameters, "input": input}) => {
|
|
||||||
if (input === null) {
|
|
||||||
return Promise.resolve({
|
|
||||||
"status_code": 400,
|
|
||||||
"data": null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const group_id : _espe.type.group_id = parseInt(path_parameters["id"]);
|
|
||||||
const data = await _espe.service.group.modify(
|
|
||||||
group_id,
|
|
||||||
input["label"]
|
|
||||||
);
|
|
||||||
return Promise.resolve({
|
|
||||||
"status_code": 200,
|
|
||||||
"data": null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
/*
|
|
||||||
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
|
||||||
Copyright (C) 2024 Christian Fraß
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
|
||||||
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with this program. If not, see
|
|
||||||
<https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace _espe.api
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export function register_group_read(
|
|
||||||
rest_subject : lib_plankton.rest_http.type_rest
|
|
||||||
) : void
|
|
||||||
{
|
|
||||||
lib_plankton.rest_http.register<
|
|
||||||
null,
|
|
||||||
{
|
|
||||||
name : string;
|
|
||||||
label : string;
|
|
||||||
}
|
|
||||||
>(
|
|
||||||
rest_subject,
|
|
||||||
lib_plankton.http.enum_method.get,
|
|
||||||
_espe.api.full_path("/group/read/:id"),
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @todo translation
|
|
||||||
*/
|
|
||||||
"description": () => "gibt die Daten zu einer Gruppen aus",
|
|
||||||
"output_schema": () => ({
|
|
||||||
"nullable": false,
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"label": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"additionalProperties": false,
|
|
||||||
"required": [
|
|
||||||
"name",
|
|
||||||
"label",
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
"restriction": () => restriction_logged_in,
|
|
||||||
"execution": () => async ({"path_parameters": path_parameters}) => {
|
|
||||||
const group_id : _espe.type.group_id = parseInt(path_parameters["id"]);
|
|
||||||
const group_object : _espe.type.group_object = await _espe.service.group.get(group_id);
|
|
||||||
return Promise.resolve({
|
|
||||||
"status_code": 200,
|
|
||||||
"data": group_object
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,196 +0,0 @@
|
||||||
/*
|
|
||||||
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
|
||||||
Copyright (C) 2024 Christian Fraß
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
|
||||||
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with this program. If not, see
|
|
||||||
<https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace _espe.api
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export function register_invitation_create(
|
|
||||||
rest_subject : lib_plankton.rest_http.type_rest
|
|
||||||
) : void
|
|
||||||
{
|
|
||||||
lib_plankton.rest_http.register<
|
|
||||||
{
|
|
||||||
data : {
|
|
||||||
name_changeable : boolean;
|
|
||||||
name_value : string;
|
|
||||||
label_changeable : boolean;
|
|
||||||
label_value : string;
|
|
||||||
email_address_changeable : boolean;
|
|
||||||
email_address_value : (null | string);
|
|
||||||
groups_changeable : boolean;
|
|
||||||
groups_value : Array<int>;
|
|
||||||
expiry : (null | int);
|
|
||||||
};
|
|
||||||
send_immediatly : boolean;
|
|
||||||
},
|
|
||||||
(
|
|
||||||
string
|
|
||||||
|
|
|
||||||
{
|
|
||||||
id : _espe.type.member_id;
|
|
||||||
key : string;
|
|
||||||
url : (null | string);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
>(
|
|
||||||
rest_subject,
|
|
||||||
lib_plankton.http.enum_method.post,
|
|
||||||
_espe.api.full_path("/invitation/create"),
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @todo translation
|
|
||||||
*/
|
|
||||||
"description": () => "erstellt eine Einladung und gibt die erzeugte ID und den erzeugten Schlüssel aus",
|
|
||||||
"input_schema": () => ({
|
|
||||||
"type": "object",
|
|
||||||
"nullable": false,
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"data": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"expiry": {
|
|
||||||
"nullable": true,
|
|
||||||
"type": "intiger",
|
|
||||||
"description": "Ablaufzeitpunkt"
|
|
||||||
},
|
|
||||||
"name_changeable": {
|
|
||||||
"type": "boolean",
|
|
||||||
"nullable": false,
|
|
||||||
"description": "Name | änderbar"
|
|
||||||
},
|
|
||||||
"name_value": {
|
|
||||||
"type": "string",
|
|
||||||
"nullable": true,
|
|
||||||
"description": "Name | Wert"
|
|
||||||
},
|
|
||||||
"email_address_changeable": {
|
|
||||||
"type": "boolean",
|
|
||||||
"nullable": false,
|
|
||||||
"description": "E-Mail-Adresse | änderbar"
|
|
||||||
},
|
|
||||||
"email_address_value": {
|
|
||||||
"type": "string",
|
|
||||||
"nullable": true,
|
|
||||||
"description": "E-Mail-Adresse | Wert"
|
|
||||||
},
|
|
||||||
"groups_integer": {
|
|
||||||
"type": "integer",
|
|
||||||
"nullable": true,
|
|
||||||
"description": "Gruppen | Modus"
|
|
||||||
},
|
|
||||||
"groups_value": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "integer",
|
|
||||||
"nullable": false,
|
|
||||||
},
|
|
||||||
"description": "Gruppen | Wert"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"membership_number_changeable",
|
|
||||||
"membership_number_value",
|
|
||||||
"name_changeable",
|
|
||||||
"name_value",
|
|
||||||
"email_address_changeable",
|
|
||||||
"email_address_value",
|
|
||||||
"groups_changeable",
|
|
||||||
"groups_value",
|
|
||||||
"expiry",
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"send_immediatly": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Einladungs-Link direkt an angegebene E-Mail-Adresse versenden"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"data",
|
|
||||||
"send_immediatly",
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
"output_schema": () => ({
|
|
||||||
"type": "object",
|
|
||||||
"nullable": false,
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "number",
|
|
||||||
"nullable": false,
|
|
||||||
},
|
|
||||||
"key": {
|
|
||||||
"type": "string",
|
|
||||||
"nullable": false,
|
|
||||||
},
|
|
||||||
"url": {
|
|
||||||
"type": "string",
|
|
||||||
"nullable": true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"additionalProperties": false,
|
|
||||||
"required": [
|
|
||||||
"id",
|
|
||||||
"key",
|
|
||||||
"url",
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
"restriction": () => restriction_logged_in,
|
|
||||||
"execution": () => async ({"input": input}) => {
|
|
||||||
if (input === null)
|
|
||||||
{
|
|
||||||
return Promise.reject(new Error("impossible"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const invitation_info : {
|
|
||||||
id : _espe.type.invitation_id;
|
|
||||||
key : _espe.type.invitation_key;
|
|
||||||
url : (null | string);
|
|
||||||
} = await _espe.service.invitation.create(
|
|
||||||
{
|
|
||||||
"name_changeable": input.data.name_changeable,
|
|
||||||
"name_value": input.data.name_value,
|
|
||||||
"label_changeable": input.data.label_changeable,
|
|
||||||
"label_value": input.data.label_value,
|
|
||||||
"email_address_changeable": input.data.email_address_changeable,
|
|
||||||
"email_address_value": input.data.email_address_value,
|
|
||||||
"groups_changeable": input.data.groups_changeable,
|
|
||||||
"groups_value": input.data.groups_value,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"expiry": input.data.expiry,
|
|
||||||
"send_immediatly": input.send_immediatly,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return Promise.resolve(
|
|
||||||
{
|
|
||||||
"status_code": 201,
|
|
||||||
"data": invitation_info
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,143 +0,0 @@
|
||||||
/*
|
|
||||||
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
|
||||||
Copyright (C) 2024 Christian Fraß
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
|
||||||
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with this program. If not, see
|
|
||||||
<https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace _espe.api
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export function register_invitation_examine(
|
|
||||||
rest_subject : lib_plankton.rest_http.type_rest
|
|
||||||
) : void
|
|
||||||
{
|
|
||||||
lib_plankton.rest_http.register<
|
|
||||||
any,
|
|
||||||
any
|
|
||||||
>(
|
|
||||||
rest_subject,
|
|
||||||
lib_plankton.http.enum_method.get,
|
|
||||||
_espe.api.full_path("/invitation/examine"),
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @todo translation
|
|
||||||
*/
|
|
||||||
"description": () => "gibt die Daten einer Einladung anhand ihres Schlüssels aus",
|
|
||||||
"query_parameters": () => [
|
|
||||||
{
|
|
||||||
"name": "key",
|
|
||||||
"required": true,
|
|
||||||
"description": "key",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"output_schema": () => ({
|
|
||||||
"type": "object",
|
|
||||||
"nullable": false,
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"expiry": {
|
|
||||||
"nullable": true,
|
|
||||||
"type": "integer",
|
|
||||||
"description": "Ablaufzeitpunkt"
|
|
||||||
},
|
|
||||||
"name_changeable": {
|
|
||||||
"type": "boolean",
|
|
||||||
"nullable": false,
|
|
||||||
"description": "Name | änderbar"
|
|
||||||
},
|
|
||||||
"name_value": {
|
|
||||||
"type": "string",
|
|
||||||
"nullable": true,
|
|
||||||
"description": "Name | Wert"
|
|
||||||
},
|
|
||||||
"label_changeable": {
|
|
||||||
"type": "boolean",
|
|
||||||
"nullable": false,
|
|
||||||
"description": "Beschriftung | änderbar"
|
|
||||||
},
|
|
||||||
"label_value": {
|
|
||||||
"type": "string",
|
|
||||||
"nullable": true,
|
|
||||||
"description": "Beschriftung | Wert"
|
|
||||||
},
|
|
||||||
"email_address_changeable": {
|
|
||||||
"type": "boolean",
|
|
||||||
"nullable": false,
|
|
||||||
"description": "E-Mail-Adresse | änderbar"
|
|
||||||
},
|
|
||||||
"email_address_value": {
|
|
||||||
"type": "string",
|
|
||||||
"nullable": true,
|
|
||||||
"description": "E-Mail-Adresse | Wert"
|
|
||||||
},
|
|
||||||
"groups_changeable": {
|
|
||||||
"type": "boolean",
|
|
||||||
"nullable": false,
|
|
||||||
"description": "Gruppen | änderbar"
|
|
||||||
},
|
|
||||||
"groups_value": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string",
|
|
||||||
"nullable": false,
|
|
||||||
},
|
|
||||||
"description": "Gruppen | Wert"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"expiry",
|
|
||||||
"name_changeable",
|
|
||||||
"name_value",
|
|
||||||
"label_changeable",
|
|
||||||
"label_value",
|
|
||||||
"email_address_changeable",
|
|
||||||
"email_address_value",
|
|
||||||
"groups_changeable",
|
|
||||||
"groups_value",
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
"restriction": () => restriction_none,
|
|
||||||
"execution": () => ({"query_parameters": query_parameters, "input": input}) => {
|
|
||||||
const invitation_key : _espe.type.invitation_key = query_parameters["key"];
|
|
||||||
return (
|
|
||||||
_espe.service.invitation.examine(invitation_key)
|
|
||||||
.then(
|
|
||||||
(invitation_object) => Promise.resolve({
|
|
||||||
"status_code": 200,
|
|
||||||
"data": {
|
|
||||||
"expiry": invitation_object.expiry,
|
|
||||||
"name_changeable": invitation_object.name_changeable,
|
|
||||||
"name_value": invitation_object.name_value,
|
|
||||||
"label_changeable": invitation_object.label_changeable,
|
|
||||||
"label_value": invitation_object.label_value,
|
|
||||||
"email_address_changeable": invitation_object.email_address_changeable,
|
|
||||||
"email_address_value": invitation_object.email_address_value,
|
|
||||||
"groups_changeable": invitation_object.groups_changeable,
|
|
||||||
"groups_value": invitation_object.groups_value,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.catch(
|
|
||||||
(error) => Promise.resolve({
|
|
||||||
"status_code": 404,
|
|
||||||
"data": "not found"
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,94 +0,0 @@
|
||||||
/*
|
|
||||||
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
|
||||||
Copyright (C) 2024 Christian Fraß
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
|
||||||
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with this program. If not, see
|
|
||||||
<https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace _espe.api
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export function register_invitation_list(
|
|
||||||
rest_subject : lib_plankton.rest_http.type_rest
|
|
||||||
) : void
|
|
||||||
{
|
|
||||||
lib_plankton.rest_http.register<
|
|
||||||
null,
|
|
||||||
Array<
|
|
||||||
{
|
|
||||||
id : _espe.type.invitation_id;
|
|
||||||
preview : {
|
|
||||||
key : _espe.type.invitation_key;
|
|
||||||
expiry : (null | int);
|
|
||||||
name_value : (null | string);
|
|
||||||
label_value : (null | string);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
>
|
|
||||||
>(
|
|
||||||
rest_subject,
|
|
||||||
lib_plankton.http.enum_method.get,
|
|
||||||
_espe.api.full_path("/invitation/list"),
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @todo translation
|
|
||||||
*/
|
|
||||||
"description": () => "listet alle Einladung auf",
|
|
||||||
"output_schema": () => ({
|
|
||||||
"type": "object",
|
|
||||||
"nullable": false,
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "intiger",
|
|
||||||
"description": "ID"
|
|
||||||
},
|
|
||||||
"key": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "string",
|
|
||||||
"description": "Schlüssel"
|
|
||||||
},
|
|
||||||
"expiry": {
|
|
||||||
"nullable": true,
|
|
||||||
"type": "integer",
|
|
||||||
"description": "Ablauf"
|
|
||||||
},
|
|
||||||
"name_value": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "string",
|
|
||||||
"description": "Name"
|
|
||||||
},
|
|
||||||
"label_value": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "string",
|
|
||||||
"description": "Beschriftung"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"id",
|
|
||||||
"key",
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
"restriction": () => restriction_logged_in,
|
|
||||||
"execution": () => async ({}) => {
|
|
||||||
const data = await _espe.service.invitation.list();
|
|
||||||
return Promise.resolve({
|
|
||||||
"status_code": 200,
|
|
||||||
"data": data
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,158 +0,0 @@
|
||||||
/*
|
|
||||||
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
|
||||||
Copyright (C) 2024 Christian Fraß
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
|
||||||
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with this program. If not, see
|
|
||||||
<https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace _espe.api
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export function register_invitation_read(
|
|
||||||
rest_subject : lib_plankton.rest_http.type_rest
|
|
||||||
) : void
|
|
||||||
{
|
|
||||||
lib_plankton.rest_http.register<
|
|
||||||
int,
|
|
||||||
(
|
|
||||||
string
|
|
||||||
|
|
|
||||||
{
|
|
||||||
key : string;
|
|
||||||
expiry : (null | int);
|
|
||||||
name_changeable : boolean;
|
|
||||||
name_value : (null | string);
|
|
||||||
label_changeable : boolean;
|
|
||||||
label_value : (null | string);
|
|
||||||
email_address_changeable : boolean;
|
|
||||||
email_address_value : (null | string);
|
|
||||||
groups_changeable : boolean;
|
|
||||||
groups_value : (null | Array<int>);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
>(
|
|
||||||
rest_subject,
|
|
||||||
lib_plankton.http.enum_method.get,
|
|
||||||
_espe.api.full_path("/invitation/read"),
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @todo translation
|
|
||||||
*/
|
|
||||||
"description": () => "gibt die Daten einer Einladung anhand ihrer ID aus",
|
|
||||||
"query_parameters": () => [
|
|
||||||
{
|
|
||||||
"name": "id",
|
|
||||||
"required": true,
|
|
||||||
"description": "id",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"output_schema": () => ({
|
|
||||||
"type": "object",
|
|
||||||
"nullable": false,
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"expiry": {
|
|
||||||
"nullable": true,
|
|
||||||
"type": "integer",
|
|
||||||
"description": "Ablaufzeitpunkt"
|
|
||||||
},
|
|
||||||
"name_changeable": {
|
|
||||||
"type": "boolean",
|
|
||||||
"nullable": false,
|
|
||||||
"description": "Name | änderbar"
|
|
||||||
},
|
|
||||||
"name_value": {
|
|
||||||
"type": "string",
|
|
||||||
"nullable": true,
|
|
||||||
"description": "Name | Wert"
|
|
||||||
},
|
|
||||||
"label_changeable": {
|
|
||||||
"type": "boolean",
|
|
||||||
"nullable": false,
|
|
||||||
"description": "Beschriftung | änderbar"
|
|
||||||
},
|
|
||||||
"label_value": {
|
|
||||||
"type": "string",
|
|
||||||
"nullable": true,
|
|
||||||
"description": "Beschriftung | Wert"
|
|
||||||
},
|
|
||||||
"email_address_changeable": {
|
|
||||||
"type": "boolean",
|
|
||||||
"nullable": false,
|
|
||||||
"description": "E-Mail-Adresse | änderbar"
|
|
||||||
},
|
|
||||||
"email_address_value": {
|
|
||||||
"type": "string",
|
|
||||||
"nullable": true,
|
|
||||||
"description": "E-Mail-Adresse | Wert"
|
|
||||||
},
|
|
||||||
"groups_changeable": {
|
|
||||||
"type": "boolean",
|
|
||||||
"nullable": false,
|
|
||||||
"description": "Gruppen | änderbar"
|
|
||||||
},
|
|
||||||
"groups_value": {
|
|
||||||
"nullable": false,
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "integer",
|
|
||||||
"nullable": false,
|
|
||||||
},
|
|
||||||
"description": "Gruppen | Wert"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"expiry",
|
|
||||||
"name_changeable",
|
|
||||||
"name_value",
|
|
||||||
"email_address_changeable",
|
|
||||||
"email_address_value",
|
|
||||||
"groups_changeable",
|
|
||||||
"groups_value",
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
"restriction": () => restriction_logged_in,
|
|
||||||
"execution": () => ({"query_parameters": query_parameters, "input": input}) => {
|
|
||||||
const invitation_id : _espe.type.invitation_id = parseInt(query_parameters["id"]);
|
|
||||||
return (
|
|
||||||
_espe.service.invitation.get_by_id(invitation_id)
|
|
||||||
.then(
|
|
||||||
(invitation_object) => Promise.resolve({
|
|
||||||
"status_code": 200,
|
|
||||||
"data": {
|
|
||||||
"key": invitation_object.key,
|
|
||||||
"expiry": invitation_object.expiry,
|
|
||||||
"name_changeable": invitation_object.name_changeable,
|
|
||||||
"name_value": invitation_object.name_value,
|
|
||||||
"label_changeable": invitation_object.label_changeable,
|
|
||||||
"label_value": invitation_object.label_value,
|
|
||||||
"email_address_changeable": invitation_object.email_address_changeable,
|
|
||||||
"email_address_value": invitation_object.email_address_value,
|
|
||||||
"groups_changeable": invitation_object.groups_changeable,
|
|
||||||
"groups_value": invitation_object.groups_value,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.catch(
|
|
||||||
(error) => Promise.resolve({
|
|
||||||
"status_code": 404,
|
|
||||||
"data": "not found"
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -17,31 +17,23 @@ namespace _espe.api
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export function register_invitation_accept(
|
export function register_invite_accept(
|
||||||
rest_subject : lib_plankton.rest_http.type_rest
|
rest_subject : lib_plankton.rest_http.type_rest
|
||||||
) : void
|
) : void
|
||||||
{
|
{
|
||||||
lib_plankton.rest_http.register<
|
lib_plankton.rest_http.register<
|
||||||
{
|
{
|
||||||
key : string;
|
key : string;
|
||||||
data : {
|
membership_number_value : (null | string);
|
||||||
name : (null | string);
|
name_value : string;
|
||||||
label : (null | string);
|
email_address_value : (null | string);
|
||||||
groups : (null | Array<int>);
|
groups_value : Array<string>;
|
||||||
email_address : (null | string);
|
|
||||||
password : (null | string);
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
Array<
|
null
|
||||||
{
|
|
||||||
incident : string;
|
|
||||||
details : Record<string, any>;
|
|
||||||
}
|
|
||||||
>
|
|
||||||
>(
|
>(
|
||||||
rest_subject,
|
rest_subject,
|
||||||
lib_plankton.http.enum_method.post,
|
lib_plankton.http.enum_method.post,
|
||||||
_espe.api.full_path("/invitation/accept"),
|
_espe.api.full_path("/invite/accept"),
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @todo translation
|
* @todo translation
|
||||||
|
|
@ -61,28 +53,27 @@ namespace _espe.api
|
||||||
}),
|
}),
|
||||||
"restriction": () => restriction_none,
|
"restriction": () => restriction_none,
|
||||||
"execution": () => async ({"input": input}) => {
|
"execution": () => async ({"input": input}) => {
|
||||||
if (input === null)
|
if (input === null) {
|
||||||
{
|
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
"status_code": 400,
|
"status_code": 400,
|
||||||
"data": null
|
"data": null
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
try {
|
||||||
try
|
await _espe.service.invite.accept(
|
||||||
{
|
|
||||||
const flaws = await _espe.service.invitation.accept(
|
|
||||||
input.key,
|
input.key,
|
||||||
input.data
|
input.membership_number_value,
|
||||||
|
input.name_value,
|
||||||
|
input.email_address_value,
|
||||||
|
input.groups_value
|
||||||
);
|
);
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
"status_code": 200,
|
"status_code": 200,
|
||||||
"data": flaws
|
"data": null
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (error)
|
catch (error) {
|
||||||
{
|
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
"status_code": 404,
|
"status_code": 404,
|
||||||
"data": null
|
"data": null
|
||||||
196
source/api/actions/invite_create.ts
Normal file
196
source/api/actions/invite_create.ts
Normal file
|
|
@ -0,0 +1,196 @@
|
||||||
|
/*
|
||||||
|
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
||||||
|
Copyright (C) 2024 Christian Fraß
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||||
|
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with this program. If not, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace _espe.api
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export function register_invite_create(
|
||||||
|
rest_subject : lib_plankton.rest_http.type_rest
|
||||||
|
) : void
|
||||||
|
{
|
||||||
|
lib_plankton.rest_http.register<
|
||||||
|
{
|
||||||
|
membership_number_mode : int;
|
||||||
|
membership_number_value : (null | string);
|
||||||
|
name_mode : int;
|
||||||
|
name_value : string;
|
||||||
|
email_address_mode : int;
|
||||||
|
email_address_value : (null | string);
|
||||||
|
groups_mode : int;
|
||||||
|
groups_value : Array<string>;
|
||||||
|
expiry ?: (null | int);
|
||||||
|
// notification_target_url_template ?: (null | string);
|
||||||
|
},
|
||||||
|
(
|
||||||
|
string
|
||||||
|
|
|
||||||
|
{
|
||||||
|
id : _espe.type.member_id;
|
||||||
|
key : string;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
>(
|
||||||
|
rest_subject,
|
||||||
|
lib_plankton.http.enum_method.post,
|
||||||
|
_espe.api.full_path("/invite/create"),
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @todo translation
|
||||||
|
*/
|
||||||
|
"description": () => "erstellt eine Einladung und gibt die erzeugte ID und den erzeugten Schlüssel aus",
|
||||||
|
"input_schema": () => ({
|
||||||
|
"type": "object",
|
||||||
|
"nullable": false,
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"membership_number_mode": {
|
||||||
|
"type": "integer",
|
||||||
|
"nullable": false,
|
||||||
|
"description": "Mitgliedsnummer | Modus"
|
||||||
|
},
|
||||||
|
"membership_number_value": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "Mitgliedsnummer | Wert"
|
||||||
|
},
|
||||||
|
"name_mode": {
|
||||||
|
"type": "integer",
|
||||||
|
"nullable": false,
|
||||||
|
"description": "Name | Modus"
|
||||||
|
},
|
||||||
|
"name_value": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "Name | Wert"
|
||||||
|
},
|
||||||
|
"email_address_mode": {
|
||||||
|
"type": "integer",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "E-Mail-Adresse | Modus"
|
||||||
|
},
|
||||||
|
"email_address_value": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "E-Mail-Adresse | Wert"
|
||||||
|
},
|
||||||
|
"groups_integer": {
|
||||||
|
"type": "integer",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "Gruppen | Modus"
|
||||||
|
},
|
||||||
|
"groups_value": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": false,
|
||||||
|
},
|
||||||
|
"description": "Gruppen | Wert"
|
||||||
|
},
|
||||||
|
"expiry": {
|
||||||
|
"nullable": true,
|
||||||
|
"type": "intiger",
|
||||||
|
"description": "Ablaufzeitpunkt"
|
||||||
|
},
|
||||||
|
/*
|
||||||
|
"notification_target_url_template": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "Platz-Halter: id"
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"membership_number_mode",
|
||||||
|
"membership_number_value",
|
||||||
|
"name_mode",
|
||||||
|
"name_value",
|
||||||
|
"email_address_mode",
|
||||||
|
"email_address_value",
|
||||||
|
"groups_mode",
|
||||||
|
"groups_value",
|
||||||
|
"expiry",
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
"output_schema": () => ({
|
||||||
|
"type": "object",
|
||||||
|
"nullable": false,
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"nullable": false,
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"key",
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
"restriction": () => restriction_logged_in,
|
||||||
|
"execution": () => async ({"input": input}) => {
|
||||||
|
if (input === null) {
|
||||||
|
return Promise.reject(new Error("impossible"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (
|
||||||
|
(! _espe.conf.get().settings.misc.facultative_membership_number)
|
||||||
|
&&
|
||||||
|
(
|
||||||
|
(input.membership_number_value === null)
|
||||||
|
||
|
||||||
|
(input.membership_number_value === "")
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return Promise.resolve({
|
||||||
|
"status_code": 400,
|
||||||
|
"data": "membership number required"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const invite_info : {id : _espe.type.invite_id; key : _espe.type.invite_key;} = await _espe.service.invite.create(
|
||||||
|
{
|
||||||
|
"membership_number_mode": _espe.helpers.invite_prefill_mode_decode(input.membership_number_mode),
|
||||||
|
"membership_number_value": input.membership_number_value,
|
||||||
|
"name_mode": _espe.helpers.invite_prefill_mode_decode(input.name_mode),
|
||||||
|
"name_value": input.name_value,
|
||||||
|
"email_address_mode": _espe.helpers.invite_prefill_mode_decode(input.email_address_mode),
|
||||||
|
"email_address_value": input.email_address_value,
|
||||||
|
"groups_mode": _espe.helpers.invite_prefill_mode_decode(input.groups_mode),
|
||||||
|
"groups_value": input.groups_value,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expiry": input.expiry,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return Promise.resolve({
|
||||||
|
"status_code": 201,
|
||||||
|
"data": invite_info
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
165
source/api/actions/invite_examine.ts
Normal file
165
source/api/actions/invite_examine.ts
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
||||||
|
Copyright (C) 2024 Christian Fraß
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||||
|
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with this program. If not, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace _espe.api
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export function register_invite_examine(
|
||||||
|
rest_subject : lib_plankton.rest_http.type_rest
|
||||||
|
) : void
|
||||||
|
{
|
||||||
|
lib_plankton.rest_http.register<
|
||||||
|
string,
|
||||||
|
(
|
||||||
|
{
|
||||||
|
expiry : (null | int);
|
||||||
|
membership_number_mode : int;
|
||||||
|
membership_number_value : (null | string);
|
||||||
|
name_mode : int;
|
||||||
|
name_value : string;
|
||||||
|
email_address_mode : int;
|
||||||
|
email_address_value : (null | string);
|
||||||
|
groups_mode : int;
|
||||||
|
groups_value : Array<string>;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
null
|
||||||
|
|
|
||||||
|
string
|
||||||
|
)
|
||||||
|
>(
|
||||||
|
rest_subject,
|
||||||
|
lib_plankton.http.enum_method.get,
|
||||||
|
_espe.api.full_path("/invite/examine"),
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @todo translation
|
||||||
|
*/
|
||||||
|
"description": () => "gibt die Daten einer Einladung anhand ihres Schlüssels aus",
|
||||||
|
"input_schema": () => ({
|
||||||
|
"type": "string",
|
||||||
|
"nullable": false,
|
||||||
|
}),
|
||||||
|
"output_schema": () => ({
|
||||||
|
"type": "object",
|
||||||
|
"nullable": false,
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"expiry": {
|
||||||
|
"nullable": true,
|
||||||
|
"type": "intiger",
|
||||||
|
"description": "Ablaufzeitpunkt"
|
||||||
|
},
|
||||||
|
"membership_number_mode": {
|
||||||
|
"type": "integer",
|
||||||
|
"nullable": false,
|
||||||
|
"description": "Mitgliedsnummer | Modus"
|
||||||
|
},
|
||||||
|
"membership_number_value": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "Mitgliedsnummer | Wert"
|
||||||
|
},
|
||||||
|
"name_mode": {
|
||||||
|
"type": "integer",
|
||||||
|
"nullable": false,
|
||||||
|
"description": "Name | Modus"
|
||||||
|
},
|
||||||
|
"name_value": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "Name | Wert"
|
||||||
|
},
|
||||||
|
"email_address_mode": {
|
||||||
|
"type": "integer",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "E-Mail-Adresse | Modus"
|
||||||
|
},
|
||||||
|
"email_address_value": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "E-Mail-Adresse | Wert"
|
||||||
|
},
|
||||||
|
"groups_integer": {
|
||||||
|
"type": "integer",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "Gruppen | Modus"
|
||||||
|
},
|
||||||
|
"groups_value": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": false,
|
||||||
|
},
|
||||||
|
"description": "Gruppen | Wert"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"expiry",
|
||||||
|
"membership_number_mode",
|
||||||
|
"membership_number_value",
|
||||||
|
"name_mode",
|
||||||
|
"name_value",
|
||||||
|
"email_address_mode",
|
||||||
|
"email_address_value",
|
||||||
|
"groups_mode",
|
||||||
|
"groups_value",
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
"restriction": () => restriction_none,
|
||||||
|
"execution": () => ({"input": input}) => {
|
||||||
|
if (input === null) {
|
||||||
|
return Promise.resolve({"status_code": 500, "data": null});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const invite_key : _espe.type.invite_key = input;
|
||||||
|
return (
|
||||||
|
_espe.service.invite.examine(invite_key)
|
||||||
|
.then(
|
||||||
|
(invite_object) => Promise.resolve({
|
||||||
|
"status_code": 200,
|
||||||
|
"data": {
|
||||||
|
"expiry": invite_object.expiry,
|
||||||
|
"membership_number_mode": _espe.helpers.invite_prefill_mode_encode(invite_object.membership_number_mode),
|
||||||
|
"membership_number_value": invite_object.membership_number_value,
|
||||||
|
"name_mode": _espe.helpers.invite_prefill_mode_encode(invite_object.name_mode),
|
||||||
|
"name_value": invite_object.name_value,
|
||||||
|
"email_address_mode": _espe.helpers.invite_prefill_mode_encode(invite_object.email_address_mode),
|
||||||
|
"email_address_value": invite_object.email_address_value,
|
||||||
|
"groups_mode": _espe.helpers.invite_prefill_mode_encode(invite_object.groups_mode),
|
||||||
|
"groups_value": invite_object.groups_value,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.catch(
|
||||||
|
/**
|
||||||
|
* in order to give less information to potentiall attackers, we treat all fails as "not found"
|
||||||
|
*/
|
||||||
|
(error) => Promise.resolve({
|
||||||
|
"status_code": 404,
|
||||||
|
"data": "not found"
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
121
source/api/actions/member_info.ts
Normal file
121
source/api/actions/member_info.ts
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
||||||
|
Copyright (C) 2024 Christian Fraß
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||||
|
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with this program. If not, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace _espe.api
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo zeitliche Begrenzung?
|
||||||
|
*/
|
||||||
|
export function register_member_info(
|
||||||
|
rest_subject : lib_plankton.rest_http.type_rest
|
||||||
|
) : void
|
||||||
|
{
|
||||||
|
lib_plankton.rest_http.register<
|
||||||
|
int,
|
||||||
|
(
|
||||||
|
null
|
||||||
|
|
|
||||||
|
{
|
||||||
|
name_real_value : string;
|
||||||
|
name_real_index : int;
|
||||||
|
name_login : string;
|
||||||
|
email_address_veiled : (null | string);
|
||||||
|
email_address_nominal : string;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
>(
|
||||||
|
rest_subject,
|
||||||
|
lib_plankton.http.enum_method.get,
|
||||||
|
_espe.api.full_path("/member/info/:id"),
|
||||||
|
{
|
||||||
|
"description": () => "gibt Angaben über ein Mitglied aus, die für die Registrierung verwendet werden dürfen",
|
||||||
|
"input_schema": () => ({
|
||||||
|
"type": "number",
|
||||||
|
"nullable": false,
|
||||||
|
}),
|
||||||
|
"output_schema": () => ({
|
||||||
|
"type": "object",
|
||||||
|
"nullable": false,
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"name_real_value": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": false,
|
||||||
|
},
|
||||||
|
"name_real_index": {
|
||||||
|
"type": "number",
|
||||||
|
"nullable": false,
|
||||||
|
},
|
||||||
|
"name_login": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": false,
|
||||||
|
},
|
||||||
|
"email_address_veiled": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
},
|
||||||
|
"email_address_nominal": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"name_real_value",
|
||||||
|
"name_real_index",
|
||||||
|
"name_login",
|
||||||
|
"email_address_veiled",
|
||||||
|
"email_address_nominal",
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
"query_parameters": () => [
|
||||||
|
{
|
||||||
|
"name": "key",
|
||||||
|
"required": true,
|
||||||
|
"description": "Zugriffs-Schlüssel",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"restriction": () => restriction_verification(
|
||||||
|
stuff => parseInt(stuff.path_parameters["id"]),
|
||||||
|
stuff => stuff.query_parameters["key"]
|
||||||
|
),
|
||||||
|
"execution": () => async ({"path_parameters": path_parameters, "input": input}) => {
|
||||||
|
const member_id : _espe.type.member_id = parseInt(path_parameters["id"]);
|
||||||
|
const data : (
|
||||||
|
null
|
||||||
|
|
|
||||||
|
{
|
||||||
|
name_real_value : string;
|
||||||
|
name_real_index : int;
|
||||||
|
name_login : string;
|
||||||
|
email_address_veiled : (null | string);
|
||||||
|
email_address_nominal : string;
|
||||||
|
}
|
||||||
|
) = await _espe.service.member.info(member_id);
|
||||||
|
|
||||||
|
return Promise.resolve({
|
||||||
|
"status_code": (
|
||||||
|
(data === null)
|
||||||
|
? 409
|
||||||
|
: 200
|
||||||
|
),
|
||||||
|
"data": data
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -28,8 +28,9 @@ namespace _espe.api
|
||||||
{
|
{
|
||||||
id : int;
|
id : int;
|
||||||
preview : {
|
preview : {
|
||||||
name : string;
|
membership_number : string;
|
||||||
label : string;
|
name_real_value : string;
|
||||||
|
name_real_index : int;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
@ -61,18 +62,23 @@ namespace _espe.api
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"membership_number": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
},
|
},
|
||||||
"label": {
|
"name_real_value": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
},
|
},
|
||||||
|
"name_real_index": {
|
||||||
|
"type": "number",
|
||||||
|
"nullable": false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"name",
|
"membership_number",
|
||||||
"label",
|
"name_real_value",
|
||||||
|
"name_real_index",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,9 @@ namespace _espe.api
|
||||||
{
|
{
|
||||||
lib_plankton.rest_http.register<
|
lib_plankton.rest_http.register<
|
||||||
{
|
{
|
||||||
label : string;
|
email_address_private : (null | string);
|
||||||
email_address : (null | string);
|
groups ?: Array<string>;
|
||||||
groups ?: Array<int>;
|
registered : boolean;
|
||||||
enabled : boolean;
|
enabled : boolean;
|
||||||
},
|
},
|
||||||
null
|
null
|
||||||
|
|
@ -40,11 +40,7 @@ namespace _espe.api
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"label": {
|
"email_address_private": {
|
||||||
"nullable": true,
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"email_address": {
|
|
||||||
"nullable": true,
|
"nullable": true,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -56,6 +52,10 @@ namespace _espe.api
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"registered": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"enabled": {
|
"enabled": {
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
|
@ -63,7 +63,8 @@ namespace _espe.api
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": [
|
"required": [
|
||||||
"email_address",
|
"email_address_private",
|
||||||
|
"registered",
|
||||||
"enabled",
|
"enabled",
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
|
|
@ -80,13 +81,13 @@ namespace _espe.api
|
||||||
await _espe.service.member.modify(
|
await _espe.service.member.modify(
|
||||||
member_id,
|
member_id,
|
||||||
{
|
{
|
||||||
"label": input.label,
|
"email_address_private": input.email_address_private,
|
||||||
"email_address": input.email_address,
|
|
||||||
"groups": (
|
"groups": (
|
||||||
(input.groups === undefined)
|
(input.groups === undefined)
|
||||||
? lib_plankton.pod.make_empty<Array<_espe.type.group_id>>()
|
? lib_plankton.pod.make_empty<Array<string>>()
|
||||||
: lib_plankton.pod.make_filled<Array<_espe.type.group_id>>(input.groups)
|
: lib_plankton.pod.make_filled<Array<string>>(input.groups)
|
||||||
),
|
),
|
||||||
|
"registered": input.registered,
|
||||||
"enabled": input.enabled,
|
"enabled": input.enabled,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -62,22 +62,15 @@ namespace _espe.api
|
||||||
}),
|
}),
|
||||||
"restriction": () => restriction_none,
|
"restriction": () => restriction_none,
|
||||||
"execution": () => async ({"input": input}) => {
|
"execution": () => async ({"input": input}) => {
|
||||||
if (input === null)
|
if (input === null) {
|
||||||
{
|
|
||||||
return Promise.reject(new Error("impossible"));
|
return Promise.reject(new Error("impossible"));
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
await _espe.service.member.password_change_initialize(input.identifier, input.url_template);
|
||||||
await _espe.service.member.password_change_initialize(
|
return Promise.resolve({
|
||||||
input.identifier,
|
|
||||||
input.url_template
|
|
||||||
);
|
|
||||||
return Promise.resolve(
|
|
||||||
{
|
|
||||||
"status_code": 200,
|
"status_code": 200,
|
||||||
"data": null
|
"data": null
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
153
source/api/actions/member_project.ts
Normal file
153
source/api/actions/member_project.ts
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
/*
|
||||||
|
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
||||||
|
Copyright (C) 2024 Christian Fraß
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||||
|
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with this program. If not, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace _espe.api
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export function register_member_project(
|
||||||
|
rest_subject : lib_plankton.rest_http.type_rest
|
||||||
|
) : void
|
||||||
|
{
|
||||||
|
lib_plankton.rest_http.register<
|
||||||
|
{
|
||||||
|
membership_number : (null | string);
|
||||||
|
name_real_value : string;
|
||||||
|
email_address_private : (null | string);
|
||||||
|
groups ?: Array<string>;
|
||||||
|
notification_target_url_template ?: (null | string);
|
||||||
|
},
|
||||||
|
(
|
||||||
|
string
|
||||||
|
|
|
||||||
|
_espe.type.member_id
|
||||||
|
)
|
||||||
|
>(
|
||||||
|
rest_subject,
|
||||||
|
lib_plankton.http.enum_method.post,
|
||||||
|
_espe.api.full_path("/member/project"),
|
||||||
|
{
|
||||||
|
"description": () => "erstellt ein neues Mitglied und gibt die erzeugte ID aus",
|
||||||
|
"input_schema": () => ({
|
||||||
|
"type": "object",
|
||||||
|
"nullable": false,
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"membership_number": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": false,
|
||||||
|
"description": "Mitgliedsnummer"
|
||||||
|
},
|
||||||
|
"name_real_value": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": false,
|
||||||
|
"description": "Klarname"
|
||||||
|
},
|
||||||
|
"email_address_private": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "private E-Mail-Adresse"
|
||||||
|
},
|
||||||
|
"groups": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification_target_url_template": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "Platz-Halter: id"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"membership_number",
|
||||||
|
"name_real_value",
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
"output_schema": () => ({
|
||||||
|
"type": "number",
|
||||||
|
"nullable": false,
|
||||||
|
}),
|
||||||
|
"restriction": () => restriction_logged_in,
|
||||||
|
"execution": () => async ({"input": input}) => {
|
||||||
|
if (input === null) {
|
||||||
|
return Promise.reject(new Error("impossible"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (
|
||||||
|
(! _espe.conf.get().settings.misc.facultative_membership_number)
|
||||||
|
&&
|
||||||
|
(
|
||||||
|
(input.membership_number === null)
|
||||||
|
||
|
||||||
|
(input.membership_number === "")
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return Promise.resolve({
|
||||||
|
"status_code": 400,
|
||||||
|
"data": "membership number required"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const member_id : _espe.type.member_id = await _espe.service.member.project(
|
||||||
|
{
|
||||||
|
"membership_number": input.membership_number,
|
||||||
|
"name_real_value": input.name_real_value,
|
||||||
|
"email_address_private": (
|
||||||
|
("email_address_private" in input)
|
||||||
|
? (
|
||||||
|
(input.email_address_private !== "")
|
||||||
|
? input.email_address_private
|
||||||
|
: null
|
||||||
|
)
|
||||||
|
: null
|
||||||
|
),
|
||||||
|
"groups": (input.groups ?? []),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"notification_target_url_template": input.notification_target_url_template,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Promise.resolve({
|
||||||
|
"status_code": 201,
|
||||||
|
"data": member_id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -25,12 +25,21 @@ namespace _espe.api
|
||||||
lib_plankton.rest_http.register<
|
lib_plankton.rest_http.register<
|
||||||
null,
|
null,
|
||||||
{
|
{
|
||||||
name : string;
|
membership_number : (null | string);
|
||||||
label : string;
|
name_real_value : string;
|
||||||
email_address : (null | string);
|
name_real_index : int;
|
||||||
groups : Array<int>;
|
email_address_private : (null | string);
|
||||||
|
groups : Array<string>;
|
||||||
|
registered : boolean;
|
||||||
enabled : boolean;
|
enabled : boolean;
|
||||||
|
email_use_veiled_address : boolean;
|
||||||
|
email_use_nominal_address : boolean;
|
||||||
|
email_redirect_to_private_address : boolean;
|
||||||
|
email_allow_sending : boolean;
|
||||||
password_set : boolean;
|
password_set : boolean;
|
||||||
|
email_address_veiled : (null | string);
|
||||||
|
email_address_nominal : string;
|
||||||
|
name_login : string;
|
||||||
}
|
}
|
||||||
>(
|
>(
|
||||||
rest_subject,
|
rest_subject,
|
||||||
|
|
@ -42,15 +51,19 @@ namespace _espe.api
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"membership_number": {
|
||||||
|
"nullable": true,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name_real_value": {
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"label": {
|
"name_real_index": {
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"type": "string"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"email_address": {
|
"email_address_private": {
|
||||||
"nullable": true,
|
"nullable": true,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -59,22 +72,67 @@ namespace _espe.api
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"type": "int"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"registered": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"enabled": {
|
"enabled": {
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"email_use_veiled_address": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"email_use_nominal_address": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"email_redirect_to_private_address": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"email_allow_sending": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"password_set": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"email_address_veiled": {
|
||||||
|
"nullable": true,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"email_address_nominal": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name_login": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": [
|
"required": [
|
||||||
"name",
|
"membership_number",
|
||||||
"label",
|
"name_real_value",
|
||||||
"email_address",
|
"name_real_index",
|
||||||
|
"email_address_private",
|
||||||
"groups",
|
"groups",
|
||||||
|
"registered",
|
||||||
"enabled",
|
"enabled",
|
||||||
|
"email_use_veiled_address",
|
||||||
|
"email_use_nominal_address",
|
||||||
|
"email_redirect_to_private_address",
|
||||||
|
"email_allow_sending",
|
||||||
"password_set",
|
"password_set",
|
||||||
|
"email_address_veiled",
|
||||||
|
"email_address_nominal",
|
||||||
|
"name_login",
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
"restriction": () => restriction_logged_in,
|
"restriction": () => restriction_logged_in,
|
||||||
|
|
@ -84,12 +142,21 @@ namespace _espe.api
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
"status_code": 200,
|
"status_code": 200,
|
||||||
"data": {
|
"data": {
|
||||||
"name": member_object.name,
|
"membership_number": member_object.membership_number,
|
||||||
"label": member_object.label,
|
"name_real_value": member_object.name_real_value,
|
||||||
"email_address": member_object.email_address,
|
"name_real_index": member_object.name_real_index,
|
||||||
|
"email_address_private": member_object.email_address_private,
|
||||||
"groups": member_object.groups,
|
"groups": member_object.groups,
|
||||||
|
"registered": member_object.registered,
|
||||||
"enabled": member_object.enabled,
|
"enabled": member_object.enabled,
|
||||||
|
"email_use_veiled_address": member_object.email_use_veiled_address,
|
||||||
|
"email_use_nominal_address": member_object.email_use_nominal_address,
|
||||||
|
"email_redirect_to_private_address": member_object.email_redirect_to_private_address,
|
||||||
|
"email_allow_sending": member_object.email_allow_sending,
|
||||||
"password_set": (member_object.password_image !== null),
|
"password_set": (member_object.password_image !== null),
|
||||||
|
"name_login": _espe.service.member.name_login(member_object),
|
||||||
|
"email_address_veiled": _espe.service.member.email_address_veiled(member_object),
|
||||||
|
"email_address_nominal": _espe.service.member.email_address_nominal(member_object),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
159
source/api/actions/member_register.ts
Normal file
159
source/api/actions/member_register.ts
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
/*
|
||||||
|
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
||||||
|
Copyright (C) 2024 Christian Fraß
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||||
|
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with this program. If not, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace _espe.api
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo zeitliche Begrenzung?
|
||||||
|
*/
|
||||||
|
export function register_member_register(
|
||||||
|
rest_subject : lib_plankton.rest_http.type_rest
|
||||||
|
) : void
|
||||||
|
{
|
||||||
|
lib_plankton.rest_http.register<
|
||||||
|
{
|
||||||
|
email_use_veiled_address : boolean;
|
||||||
|
email_use_nominal_address : boolean;
|
||||||
|
email_redirect_to_private_address : boolean;
|
||||||
|
password : (null | string);
|
||||||
|
notification_target_url_template ?: (null | string);
|
||||||
|
},
|
||||||
|
Array<
|
||||||
|
{
|
||||||
|
incident : string;
|
||||||
|
details : Record<string, any>;
|
||||||
|
}
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
rest_subject,
|
||||||
|
lib_plankton.http.enum_method.post,
|
||||||
|
_espe.api.full_path("/member/register/:id"),
|
||||||
|
{
|
||||||
|
"description": () => "nimmt zusätzliche Angaben eines Mitglieds entgegen",
|
||||||
|
"input_schema": () => ({
|
||||||
|
"type": "object",
|
||||||
|
"nullable": false,
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"email_use_veiled_address": {
|
||||||
|
"type": "boolean",
|
||||||
|
"nullable": false,
|
||||||
|
"description": "ob die nummern-basierte E-Mail-Adresse eingerichtet werden soll",
|
||||||
|
},
|
||||||
|
"email_use_nominal_address": {
|
||||||
|
"type": "boolean",
|
||||||
|
"nullable": false,
|
||||||
|
"description": "ob die namens-basierte E-Mail-Adresse eingerichtet werden soll",
|
||||||
|
},
|
||||||
|
"email_redirect_to_private_address": {
|
||||||
|
"type": "boolean",
|
||||||
|
"nullable": false,
|
||||||
|
"description": "ob auf die Partei-Adressen eingehende E-Mails zur privaten Adresse weitergeleitet werden sollen",
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "Passwort für alle Netz-Dienste",
|
||||||
|
},
|
||||||
|
"notification_target_url_template": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "Platz-Halter: id"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"email_use_veiled_address",
|
||||||
|
"email_use_nominal_address",
|
||||||
|
"email_redirect_to_private_address",
|
||||||
|
"password",
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
"output_schema": () => ({
|
||||||
|
"nullable": false,
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"incident": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"details": {
|
||||||
|
"nullable": false,
|
||||||
|
"type": "object",
|
||||||
|
"properties": {},
|
||||||
|
"additionalProperties": {
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"required": []
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"incident",
|
||||||
|
"details",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
"query_parameters": () => [
|
||||||
|
{
|
||||||
|
"name": "key",
|
||||||
|
"required": true,
|
||||||
|
"description": "Zugriffs-Schlüssel",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"restriction": () => restriction_verification(
|
||||||
|
stuff => parseInt(stuff.path_parameters["id"]),
|
||||||
|
stuff => stuff.query_parameters["key"]
|
||||||
|
),
|
||||||
|
"execution": () => ({"path_parameters": path_parameters, "input": input}) => {
|
||||||
|
if (input === null) {
|
||||||
|
return Promise.reject(new Error("impossible"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const member_id : _espe.type.member_id = parseInt(path_parameters["id"]);
|
||||||
|
return (
|
||||||
|
_espe.service.member.register(
|
||||||
|
member_id,
|
||||||
|
{
|
||||||
|
"email_use_veiled_address": input.email_use_veiled_address,
|
||||||
|
"email_use_nominal_address": input.email_use_nominal_address,
|
||||||
|
"email_redirect_to_private_address": input.email_redirect_to_private_address,
|
||||||
|
"password": input.password,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"notification_target_url_template": (input.notification_target_url_template ?? null),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(
|
||||||
|
flaws => Promise.resolve({
|
||||||
|
"status_code": (
|
||||||
|
(flaws.length <= 0)
|
||||||
|
? 200
|
||||||
|
: 409
|
||||||
|
),
|
||||||
|
"data": flaws
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -18,46 +18,44 @@ namespace _espe.api
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export function register_invitation_delete(
|
export function register_member_summon(
|
||||||
rest_subject : lib_plankton.rest_http.type_rest
|
rest_subject : lib_plankton.rest_http.type_rest
|
||||||
) : void
|
) : void
|
||||||
{
|
{
|
||||||
lib_plankton.rest_http.register<
|
lib_plankton.rest_http.register<
|
||||||
int,
|
{
|
||||||
|
url_template : string;
|
||||||
|
},
|
||||||
|
(
|
||||||
null
|
null
|
||||||
|
|
|
||||||
|
string
|
||||||
|
)
|
||||||
>(
|
>(
|
||||||
rest_subject,
|
rest_subject,
|
||||||
lib_plankton.http.enum_method.delete,
|
lib_plankton.http.enum_method.post,
|
||||||
_espe.api.full_path("/invitation/delete"),
|
_espe.conf.get().server.path_base + "/member/summon/:id",
|
||||||
{
|
{
|
||||||
/**
|
"description": () => "sendet an ein Mitglied eine E-Mail mit Aufforderung zur Registrierung",
|
||||||
* @todo translation
|
|
||||||
*/
|
|
||||||
"description": () => "löscht eine Einladung",
|
|
||||||
"input_schema": () => ({
|
|
||||||
"nullable": false,
|
|
||||||
"type": "integer",
|
|
||||||
}),
|
|
||||||
"output_schema": () => ({
|
|
||||||
"nullable": true,
|
|
||||||
}),
|
|
||||||
"restriction": () => restriction_logged_in,
|
"restriction": () => restriction_logged_in,
|
||||||
"execution": () => async (stuff) => {
|
"execution": () => async ({"path_parameters": path_parameters, "input": input}) => {
|
||||||
if (stuff.input === null)
|
if (input === null) {
|
||||||
{
|
|
||||||
return Promise.reject(new Error("impossible"));
|
return Promise.reject(new Error("impossible"));
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
const member_id : _espe.type.member_id = parseInt(path_parameters["id"]);
|
||||||
const invitation_id : _espe.type.invitation_id = stuff.input;
|
const url : (null | string) = await _espe.service.member.summon(member_id, input.url_template);
|
||||||
await _espe.service.invitation.remove(
|
|
||||||
invitation_id
|
return (
|
||||||
);
|
(url === null)
|
||||||
return Promise.resolve(
|
? Promise.resolve({
|
||||||
{
|
"status_code": 409,
|
||||||
|
"data": null,
|
||||||
|
})
|
||||||
|
: Promise.resolve({
|
||||||
"status_code": 200,
|
"status_code": 200,
|
||||||
"data": null
|
"data": url,
|
||||||
}
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -66,4 +64,3 @@ namespace _espe.api
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,7 +35,7 @@ namespace _espe.api
|
||||||
>(
|
>(
|
||||||
rest_subject,
|
rest_subject,
|
||||||
lib_plankton.http.enum_method.post,
|
lib_plankton.http.enum_method.post,
|
||||||
_espe.api.full_path("/session/begin"),
|
_espe.conf.get().server.path_base + "/session/begin",
|
||||||
{
|
{
|
||||||
"description": () => "führt die Anmeldung am System aus um geschützte Aktionen nutzen zu können",
|
"description": () => "führt die Anmeldung am System aus um geschützte Aktionen nutzen zu können",
|
||||||
"input_schema": () => ({
|
"input_schema": () => ({
|
||||||
|
|
|
||||||
|
|
@ -43,15 +43,12 @@ namespace _espe.api
|
||||||
_espe.api.register_session_begin(rest_subject);
|
_espe.api.register_session_begin(rest_subject);
|
||||||
_espe.api.register_session_end(rest_subject);
|
_espe.api.register_session_end(rest_subject);
|
||||||
}
|
}
|
||||||
// group
|
|
||||||
{
|
|
||||||
_espe.api.register_group_list(rest_subject);
|
|
||||||
_espe.api.register_group_read(rest_subject);
|
|
||||||
_espe.api.register_group_add(rest_subject);
|
|
||||||
_espe.api.register_group_modify(rest_subject);
|
|
||||||
}
|
|
||||||
// member
|
// member
|
||||||
{
|
{
|
||||||
|
_espe.api.register_member_project(rest_subject);
|
||||||
|
_espe.api.register_member_summon(rest_subject);
|
||||||
|
_espe.api.register_member_info(rest_subject);
|
||||||
|
_espe.api.register_member_register(rest_subject);
|
||||||
_espe.api.register_member_list(rest_subject);
|
_espe.api.register_member_list(rest_subject);
|
||||||
_espe.api.register_member_read(rest_subject);
|
_espe.api.register_member_read(rest_subject);
|
||||||
_espe.api.register_member_modify(rest_subject);
|
_espe.api.register_member_modify(rest_subject);
|
||||||
|
|
@ -62,14 +59,11 @@ namespace _espe.api
|
||||||
_espe.api.register_member_password_change_execute(rest_subject);
|
_espe.api.register_member_password_change_execute(rest_subject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// invitation
|
// invite
|
||||||
{
|
{
|
||||||
_espe.api.register_invitation_list(rest_subject);
|
_espe.api.register_invite_create(rest_subject);
|
||||||
_espe.api.register_invitation_read(rest_subject);
|
_espe.api.register_invite_examine(rest_subject);
|
||||||
_espe.api.register_invitation_create(rest_subject);
|
_espe.api.register_invite_accept(rest_subject);
|
||||||
_espe.api.register_invitation_delete(rest_subject);
|
|
||||||
_espe.api.register_invitation_examine(rest_subject);
|
|
||||||
_espe.api.register_invitation_accept(rest_subject);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rest_subject;
|
return rest_subject;
|
||||||
|
|
|
||||||
124
source/conf.ts
124
source/conf.ts
|
|
@ -149,6 +149,14 @@ namespace _espe.conf
|
||||||
name : string;
|
name : string;
|
||||||
domain : string;
|
domain : string;
|
||||||
};
|
};
|
||||||
|
misc : {
|
||||||
|
prefix_for_veiled_email_addresses : string;
|
||||||
|
facultative_membership_number : boolean;
|
||||||
|
auto_register : boolean;
|
||||||
|
};
|
||||||
|
summon_email : {
|
||||||
|
remark : string;
|
||||||
|
};
|
||||||
password_policy : {
|
password_policy : {
|
||||||
minimum_length : (null | int);
|
minimum_length : (null | int);
|
||||||
maximum_length : (null | int);
|
maximum_length : (null | int);
|
||||||
|
|
@ -159,10 +167,12 @@ namespace _espe.conf
|
||||||
password_change : {
|
password_change : {
|
||||||
cooldown_time : int;
|
cooldown_time : int;
|
||||||
};
|
};
|
||||||
|
name_index : {
|
||||||
|
veil : boolean;
|
||||||
|
salt : (null | string);
|
||||||
|
};
|
||||||
connections : {
|
connections : {
|
||||||
frontend_url_base : (null | string);
|
frontend_url_base : (null | string);
|
||||||
frontend_path_template_invitation_handle : (null | string);
|
|
||||||
frontend_path_template_password_change : (null | string);
|
|
||||||
login_url : (null | string);
|
login_url : (null | string);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -210,7 +220,7 @@ namespace _espe.conf
|
||||||
conf_raw : any
|
conf_raw : any
|
||||||
) : void
|
) : void
|
||||||
{
|
{
|
||||||
const version : int = (conf_raw["version"] ?? 6);
|
const version : int = (conf_raw["version"] ?? 5);
|
||||||
_data = {
|
_data = {
|
||||||
"general": (
|
"general": (
|
||||||
((node_general) => ({
|
((node_general) => ({
|
||||||
|
|
@ -221,8 +231,7 @@ namespace _espe.conf
|
||||||
"log": (
|
"log": (
|
||||||
(() => {
|
(() => {
|
||||||
switch (version) {
|
switch (version) {
|
||||||
case 1:
|
case 1: {
|
||||||
{
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
"kind": "stdout",
|
"kind": "stdout",
|
||||||
|
|
@ -236,9 +245,7 @@ namespace _espe.conf
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
case 3:
|
||||||
case 4:
|
case 4:
|
||||||
case 5:
|
case 5: {
|
||||||
case 6:
|
|
||||||
{
|
|
||||||
const node_log = (
|
const node_log = (
|
||||||
conf_raw["log"]
|
conf_raw["log"]
|
||||||
??
|
??
|
||||||
|
|
@ -275,15 +282,12 @@ namespace _espe.conf
|
||||||
switch (version) {
|
switch (version) {
|
||||||
case 1:
|
case 1:
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
case 3: {
|
||||||
{
|
|
||||||
return "::";
|
return "::";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 4:
|
case 4:
|
||||||
case 5:
|
case 5: {
|
||||||
case 6:
|
|
||||||
{
|
|
||||||
return (node_server["host"] ?? "::");
|
return (node_server["host"] ?? "::");
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -298,8 +302,7 @@ namespace _espe.conf
|
||||||
const kind : string = (node_database["kind"] ?? "sqlite");
|
const kind : string = (node_database["kind"] ?? "sqlite");
|
||||||
const node_database_data_raw = (node_database["data"] ?? {});
|
const node_database_data_raw = (node_database["data"] ?? {});
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case "sqlite":
|
case "sqlite": {
|
||||||
{
|
|
||||||
return {
|
return {
|
||||||
"kind": kind,
|
"kind": kind,
|
||||||
"data": {
|
"data": {
|
||||||
|
|
@ -308,16 +311,14 @@ namespace _espe.conf
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "postgresql":
|
case "postgresql": {
|
||||||
{
|
|
||||||
return {
|
return {
|
||||||
"kind": kind,
|
"kind": kind,
|
||||||
"data": node_database_data_raw,
|
"data": node_database_data_raw,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
{
|
|
||||||
throw (new Error("unhandled"));
|
throw (new Error("unhandled"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -329,8 +330,7 @@ namespace _espe.conf
|
||||||
const kind : string = (node_email_sending["kind"] ?? "console");
|
const kind : string = (node_email_sending["kind"] ?? "console");
|
||||||
const data_raw = (node_email_sending["data"] ?? {});
|
const data_raw = (node_email_sending["data"] ?? {});
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case "regular":
|
case "regular": {
|
||||||
{
|
|
||||||
return {
|
return {
|
||||||
"kind": kind,
|
"kind": kind,
|
||||||
"data": {
|
"data": {
|
||||||
|
|
@ -340,8 +340,7 @@ namespace _espe.conf
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "redirect":
|
case "redirect": {
|
||||||
{
|
|
||||||
return {
|
return {
|
||||||
"kind": kind,
|
"kind": kind,
|
||||||
"data": {
|
"data": {
|
||||||
|
|
@ -352,8 +351,7 @@ namespace _espe.conf
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "console":
|
case "console": {
|
||||||
{
|
|
||||||
return {
|
return {
|
||||||
"kind": kind,
|
"kind": kind,
|
||||||
"data": {
|
"data": {
|
||||||
|
|
@ -361,8 +359,7 @@ namespace _espe.conf
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "drop":
|
case "drop": {
|
||||||
{
|
|
||||||
return {
|
return {
|
||||||
"kind": kind,
|
"kind": kind,
|
||||||
"data": {
|
"data": {
|
||||||
|
|
@ -370,8 +367,7 @@ namespace _espe.conf
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
{
|
|
||||||
throw (new Error("unhandled"));
|
throw (new Error("unhandled"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -391,6 +387,18 @@ namespace _espe.conf
|
||||||
"name": ((node_settings["organisation"] ?? {})["name"] ?? "Example Orginsation"), // TODO: mandatory?
|
"name": ((node_settings["organisation"] ?? {})["name"] ?? "Example Orginsation"), // TODO: mandatory?
|
||||||
"domain": ((node_settings["organisation"] ?? {})["domain"] ?? "example.org"), // 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": (
|
"password_policy": (
|
||||||
((node_settings_password_policy) => ({
|
((node_settings_password_policy) => ({
|
||||||
"minimum_length": (
|
"minimum_length": (
|
||||||
|
|
@ -404,8 +412,8 @@ namespace _espe.conf
|
||||||
: 240
|
: 240
|
||||||
),
|
),
|
||||||
"must_contain_letter": (node_settings_password_policy["must_contain_letter"] ?? true),
|
"must_contain_letter": (node_settings_password_policy["must_contain_letter"] ?? true),
|
||||||
"must_contain_number": (node_settings_password_policy["must_contain_number"] ?? false),
|
"must_contain_number": (node_settings_password_policy["must_contain_number"] ?? true),
|
||||||
"must_contain_special_character": (node_settings_password_policy["must_contain_special_character"] ?? false),
|
"must_contain_special_character": (node_settings_password_policy["must_contain_special_character"] ?? true),
|
||||||
})) (node_settings["password_policy"] ?? {})
|
})) (node_settings["password_policy"] ?? {})
|
||||||
),
|
),
|
||||||
"password_change": (
|
"password_change": (
|
||||||
|
|
@ -413,47 +421,15 @@ namespace _espe.conf
|
||||||
"cooldown_time": (node_settings_password_change["cooldown_time"] ?? 86400),
|
"cooldown_time": (node_settings_password_change["cooldown_time"] ?? 86400),
|
||||||
})) (node_settings["password_change"] ?? {})
|
})) (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": (
|
"connections": (
|
||||||
((node_settings_connections) => ({
|
((node_settings_connections) => ({
|
||||||
"frontend_url_base": (node_settings_connections["frontend_url_base"] ?? null),
|
"frontend_url_base": (node_settings_connections["frontend_url_base"] ?? null),
|
||||||
"frontend_path_template_password_change": (() => {
|
|
||||||
switch (version)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
case 5:
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 6:
|
|
||||||
{
|
|
||||||
return (node_settings_connections["frontend_path_template_password_change"] ?? null);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}) (),
|
|
||||||
"frontend_path_template_invitation_handle": (() => {
|
|
||||||
switch (version)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
case 5:
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 6:
|
|
||||||
{
|
|
||||||
return (node_settings_connections["frontend_path_template_invitation_handle"] ?? null);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}) (),
|
|
||||||
"login_url": (node_settings_connections["login_url"] ?? null),
|
"login_url": (node_settings_connections["login_url"] ?? null),
|
||||||
})) (node_settings["connections"] ?? {})
|
})) (node_settings["connections"] ?? {})
|
||||||
),
|
),
|
||||||
|
|
@ -462,8 +438,7 @@ namespace _espe.conf
|
||||||
"outputs": (() => {
|
"outputs": (() => {
|
||||||
switch (version) {
|
switch (version) {
|
||||||
case 1:
|
case 1:
|
||||||
case 2:
|
case 2: {
|
||||||
{
|
|
||||||
const node_output = (conf_raw["output"] ?? {});
|
const node_output = (conf_raw["output"] ?? {});
|
||||||
return (
|
return (
|
||||||
("authelia" in node_output)
|
("authelia" in node_output)
|
||||||
|
|
@ -482,15 +457,12 @@ namespace _espe.conf
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 3:
|
case 3: {
|
||||||
{
|
|
||||||
return (conf_raw["outputs"] ?? []);
|
return (conf_raw["outputs"] ?? []);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 4:
|
case 4:
|
||||||
case 5:
|
case 5: {
|
||||||
case 6:
|
|
||||||
{
|
|
||||||
const node_outputs = (conf_raw["outputs"] ?? []);
|
const node_outputs = (conf_raw["outputs"] ?? []);
|
||||||
return node_outputs.map(
|
return node_outputs.map(
|
||||||
(output_description : {kind : string; data : any;}) => {
|
(output_description : {kind : string; data : any;}) => {
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,10 @@
|
||||||
"identifier": "deu"
|
"identifier": "deu"
|
||||||
},
|
},
|
||||||
"tree": {
|
"tree": {
|
||||||
|
"email.summon.subject": "Registrierung",
|
||||||
|
"email.summon.body": "Hi, {{name}}\n\n{{remark}}\n\nWenn du die Dienste nutzen möchtest, rufe bitte folgende Adresse auf:\n\n{{url}}",
|
||||||
"email.registration.subject": "Registrierung erfolgt",
|
"email.registration.subject": "Registrierung erfolgt",
|
||||||
"email.registration.body": "'{{name}}' ('{{label}}') wurde soeben registriert",
|
"email.registration.body": "Das Mitglied '{{name_display}}' hat sich soeben registriert:\n\n{{url}}",
|
||||||
"email.activation.subject": "Freischaltung erfolgt",
|
"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}}\n{{password_info}}",
|
"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.activation.password_info": "Passwort: {{password}}\n\nBitte ändere dein Passwort zeitnah!",
|
||||||
|
|
@ -12,12 +14,9 @@
|
||||||
"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.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",
|
"email.password_change.execution.subject": "Passwort-Änderung abgeschlossen",
|
||||||
"email.password_change.execution.body": "Hi, {{name}}\n\nDein Passwort wurde soeben geändert.\n",
|
"email.password_change.execution.body": "Hi, {{name}}\n\nDein Passwort wurde soeben geändert.\n",
|
||||||
"email.invitation.subject": "Einladung",
|
|
||||||
"email.invitation.body": "Du wurdest zu {{organisation}} eingeladen. Um beizutreten, rufe bitte folgende Adresse auf:\n\n{{url}}",
|
|
||||||
"help.args.action.description": "auszuführende Aktion; Auswahl",
|
"help.args.action.description": "auszuführende Aktion; Auswahl",
|
||||||
"help.args.action.options.serve": "Server starten",
|
"help.args.action.options.serve": "Server starten",
|
||||||
"help.args.action.options.api_doc": "API-Dokumentation gemäß OpenAPI-Spezifikation auf Standard-Ausgabe schreiben",
|
"help.args.action.options.api_doc": "API-Dokumentation gemäß OpenAPI-Spezifikation auf Standard-Ausgabe schreiben",
|
||||||
"help.args.action.options.sample": "Datenbank mit Beispiel-Daten befüllen",
|
|
||||||
"help.args.action.options.email_test": "eine Test-E-Mail senden",
|
"help.args.action.options.email_test": "eine Test-E-Mail senden",
|
||||||
"help.args.action.options.expose_conf": "Vollständige Konfiguration ausgeben",
|
"help.args.action.options.expose_conf": "Vollständige Konfiguration ausgeben",
|
||||||
"help.args.action.options.password_image": "Passwort-Abbild errechnen und auf Standard-Ausgabe schreiben",
|
"help.args.action.options.password_image": "Passwort-Abbild errechnen und auf Standard-Ausgabe schreiben",
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,10 @@
|
||||||
"identifier": "eng"
|
"identifier": "eng"
|
||||||
},
|
},
|
||||||
"tree": {
|
"tree": {
|
||||||
|
"email.summon.subject": "Registration",
|
||||||
|
"email.summon.body": "Hi, {{name}}\n\n{{remark}}\n\nIn case you want to use online service, open the following link:\n\n{{url}}",
|
||||||
"email.registration.subject": "Registration received",
|
"email.registration.subject": "Registration received",
|
||||||
"email.registration.body": "'{{name}}' ('{{label}}') just has been registered",
|
"email.registration.body": "The member '{{name_display}}' just registered:\n\n{{url}}",
|
||||||
"email.activation.subject": "Activated",
|
"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.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\nPlease change your password soon!",
|
"email.activation.password_info": "Password: {{password}}\n\nPlease change your password soon!",
|
||||||
|
|
@ -12,12 +14,9 @@
|
||||||
"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.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",
|
"email.password_change.execution.subject": "Password change concluded",
|
||||||
"email.password_change.execution.body": "Hi, {{name}}\n\nYour password has just been changed.\n",
|
"email.password_change.execution.body": "Hi, {{name}}\n\nYour password has just been changed.\n",
|
||||||
"email.invitation.subject": "invitation",
|
|
||||||
"email.invitation.body": "You have been invited to {{organisation}}. In order to join, please open the following address:\n\n{{url}}",
|
|
||||||
"help.args.action.description": "action to executo; options",
|
"help.args.action.description": "action to executo; options",
|
||||||
"help.args.action.options.serve": "start server",
|
"help.args.action.options.serve": "start server",
|
||||||
"help.args.action.options.api_doc": "write API documentation according to OpenAPI specification to stdout",
|
"help.args.action.options.api_doc": "write API documentation according to OpenAPI specification to stdout",
|
||||||
"help.args.action.options.sample": "fill database with sample data",
|
|
||||||
"help.args.action.options.email_test": "send a test e-mail",
|
"help.args.action.options.email_test": "send a test e-mail",
|
||||||
"help.args.action.options.expose_conf": "write complete configuration to stdout",
|
"help.args.action.options.expose_conf": "write complete configuration to stdout",
|
||||||
"help.args.action.options.password_image": "compute password image and write to stdout",
|
"help.args.action.options.password_image": "compute password image and write to stdout",
|
||||||
|
|
|
||||||
|
|
@ -16,26 +16,6 @@ You should have received a copy of the GNU General Public License along with thi
|
||||||
namespace _espe.helpers
|
namespace _espe.helpers
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export function dbbool_encode(
|
|
||||||
value : boolean
|
|
||||||
) : int
|
|
||||||
{
|
|
||||||
return (value ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export function dbbool_decode(
|
|
||||||
value : int
|
|
||||||
) : boolean
|
|
||||||
{
|
|
||||||
return (value > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export type type_smtp_credentials = {
|
export type type_smtp_credentials = {
|
||||||
|
|
@ -259,7 +239,7 @@ namespace _espe.helpers
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return lib_plankton.string.coin(
|
return lib_plankton.string.coin(
|
||||||
"{{base}}{{rest}}",
|
"{{base}}/{{rest}}",
|
||||||
{
|
{
|
||||||
"base": frontend_url_base,
|
"base": frontend_url_base,
|
||||||
"rest": lib_plankton.string.coin(template, arguments_),
|
"rest": lib_plankton.string.coin(template, arguments_),
|
||||||
|
|
@ -268,4 +248,34 @@ namespace _espe.helpers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export function invite_prefill_mode_encode(
|
||||||
|
invite_prefill_mode : _espe.type.invite_prefill_mode
|
||||||
|
) : int
|
||||||
|
{
|
||||||
|
switch (invite_prefill_mode) {
|
||||||
|
case _espe.type.invite_prefill_mode.hidden: return 0;
|
||||||
|
case _espe.type.invite_prefill_mode.locked: return 1;
|
||||||
|
case _espe.type.invite_prefill_mode.free: return 2;
|
||||||
|
default: throw (new Error("unhandled invite prefill mode: " + String(invite_prefill_mode)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export function invite_prefill_mode_decode(
|
||||||
|
invite_prefill_mode_encoded : int
|
||||||
|
) : _espe.type.invite_prefill_mode
|
||||||
|
{
|
||||||
|
switch (invite_prefill_mode_encoded) {
|
||||||
|
case 0: return _espe.type.invite_prefill_mode.hidden;
|
||||||
|
case 1: return _espe.type.invite_prefill_mode.locked;
|
||||||
|
case 2: return _espe.type.invite_prefill_mode.free;
|
||||||
|
default: throw (new Error("unhandled encoded invite prefill mode: " + String(invite_prefill_mode_encoded)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -204,10 +204,6 @@ namespace _espe
|
||||||
"name": "api-doc",
|
"name": "api-doc",
|
||||||
"description": lib_plankton.translate.get("help.args.action.options.api_doc")
|
"description": lib_plankton.translate.get("help.args.action.options.api_doc")
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "sample",
|
|
||||||
"description": lib_plankton.translate.get("help.args.action.options.sample"),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "email-test",
|
"name": "email-test",
|
||||||
"description": lib_plankton.translate.get("help.args.action.options.email_test")
|
"description": lib_plankton.translate.get("help.args.action.options.email_test")
|
||||||
|
|
@ -275,7 +271,7 @@ namespace _espe
|
||||||
"hidden": true,
|
"hidden": true,
|
||||||
}),
|
}),
|
||||||
"conf_path": lib_plankton.args.class_argument.volatile({
|
"conf_path": lib_plankton.args.class_argument.volatile({
|
||||||
"indicators_long": ["conf-path"],
|
"indicators_long": ["conf_path"],
|
||||||
"indicators_short": ["c"],
|
"indicators_short": ["c"],
|
||||||
"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,
|
||||||
|
|
@ -364,14 +360,6 @@ namespace _espe
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "sample": {
|
|
||||||
const path : string = args["arg1"];
|
|
||||||
if (path === null) {
|
|
||||||
throw (new Error("SYNTAX: sample <source-file-path>"));
|
|
||||||
}
|
|
||||||
_espe.sample.fill_by_path(path);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "email-test": {
|
case "email-test": {
|
||||||
await _espe.helpers.email_send(
|
await _espe.helpers.email_send(
|
||||||
(
|
(
|
||||||
|
|
|
||||||
|
|
@ -1,226 +0,0 @@
|
||||||
/*
|
|
||||||
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
|
||||||
Copyright (C) 2024 Christian Fraß
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
|
||||||
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with this program. If not, see
|
|
||||||
<https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace _espe.repository.group
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
var _store : (
|
|
||||||
null
|
|
||||||
|
|
|
||||||
lib_plankton.storage.type_store<
|
|
||||||
_espe.type.group_id,
|
|
||||||
Record<string, any>,
|
|
||||||
{},
|
|
||||||
lib_plankton.storage.type_sql_table_autokey_search_term,
|
|
||||||
Record<string, any>
|
|
||||||
>
|
|
||||||
) = null;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function get_store(
|
|
||||||
) : lib_plankton.storage.type_store<
|
|
||||||
_espe.type.group_id,
|
|
||||||
Record<string, any>,
|
|
||||||
{},
|
|
||||||
lib_plankton.storage.type_sql_table_autokey_search_term,
|
|
||||||
Record<string, any>
|
|
||||||
>
|
|
||||||
{
|
|
||||||
if (_store === null)
|
|
||||||
{
|
|
||||||
_store = lib_plankton.storage.sql_table_autokey_store(
|
|
||||||
{
|
|
||||||
"database_implementation": _espe.helpers.database_implementation(),
|
|
||||||
"table_name": "groups",
|
|
||||||
"key_name": "id",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
return _store;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
type type_dispersal = Record<string, any>;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function encode(
|
|
||||||
object : _espe.type.group_object
|
|
||||||
) : type_dispersal
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
"name": object.name,
|
|
||||||
"label": object.label,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function decode(
|
|
||||||
dispersal : type_dispersal
|
|
||||||
) : _espe.type.group_object
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
"name": dispersal["name"],
|
|
||||||
"label": dispersal["label"],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo optimize
|
|
||||||
*/
|
|
||||||
export async function list(
|
|
||||||
search_term : (null | string)
|
|
||||||
) : Promise<
|
|
||||||
Array<
|
|
||||||
{
|
|
||||||
id : _espe.type.group_id;
|
|
||||||
preview : {
|
|
||||||
name : string;
|
|
||||||
label : string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
>
|
|
||||||
>
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
(await get_store().search(null))
|
|
||||||
.filter(
|
|
||||||
({"key": key, "preview": preview}) => (
|
|
||||||
(
|
|
||||||
(search_term === null)
|
|
||||||
||
|
|
||||||
(search_term.length <= 1)
|
|
||||||
)
|
|
||||||
?
|
|
||||||
true
|
|
||||||
:
|
|
||||||
preview["name"].toLowerCase().includes(search_term.toLowerCase())
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.map(
|
|
||||||
({"key": key, "preview": preview}) => ({
|
|
||||||
"id": key,
|
|
||||||
"preview": {
|
|
||||||
"name": preview["name"],
|
|
||||||
"label": preview["label"],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export async function read(
|
|
||||||
id : _espe.type.group_id
|
|
||||||
) : Promise<_espe.type.group_object>
|
|
||||||
{
|
|
||||||
const row : Record<string, any> = await get_store().read(id);
|
|
||||||
|
|
||||||
const dispersal : type_dispersal = row;
|
|
||||||
|
|
||||||
return decode(dispersal);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export async function create(
|
|
||||||
value : _espe.type.group_object
|
|
||||||
) : Promise<_espe.type.group_id>
|
|
||||||
{
|
|
||||||
const dispersal : type_dispersal = encode(value);
|
|
||||||
|
|
||||||
// core
|
|
||||||
const id : _espe.type.group_id = await get_store().create(dispersal);
|
|
||||||
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo replace groups smartly
|
|
||||||
*/
|
|
||||||
export async function update(
|
|
||||||
id : _espe.type.group_id,
|
|
||||||
value : _espe.type.group_object
|
|
||||||
) : Promise<void>
|
|
||||||
{
|
|
||||||
const dispersal : type_dispersal = encode(value);
|
|
||||||
|
|
||||||
// core
|
|
||||||
await get_store().update(id, dispersal);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export async function delete_(
|
|
||||||
id : _espe.type.group_id
|
|
||||||
) : Promise<void>
|
|
||||||
{
|
|
||||||
// core
|
|
||||||
await get_store().delete(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export async function dump(
|
|
||||||
) : Promise<
|
|
||||||
Array<
|
|
||||||
{
|
|
||||||
id : _espe.type.group_id;
|
|
||||||
object : _espe.type.group_object;
|
|
||||||
}
|
|
||||||
>
|
|
||||||
>
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
Promise.all(
|
|
||||||
(await get_store().search(null))
|
|
||||||
.map(hit => hit.key)
|
|
||||||
.map(
|
|
||||||
id => (
|
|
||||||
read(id)
|
|
||||||
.then(
|
|
||||||
(object) => ({
|
|
||||||
"id": id,
|
|
||||||
"object": object
|
|
||||||
})
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with thi
|
||||||
<https://www.gnu.org/licenses/>.
|
<https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace _espe.repository.invitation
|
namespace _espe.repository.invite
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -33,7 +33,7 @@ namespace _espe.repository.invitation
|
||||||
null
|
null
|
||||||
|
|
|
|
||||||
lib_plankton.storage.type_store<
|
lib_plankton.storage.type_store<
|
||||||
_espe.type.invitation_id,
|
_espe.type.invite_id,
|
||||||
Record<string, any>,
|
Record<string, any>,
|
||||||
{},
|
{},
|
||||||
lib_plankton.storage.type_sql_table_autokey_search_term,
|
lib_plankton.storage.type_sql_table_autokey_search_term,
|
||||||
|
|
@ -55,7 +55,7 @@ namespace _espe.repository.invitation
|
||||||
*/
|
*/
|
||||||
function get_core_store(
|
function get_core_store(
|
||||||
) : lib_plankton.storage.type_store<
|
) : lib_plankton.storage.type_store<
|
||||||
_espe.type.invitation_id,
|
_espe.type.invite_id,
|
||||||
Record<string, any>,
|
Record<string, any>,
|
||||||
{},
|
{},
|
||||||
lib_plankton.storage.type_sql_table_autokey_search_term,
|
lib_plankton.storage.type_sql_table_autokey_search_term,
|
||||||
|
|
@ -66,7 +66,7 @@ namespace _espe.repository.invitation
|
||||||
_core_store = lib_plankton.storage.sql_table_autokey_store(
|
_core_store = lib_plankton.storage.sql_table_autokey_store(
|
||||||
{
|
{
|
||||||
"database_implementation": _espe.helpers.database_implementation(),
|
"database_implementation": _espe.helpers.database_implementation(),
|
||||||
"table_name": "invitations",
|
"table_name": "invites",
|
||||||
"key_name": "id",
|
"key_name": "id",
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -87,8 +87,8 @@ namespace _espe.repository.invitation
|
||||||
_group_chest = lib_plankton.storage.sql_table_common.chest(
|
_group_chest = lib_plankton.storage.sql_table_common.chest(
|
||||||
{
|
{
|
||||||
"database_implementation": _espe.helpers.database_implementation(),
|
"database_implementation": _espe.helpers.database_implementation(),
|
||||||
"table_name": "invitation_groups",
|
"table_name": "invite_groups",
|
||||||
"key_names": ["invitation_id","group_id"],
|
"key_names": ["invite_id","group_name"],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -112,26 +112,26 @@ namespace _espe.repository.invitation
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
function encode(
|
function encode(
|
||||||
object : _espe.type.invitation_object
|
object : _espe.type.invite_object
|
||||||
) : type_dispersal
|
) : type_dispersal
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
"core_row": {
|
"core_row": {
|
||||||
"key": object.key,
|
"key": object.key,
|
||||||
"expiry": object.expiry,
|
"expiry": object.expiry,
|
||||||
"name_changeable": _espe.helpers.dbbool_encode(object.name_changeable),
|
"membership_number_mode": _espe.helpers.invite_prefill_mode_encode(object.membership_number_mode),
|
||||||
|
"membership_number_value": object.membership_number_value,
|
||||||
|
"name_mode": _espe.helpers.invite_prefill_mode_encode(object.name_mode),
|
||||||
"name_value": object.name_value,
|
"name_value": object.name_value,
|
||||||
"label_changeable": _espe.helpers.dbbool_encode(object.label_changeable),
|
"email_address_mode": _espe.helpers.invite_prefill_mode_encode(object.email_address_mode),
|
||||||
"label_value": object.label_value,
|
|
||||||
"email_address_changeable": _espe.helpers.dbbool_encode(object.email_address_changeable),
|
|
||||||
"email_address_value": object.email_address_value,
|
"email_address_value": object.email_address_value,
|
||||||
"groups_changeable": _espe.helpers.dbbool_encode(object.groups_changeable),
|
"groups_mode": _espe.helpers.invite_prefill_mode_encode(object.groups_mode),
|
||||||
},
|
},
|
||||||
"group_rows": (
|
"group_rows": (
|
||||||
(object.groups_value ?? [])
|
object.groups_value
|
||||||
.map(
|
.map(
|
||||||
group_id => ({
|
group => ({
|
||||||
"group_id": group_id,
|
"group_name": group,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -143,20 +143,20 @@ namespace _espe.repository.invitation
|
||||||
*/
|
*/
|
||||||
function decode(
|
function decode(
|
||||||
dispersal : type_dispersal
|
dispersal : type_dispersal
|
||||||
) : _espe.type.invitation_object
|
) : _espe.type.invite_object
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
"key": dispersal.core_row["key"],
|
"key": dispersal.core_row["key"],
|
||||||
"expiry": dispersal.core_row["expiry"],
|
"expiry": dispersal.core_row["expiry"],
|
||||||
"name_changeable": _espe.helpers.dbbool_decode(dispersal.core_row["name_changeable"]),
|
"membership_number_mode": _espe.helpers.invite_prefill_mode_decode(dispersal.core_row["membership_number_mode"]),
|
||||||
|
"membership_number_value": dispersal.core_row["membership_number_value"],
|
||||||
|
"name_mode": _espe.helpers.invite_prefill_mode_decode(dispersal.core_row["name_mode"]),
|
||||||
"name_value": dispersal.core_row["name_value"],
|
"name_value": dispersal.core_row["name_value"],
|
||||||
"label_changeable": _espe.helpers.dbbool_decode(dispersal.core_row["label_changeable"]),
|
"email_address_mode": _espe.helpers.invite_prefill_mode_decode(dispersal.core_row["email_address_mode"]),
|
||||||
"label_value": dispersal.core_row["label_value"],
|
|
||||||
"email_address_changeable": _espe.helpers.dbbool_decode(dispersal.core_row["email_address_changeable"]),
|
|
||||||
"email_address_value": dispersal.core_row["email_address_value"],
|
"email_address_value": dispersal.core_row["email_address_value"],
|
||||||
"groups_changeable": _espe.helpers.dbbool_decode(dispersal.core_row["groups_changeable"]),
|
"groups_mode": _espe.helpers.invite_prefill_mode_decode(dispersal.core_row["groups_mode"]),
|
||||||
"groups_value": lib_plankton.list.sorted<_espe.type.group_id>(
|
"groups_value": lib_plankton.list.sorted<string>(
|
||||||
dispersal.group_rows.map(row => row["group_id"]),
|
dispersal.group_rows.map(row => row["group_name"]),
|
||||||
{
|
{
|
||||||
"compare_element": (group1, group2) => (group1 <= group2)
|
"compare_element": (group1, group2) => (group1 <= group2)
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +173,7 @@ namespace _espe.repository.invitation
|
||||||
) : Promise<
|
) : Promise<
|
||||||
Array<
|
Array<
|
||||||
{
|
{
|
||||||
id : _espe.type.invitation_id;
|
id : _espe.type.invite_id;
|
||||||
preview : {
|
preview : {
|
||||||
name : string;
|
name : string;
|
||||||
};
|
};
|
||||||
|
|
@ -197,7 +197,6 @@ namespace _espe.repository.invitation
|
||||||
"id": key,
|
"id": key,
|
||||||
"preview": {
|
"preview": {
|
||||||
"name": preview["name_value"],
|
"name": preview["name_value"],
|
||||||
"label": preview["label_value"],
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
@ -208,14 +207,14 @@ namespace _espe.repository.invitation
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export async function read(
|
export async function read(
|
||||||
id : _espe.type.invitation_id
|
id : _espe.type.invite_id
|
||||||
) : Promise<_espe.type.invitation_object>
|
) : Promise<_espe.type.invite_object>
|
||||||
{
|
{
|
||||||
const core_row : Record<string, any> = await get_core_store().read(id);
|
const core_row : Record<string, any> = await get_core_store().read(id);
|
||||||
const group_hits : Array<{key : Record<string, any>; preview : Record<string, any>;}> = await get_group_chest().search(
|
const group_hits : Array<{key : Record<string, any>; preview : Record<string, any>;}> = await get_group_chest().search(
|
||||||
{
|
{
|
||||||
"expression": "invitation_id = $invitation_id",
|
"expression": "invite_id = $invite_id",
|
||||||
"arguments": {"invitation_id": id}
|
"arguments": {"invite_id": id}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -223,7 +222,7 @@ namespace _espe.repository.invitation
|
||||||
"core_row": core_row,
|
"core_row": core_row,
|
||||||
"group_rows": group_hits.map(
|
"group_rows": group_hits.map(
|
||||||
hit => ({
|
hit => ({
|
||||||
"group_id": hit.preview["group_id"]
|
"group_name": hit.preview["group_name"]
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
@ -235,20 +234,20 @@ namespace _espe.repository.invitation
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export async function create(
|
export async function create(
|
||||||
value : _espe.type.invitation_object
|
value : _espe.type.invite_object
|
||||||
) : Promise<_espe.type.invitation_id>
|
) : Promise<_espe.type.invite_id>
|
||||||
{
|
{
|
||||||
const dispersal : type_dispersal = encode(value);
|
const dispersal : type_dispersal = encode(value);
|
||||||
|
|
||||||
// core
|
// core
|
||||||
const id : _espe.type.invitation_id = await get_core_store().create(dispersal.core_row);
|
const id : _espe.type.invite_id = await get_core_store().create(dispersal.core_row);
|
||||||
|
|
||||||
// groups
|
// groups
|
||||||
for await (const group_row of dispersal.group_rows) {
|
for await (const group_row of dispersal.group_rows) {
|
||||||
await get_group_chest().write(
|
await get_group_chest().write(
|
||||||
[
|
[
|
||||||
id,
|
id,
|
||||||
group_row["group_id"],
|
group_row["group_name"],
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
"_dummy": null,
|
"_dummy": null,
|
||||||
|
|
@ -263,14 +262,14 @@ namespace _espe.repository.invitation
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export async function delete_(
|
export async function delete_(
|
||||||
id : _espe.type.invitation_id
|
id : _espe.type.invite_id
|
||||||
) : Promise<void>
|
) : Promise<void>
|
||||||
{
|
{
|
||||||
// groups
|
// groups
|
||||||
const hits : Array<{key : Array<any>; preview : Record<string, any>;}> = await get_group_chest().search(
|
const hits : Array<{key : Array<any>; preview : Record<string, any>;}> = await get_group_chest().search(
|
||||||
{
|
{
|
||||||
"expression": "invitation_id = $invitation_id",
|
"expression": "invite_id = $invite_id",
|
||||||
"arguments": {"invitation_id": id}
|
"arguments": {"invite_id": id}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
for (const hit of hits) {
|
for (const hit of hits) {
|
||||||
|
|
@ -283,19 +282,18 @@ namespace _espe.repository.invitation
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @todo optimize
|
|
||||||
*/
|
*/
|
||||||
export async function identify(
|
export async function identify(
|
||||||
key : _espe.type.invitation_key
|
key : _espe.type.invite_key
|
||||||
) : Promise<_espe.type.invitation_id>
|
) : Promise<_espe.type.invite_id>
|
||||||
{
|
{
|
||||||
const hits : Array<{id : _espe.type.invitation_id; preview : any;}> = await list(key);
|
const hits : Array<{id : _espe.type.invite_id; preview : any;}> = await list(key);
|
||||||
return (
|
return (
|
||||||
(hits.length !== 1)
|
(hits.length !== 1)
|
||||||
?
|
?
|
||||||
Promise.reject<_espe.type.invitation_id>(new Error("not found"))
|
Promise.reject<_espe.type.invite_id>(new Error("not found"))
|
||||||
:
|
:
|
||||||
Promise.resolve<_espe.type.invitation_id>(hits[0].id)
|
Promise.resolve<_espe.type.invite_id>(hits[0].id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -306,8 +304,8 @@ namespace _espe.repository.invitation
|
||||||
) : Promise<
|
) : Promise<
|
||||||
Array<
|
Array<
|
||||||
{
|
{
|
||||||
id : _espe.type.invitation_id;
|
id : _espe.type.invite_id;
|
||||||
object : _espe.type.invitation_object;
|
object : _espe.type.invite_object;
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
|
|
@ -88,7 +88,7 @@ namespace _espe.repository.member
|
||||||
{
|
{
|
||||||
"database_implementation": _espe.helpers.database_implementation(),
|
"database_implementation": _espe.helpers.database_implementation(),
|
||||||
"table_name": "member_groups",
|
"table_name": "member_groups",
|
||||||
"key_names": ["member_id","group_id"],
|
"key_names": ["member_id","group_name"],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -117,10 +117,16 @@ namespace _espe.repository.member
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
"core_row": {
|
"core_row": {
|
||||||
"name": object.name,
|
"membership_number": object.membership_number,
|
||||||
"label": object.label,
|
"name_real_value": object.name_real_value,
|
||||||
"email_address": object.email_address,
|
"name_real_index": object.name_real_index,
|
||||||
"enabled": _espe.helpers.dbbool_encode(object.enabled),
|
"email_address_private": object.email_address_private,
|
||||||
|
"registered": (object.registered ? 1 : 0),
|
||||||
|
"enabled": (object.enabled ? 1 : 0),
|
||||||
|
"email_use_veiled_address": (object.email_use_veiled_address ? 1 : 0),
|
||||||
|
"email_use_nominal_address": (object.email_use_nominal_address ? 1 : 0),
|
||||||
|
"email_redirect_to_private_address": (object.email_redirect_to_private_address ? 1 : 0),
|
||||||
|
"email_allow_sending": (object.email_allow_sending ? 1 : 0),
|
||||||
"password_image": object.password_image,
|
"password_image": object.password_image,
|
||||||
"password_change_last_attempt": object.password_change_last_attempt,
|
"password_change_last_attempt": object.password_change_last_attempt,
|
||||||
"password_change_token": object.password_change_token,
|
"password_change_token": object.password_change_token,
|
||||||
|
|
@ -129,7 +135,7 @@ namespace _espe.repository.member
|
||||||
object.groups
|
object.groups
|
||||||
.map(
|
.map(
|
||||||
group => ({
|
group => ({
|
||||||
"group_id": group,
|
"group_name": group,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -144,16 +150,22 @@ namespace _espe.repository.member
|
||||||
) : _espe.type.member_object
|
) : _espe.type.member_object
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
"name": dispersal.core_row["name"],
|
"membership_number": dispersal.core_row["membership_number"],
|
||||||
"label": dispersal.core_row["label"],
|
"name_real_value": dispersal.core_row["name_real_value"],
|
||||||
"email_address": dispersal.core_row["email_address"],
|
"name_real_index": dispersal.core_row["name_real_index"],
|
||||||
"groups": lib_plankton.list.sorted<_espe.type.group_id>(
|
"email_address_private": dispersal.core_row["email_address_private"],
|
||||||
dispersal.group_rows.map(row => row["group_id"]),
|
"groups": lib_plankton.list.sorted<string>(
|
||||||
|
dispersal.group_rows.map(row => row["group_name"]),
|
||||||
{
|
{
|
||||||
"compare_element": (group1, group2) => (group1 <= group2)
|
"compare_element": (group1, group2) => (group1 <= group2)
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
"enabled": _espe.helpers.dbbool_decode(dispersal.core_row["enabled"]),
|
"registered": (dispersal.core_row["registered"] > 0),
|
||||||
|
"enabled": (dispersal.core_row["enabled"] > 0),
|
||||||
|
"email_use_veiled_address": (dispersal.core_row["email_use_veiled_address"] > 0),
|
||||||
|
"email_use_nominal_address": (dispersal.core_row["email_use_nominal_address"] > 0),
|
||||||
|
"email_redirect_to_private_address": (dispersal.core_row["email_redirect_to_private_address"] > 0),
|
||||||
|
"email_allow_sending": (dispersal.core_row["email_allow_sending"] > 0),
|
||||||
"password_image": dispersal.core_row["password_image"],
|
"password_image": dispersal.core_row["password_image"],
|
||||||
"password_change_last_attempt": dispersal.core_row["password_change_last_attempt"],
|
"password_change_last_attempt": dispersal.core_row["password_change_last_attempt"],
|
||||||
"password_change_token": dispersal.core_row["password_change_token"],
|
"password_change_token": dispersal.core_row["password_change_token"],
|
||||||
|
|
@ -171,8 +183,9 @@ namespace _espe.repository.member
|
||||||
{
|
{
|
||||||
id : _espe.type.member_id;
|
id : _espe.type.member_id;
|
||||||
preview : {
|
preview : {
|
||||||
name : string;
|
membership_number : string;
|
||||||
label : string;
|
name_real_value : string;
|
||||||
|
name_real_index : int;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
@ -187,18 +200,21 @@ namespace _espe.repository.member
|
||||||
||
|
||
|
||||||
(search_term.length <= 1)
|
(search_term.length <= 1)
|
||||||
)
|
)
|
||||||
?
|
? true
|
||||||
true
|
: (
|
||||||
:
|
preview["membership_number"].toLowerCase().includes(search_term.toLowerCase())
|
||||||
preview["name"].toLowerCase().includes(search_term.toLowerCase())
|
||
|
||||||
|
preview["name_real_value"].toLowerCase().includes(search_term.toLowerCase())
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.map(
|
.map(
|
||||||
({"key": key, "preview": preview}) => ({
|
({"key": key, "preview": preview}) => ({
|
||||||
"id": key,
|
"id": key,
|
||||||
"preview": {
|
"preview": {
|
||||||
"name": preview["name"],
|
"membership_number": preview["membership_number"],
|
||||||
"label": preview["label"],
|
"name_real_value": preview["name_real_value"],
|
||||||
|
"name_real_index": preview["name_real_index"],
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
@ -224,7 +240,7 @@ namespace _espe.repository.member
|
||||||
"core_row": core_row,
|
"core_row": core_row,
|
||||||
"group_rows": group_hits.map(
|
"group_rows": group_hits.map(
|
||||||
hit => ({
|
hit => ({
|
||||||
"group_id": hit.preview["group_id"]
|
"group_name": hit.preview["group_name"]
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
@ -249,7 +265,7 @@ namespace _espe.repository.member
|
||||||
await get_group_chest().write(
|
await get_group_chest().write(
|
||||||
[
|
[
|
||||||
id,
|
id,
|
||||||
group_row["group_id"],
|
group_row["group_name"],
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
"_dummy": null,
|
"_dummy": null,
|
||||||
|
|
@ -281,6 +297,7 @@ namespace _espe.repository.member
|
||||||
"arguments": {"member_id": id}
|
"arguments": {"member_id": id}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
lib_plankton.log.info("update_hit", hits);
|
||||||
for (const hit of hits) {
|
for (const hit of hits) {
|
||||||
await get_group_chest().delete(hit.key);
|
await get_group_chest().delete(hit.key);
|
||||||
}
|
}
|
||||||
|
|
@ -288,7 +305,7 @@ namespace _espe.repository.member
|
||||||
await get_group_chest().write(
|
await get_group_chest().write(
|
||||||
[
|
[
|
||||||
id,
|
id,
|
||||||
group_row["group_id"],
|
group_row["group_name"],
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
"_dummy": null,
|
"_dummy": null,
|
||||||
|
|
|
||||||
108
source/repositories/name_index.ts
Normal file
108
source/repositories/name_index.ts
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
||||||
|
Copyright (C) 2024 Christian Fraß
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||||
|
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with this program. If not, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace _espe.repository.name_index
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
var _chest : (
|
||||||
|
null
|
||||||
|
|
|
||||||
|
lib_plankton.storage.type_chest<
|
||||||
|
Array<any>,
|
||||||
|
Record<string, any>,
|
||||||
|
lib_plankton.database.type_description_create_table,
|
||||||
|
lib_plankton.storage.sql_table_common.type_sql_table_common_search_term,
|
||||||
|
Record<string, any>
|
||||||
|
>
|
||||||
|
) = null;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function get_chest(
|
||||||
|
) : lib_plankton.storage.type_chest<
|
||||||
|
Array<any>,
|
||||||
|
Record<string, any>,
|
||||||
|
lib_plankton.database.type_description_create_table,
|
||||||
|
lib_plankton.storage.sql_table_common.type_sql_table_common_search_term,
|
||||||
|
Record<string, any>
|
||||||
|
>
|
||||||
|
{
|
||||||
|
if (_chest === null) {
|
||||||
|
_chest = lib_plankton.storage.sql_table_common.chest(
|
||||||
|
{
|
||||||
|
"database_implementation": _espe.helpers.database_implementation(),
|
||||||
|
"table_name": "name_indices",
|
||||||
|
"key_names": ["name_image"],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
return _chest;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
async function get_name_image(
|
||||||
|
name : string
|
||||||
|
) : Promise<string>
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
(! _espe.conf.get().settings.name_index.veil)
|
||||||
|
? name
|
||||||
|
: await lib_plankton.sha256.get(
|
||||||
|
lib_plankton.json.encode(name),
|
||||||
|
(_espe.conf.get().settings.name_index.salt ?? undefined)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export async function read(
|
||||||
|
name : string
|
||||||
|
) : Promise<int>
|
||||||
|
{
|
||||||
|
const name_image : string = await get_name_image(name);
|
||||||
|
let row : Record<string, any>;
|
||||||
|
try {
|
||||||
|
row = await get_chest().read([name_image]);
|
||||||
|
return row["index"];
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export async function write(
|
||||||
|
name : string,
|
||||||
|
index : int
|
||||||
|
) : Promise<void>
|
||||||
|
{
|
||||||
|
const name_image : string = await get_name_image(name);
|
||||||
|
await get_chest().write([name_image], {"index": index});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
151
source/sample.ts
151
source/sample.ts
|
|
@ -1,151 +0,0 @@
|
||||||
/*
|
|
||||||
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
|
||||||
Copyright (C) 2024 Christian Fraß
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
|
||||||
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with this program. If not, see
|
|
||||||
<https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace _espe.sample
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
type type_data = {
|
|
||||||
groups : Array<
|
|
||||||
{
|
|
||||||
id : int;
|
|
||||||
name : string;
|
|
||||||
label : string;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
admins : Array<
|
|
||||||
{
|
|
||||||
id : int;
|
|
||||||
name : string;
|
|
||||||
email_address : (null | string);
|
|
||||||
password : string;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
members : Array<
|
|
||||||
{
|
|
||||||
id : int;
|
|
||||||
name : string;
|
|
||||||
label : string;
|
|
||||||
email_address : (null | string);
|
|
||||||
groups : Array<int>;
|
|
||||||
password : string;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
invitations : Array<
|
|
||||||
{
|
|
||||||
id : int;
|
|
||||||
name_changeable : boolean;
|
|
||||||
name_value : string;
|
|
||||||
label_changeable : boolean;
|
|
||||||
label_value : string;
|
|
||||||
email_address_changeable : boolean;
|
|
||||||
email_address_value : (null | string);
|
|
||||||
groups_changeable : boolean;
|
|
||||||
groups_value : Array<int>;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export async function fill(
|
|
||||||
data : type_data
|
|
||||||
) : Promise<void>
|
|
||||||
{
|
|
||||||
const track_groups : Map<int, _espe.type.group_id> = new Map<int, _espe.type.group_id>();
|
|
||||||
// groups
|
|
||||||
{
|
|
||||||
for (const group_raw of data.groups)
|
|
||||||
{
|
|
||||||
const group_id : _espe.type.group_id = await _espe.service.group.add(
|
|
||||||
{
|
|
||||||
"name": group_raw.name,
|
|
||||||
"label": group_raw.label,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
track_groups.set(group_raw.id, group_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// admins
|
|
||||||
{
|
|
||||||
for (const admin_raw of data.admins)
|
|
||||||
{
|
|
||||||
const admin_id : _espe.type.admin_id = await _espe.service.admin.add(
|
|
||||||
admin_raw.name,
|
|
||||||
admin_raw.email_address,
|
|
||||||
admin_raw.password,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// members
|
|
||||||
{
|
|
||||||
for (const member_raw of data.members)
|
|
||||||
{
|
|
||||||
const member_id : _espe.type.member_id = await _espe.service.member.add(
|
|
||||||
{
|
|
||||||
"name": member_raw.name,
|
|
||||||
"label": member_raw.label,
|
|
||||||
"email_address": member_raw.email_address,
|
|
||||||
"groups": member_raw.groups.map(group_id => track_groups.get(group_id)),
|
|
||||||
"password": member_raw.password,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"password_generated": false,
|
|
||||||
"signal_change": false,
|
|
||||||
"greet_member": false,
|
|
||||||
"notify_admins": false,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @todo passwords
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
// invitations
|
|
||||||
{
|
|
||||||
for (const invitation_raw of data.invitations)
|
|
||||||
{
|
|
||||||
const result : {id : _espe.type.invitation_id; key : _espe.type.invitation_key;} = await _espe.service.invitation.create(
|
|
||||||
{
|
|
||||||
"name_changeable": invitation_raw.name_changeable,
|
|
||||||
"name_value": invitation_raw.name_value,
|
|
||||||
"label_changeable": invitation_raw.label_changeable,
|
|
||||||
"label_value": invitation_raw.label_value,
|
|
||||||
"email_address_changeable": invitation_raw.email_address_changeable,
|
|
||||||
"email_address_value": invitation_raw.email_address_value,
|
|
||||||
"groups_changeable": invitation_raw.groups_changeable,
|
|
||||||
"groups_value": invitation_raw.groups_value.map(group_id => track_groups.get(group_id)),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export async function fill_by_path(
|
|
||||||
path : string
|
|
||||||
) : Promise<void>
|
|
||||||
{
|
|
||||||
const content : string = await lib_plankton.file.read(path);
|
|
||||||
const data : type_data = (lib_plankton.json.decode(content) as type_data);
|
|
||||||
await fill(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
/*
|
|
||||||
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
|
||||||
Copyright (C) 2024 Christian Fraß
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
|
||||||
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with this program. If not, see
|
|
||||||
<https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace _espe.service.group
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export async function list(
|
|
||||||
) : Promise<
|
|
||||||
Array<
|
|
||||||
{
|
|
||||||
id : _espe.type.group_id;
|
|
||||||
preview : {
|
|
||||||
name : string;
|
|
||||||
label : string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
>
|
|
||||||
>
|
|
||||||
{
|
|
||||||
return lib_plankton.list.sorted(
|
|
||||||
await _espe.repository.group.list(null),
|
|
||||||
{
|
|
||||||
"compare_element": (entry1, entry2) => (entry1.preview.label <= entry2.preview.label)
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export function get(
|
|
||||||
id : _espe.type.group_id
|
|
||||||
) : Promise<_espe.type.group_object>
|
|
||||||
{
|
|
||||||
return _espe.repository.group.read(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export function add(
|
|
||||||
object : _espe.type.group_object
|
|
||||||
) : Promise<_espe.type.group_id>
|
|
||||||
{
|
|
||||||
return _espe.repository.group.create(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export async function modify(
|
|
||||||
id : _espe.type.group_id,
|
|
||||||
label : string
|
|
||||||
) : Promise<void>
|
|
||||||
{
|
|
||||||
const object : _espe.type.group_object = await _espe.repository.group.read(id);
|
|
||||||
object.label = label;
|
|
||||||
await _espe.repository.group.update(id, object);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,412 +0,0 @@
|
||||||
/*
|
|
||||||
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
|
||||||
Copyright (C) 2024 Christian Fraß
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
|
||||||
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with this program. If not, see
|
|
||||||
<https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace _espe.service.invitation
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export function list(
|
|
||||||
) : Promise<
|
|
||||||
Array<
|
|
||||||
{
|
|
||||||
id : _espe.type.invitation_id;
|
|
||||||
preview : {
|
|
||||||
key : _espe.type.invitation_key;
|
|
||||||
expiry : (null | int);
|
|
||||||
name_value : (null | string);
|
|
||||||
label_value : (null | string);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
>
|
|
||||||
>
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
_espe.repository.invitation.dump()
|
|
||||||
.then(
|
|
||||||
entries => Promise.resolve(
|
|
||||||
entries.map(
|
|
||||||
entry => ({
|
|
||||||
"id": entry.id,
|
|
||||||
"preview": {
|
|
||||||
"key": entry.object.key,
|
|
||||||
"expiry": entry.object.expiry,
|
|
||||||
"name_value": entry.object.name_value,
|
|
||||||
"label_value": entry.object.label_value,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export async function create(
|
|
||||||
{
|
|
||||||
"name_changeable": name_changeable,
|
|
||||||
"name_value": name_value,
|
|
||||||
"label_changeable": label_changeable,
|
|
||||||
"label_value": label_value,
|
|
||||||
"email_address_changeable": email_address_changeable,
|
|
||||||
"email_address_value": email_address_value,
|
|
||||||
"groups_changeable": groups_changeable,
|
|
||||||
"groups_value": groups_value,
|
|
||||||
} : {
|
|
||||||
name_changeable : boolean;
|
|
||||||
name_value : (null | string);
|
|
||||||
label_changeable : boolean;
|
|
||||||
label_value : (null | string);
|
|
||||||
email_address_changeable : boolean;
|
|
||||||
email_address_value : (null | string);
|
|
||||||
groups_changeable : boolean;
|
|
||||||
groups_value : Array<_espe.type.group_id>;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"expiry": expiry = -1,
|
|
||||||
"send_immediatly": send_immediatly = true,
|
|
||||||
} : {
|
|
||||||
expiry ?: (null | int);
|
|
||||||
send_immediatly ?: boolean;
|
|
||||||
} = {
|
|
||||||
}
|
|
||||||
) : Promise<
|
|
||||||
{
|
|
||||||
id : _espe.type.invitation_id;
|
|
||||||
key : _espe.type.invitation_key;
|
|
||||||
url : (null | string);
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @todo outsource to conf
|
|
||||||
*/
|
|
||||||
const default_lifetime : int = (60 * 60 * 24 * 7 * 2);
|
|
||||||
/**
|
|
||||||
* @todo proper salt
|
|
||||||
*/
|
|
||||||
const invitation_key : _espe.type.invitation_key = lib_plankton.sha256.get(
|
|
||||||
(
|
|
||||||
(name_value ?? "")
|
|
||||||
+
|
|
||||||
"/"
|
|
||||||
+
|
|
||||||
lib_plankton.base.get_current_timestamp(true).toFixed(0)
|
|
||||||
),
|
|
||||||
"secret"
|
|
||||||
);
|
|
||||||
const invitation_object : _espe.type.invitation_object = {
|
|
||||||
"key": invitation_key,
|
|
||||||
"expiry": (
|
|
||||||
((expiry !== null) && (expiry < 0))
|
|
||||||
?
|
|
||||||
(lib_plankton.base.get_current_timestamp(true) + default_lifetime)
|
|
||||||
:
|
|
||||||
expiry
|
|
||||||
),
|
|
||||||
"name_changeable": name_changeable,
|
|
||||||
"name_value": name_value,
|
|
||||||
"label_changeable": label_changeable,
|
|
||||||
"label_value": label_value,
|
|
||||||
"email_address_changeable": email_address_changeable,
|
|
||||||
"email_address_value": email_address_value,
|
|
||||||
"groups_changeable": groups_changeable,
|
|
||||||
"groups_value": groups_value,
|
|
||||||
};
|
|
||||||
const invitation_id : _espe.type.invitation_id = await _espe.repository.invitation.create(invitation_object);
|
|
||||||
const frontend_path_template_invitation_handle : (null | string) = _espe.conf.get().settings.connections.frontend_path_template_invitation_handle;
|
|
||||||
const url : (null | string) = (
|
|
||||||
(frontend_path_template_invitation_handle === null)
|
|
||||||
?
|
|
||||||
null
|
|
||||||
:
|
|
||||||
_espe.helpers.frontend_url_get(
|
|
||||||
frontend_path_template_invitation_handle,
|
|
||||||
{
|
|
||||||
"key": invitation_key,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
// send link
|
|
||||||
{
|
|
||||||
if (! send_immediatly)
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (
|
|
||||||
! (
|
|
||||||
(
|
|
||||||
(email_address_value !== null)
|
|
||||||
&&
|
|
||||||
(email_address_value !== "")
|
|
||||||
)
|
|
||||||
&&
|
|
||||||
(url !== null)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
lib_plankton.log._warning(
|
|
||||||
"espe.service.invitation.create.email.condition_unmet",
|
|
||||||
{
|
|
||||||
"details": {
|
|
||||||
"provided_address": email_address_value,
|
|
||||||
"url": url,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await _espe.helpers.email_send(
|
|
||||||
[email_address_value],
|
|
||||||
lib_plankton.string.coin(
|
|
||||||
"{{head}} | {{core}}",
|
|
||||||
{
|
|
||||||
"head": _espe.conf.get().settings.organisation.name,
|
|
||||||
"core": lib_plankton.translate.get("email.invitation.subject"),
|
|
||||||
}
|
|
||||||
),
|
|
||||||
lib_plankton.translate.get(
|
|
||||||
"email.invitation.body",
|
|
||||||
{
|
|
||||||
"url": (url ?? "?"),
|
|
||||||
"organisation": _espe.conf.get().settings.organisation.name,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
catch (error)
|
|
||||||
{
|
|
||||||
lib_plankton.log._error(
|
|
||||||
"espe.service.invitation.create.email.could_not_be_sent",
|
|
||||||
{
|
|
||||||
"details": {
|
|
||||||
"provided_address": email_address_value,
|
|
||||||
"error": String(error),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
"id": invitation_id,
|
|
||||||
"key": invitation_key,
|
|
||||||
"url": url,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export function remove(
|
|
||||||
id : _espe.type.invitation_id
|
|
||||||
) : Promise<void>
|
|
||||||
{
|
|
||||||
return _espe.repository.invitation.delete_(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export function get_by_id(
|
|
||||||
id : _espe.type.invitation_id
|
|
||||||
) : Promise<_espe.type.invitation_object>
|
|
||||||
{
|
|
||||||
return _espe.repository.invitation.read(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function get_by_key(
|
|
||||||
key : _espe.type.invitation_key
|
|
||||||
) : Promise<_espe.type.invitation_object>
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
_espe.repository.invitation.identify(key)
|
|
||||||
.then(
|
|
||||||
(id) => _espe.repository.invitation.read(id)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export async function examine(
|
|
||||||
key : _espe.type.invitation_key
|
|
||||||
) : Promise<_espe.type.invitation_object>
|
|
||||||
{
|
|
||||||
let invitation_object : (null | _espe.type.invitation_object);
|
|
||||||
try {
|
|
||||||
invitation_object = await get_by_key(key);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
invitation_object = null;
|
|
||||||
}
|
|
||||||
if (invitation_object === null) {
|
|
||||||
return Promise.reject(new Error("not found"))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const now : int = lib_plankton.base.get_current_timestamp(true);
|
|
||||||
if ((invitation_object.expiry !== null) && (invitation_object.expiry < now)) {
|
|
||||||
return Promise.reject(new Error("expired"));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return Promise.resolve(invitation_object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export async function accept(
|
|
||||||
key : _espe.type.invitation_key,
|
|
||||||
data : {
|
|
||||||
name : (null | string);
|
|
||||||
label : (null | string);
|
|
||||||
groups : (null | Array<_espe.type.group_id>);
|
|
||||||
email_address : (null | string);
|
|
||||||
password : (null | string);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
: Promise<
|
|
||||||
Array<
|
|
||||||
{
|
|
||||||
incident : string;
|
|
||||||
details : Record<string, any>;
|
|
||||||
}
|
|
||||||
>
|
|
||||||
>
|
|
||||||
{
|
|
||||||
const invitation_id : _espe.type.invitation_id = await _espe.repository.invitation.identify(key);
|
|
||||||
/**
|
|
||||||
* might throw, but that's fine, since caught and handled in the API action
|
|
||||||
*/
|
|
||||||
const invitation_object : _espe.type.invitation_object = await _espe.repository.invitation.read(invitation_id);
|
|
||||||
const now : int = lib_plankton.base.get_current_timestamp(true);
|
|
||||||
if ((invitation_object.expiry !== null) && (invitation_object.expiry < now))
|
|
||||||
{
|
|
||||||
return Promise.reject(new Error("expired"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
let password_generated : boolean = (
|
|
||||||
(data.password === null)
|
|
||||||
||
|
|
||||||
(data.password === "")
|
|
||||||
);
|
|
||||||
const password_value : string = (
|
|
||||||
password_generated
|
|
||||||
?
|
|
||||||
(data.password as string)
|
|
||||||
:
|
|
||||||
_espe.service.member.generate_password()
|
|
||||||
);
|
|
||||||
const flaws_password : Array<
|
|
||||||
{
|
|
||||||
incident : string;
|
|
||||||
details : Record<string, any>;
|
|
||||||
}
|
|
||||||
> = _espe.service.member.validate_password(password_value);
|
|
||||||
if (flaws_password.length > 0)
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
flaws_password
|
|
||||||
.map(flaw => ({"incident": ("password_" + flaw.incident), "details": flaw.details}))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (
|
|
||||||
(invitation_object.name_value === null)
|
|
||||||
&&
|
|
||||||
(data.name === null)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
throw (new Error("no name provided"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const member_id : _espe.type.member_id = await _espe.service.member.add(
|
|
||||||
{
|
|
||||||
"name": (
|
|
||||||
(
|
|
||||||
invitation_object.name_changeable
|
|
||||||
?
|
|
||||||
data.name
|
|
||||||
:
|
|
||||||
invitation_object.name_value
|
|
||||||
) as string
|
|
||||||
),
|
|
||||||
"label": (
|
|
||||||
(
|
|
||||||
invitation_object.label_changeable
|
|
||||||
?
|
|
||||||
data.label
|
|
||||||
:
|
|
||||||
invitation_object.label_value
|
|
||||||
) as string
|
|
||||||
),
|
|
||||||
"email_address": (
|
|
||||||
(
|
|
||||||
invitation_object.email_address_changeable
|
|
||||||
&&
|
|
||||||
(data.email_address !== null)
|
|
||||||
)
|
|
||||||
?
|
|
||||||
data.email_address
|
|
||||||
:
|
|
||||||
invitation_object.email_address_value
|
|
||||||
),
|
|
||||||
"groups": (
|
|
||||||
(
|
|
||||||
invitation_object.groups_changeable
|
|
||||||
?
|
|
||||||
data.groups
|
|
||||||
:
|
|
||||||
invitation_object.groups_value
|
|
||||||
)
|
|
||||||
??
|
|
||||||
[]
|
|
||||||
),
|
|
||||||
"password": password_value,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"password_generated": password_generated,
|
|
||||||
"signal_change": true,
|
|
||||||
"greet_member": true,
|
|
||||||
"notify_admins": true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
await _espe.repository.invitation.delete_(invitation_id);
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
192
source/services/invite.ts
Normal file
192
source/services/invite.ts
Normal file
|
|
@ -0,0 +1,192 @@
|
||||||
|
/*
|
||||||
|
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
||||||
|
Copyright (C) 2024 Christian Fraß
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||||
|
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with this program. If not, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace _espe.service.invite
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export async function create(
|
||||||
|
{
|
||||||
|
"membership_number_mode": membership_number_mode,
|
||||||
|
"membership_number_value": membership_number_value,
|
||||||
|
"name_mode": name_mode,
|
||||||
|
"name_value": name_value,
|
||||||
|
"email_address_mode": email_address_mode,
|
||||||
|
"email_address_value": email_address_value,
|
||||||
|
"groups_mode": groups_mode,
|
||||||
|
"groups_value": groups_value,
|
||||||
|
} : {
|
||||||
|
membership_number_mode : _espe.type.invite_prefill_mode;
|
||||||
|
membership_number_value : (null | string);
|
||||||
|
name_mode : _espe.type.invite_prefill_mode;
|
||||||
|
name_value : string;
|
||||||
|
email_address_mode : _espe.type.invite_prefill_mode;
|
||||||
|
email_address_value : (null | string);
|
||||||
|
groups_mode : _espe.type.invite_prefill_mode;
|
||||||
|
groups_value : Array<string>;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expiry": expiry = -1,
|
||||||
|
} : {
|
||||||
|
expiry ?: (null | int);
|
||||||
|
} = {
|
||||||
|
}
|
||||||
|
) : Promise<{id : _espe.type.invite_id; key : _espe.type.invite_key}>
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @todo outsource to conf
|
||||||
|
*/
|
||||||
|
const default_lifetime : int = (60 * 60 * 24 * 7 * 2);
|
||||||
|
/**
|
||||||
|
* @todo proper salt
|
||||||
|
*/
|
||||||
|
const invite_key : _espe.type.invite_key = lib_plankton.sha256.get(
|
||||||
|
(
|
||||||
|
name_value
|
||||||
|
+
|
||||||
|
"/"
|
||||||
|
+
|
||||||
|
lib_plankton.base.get_current_timestamp(true).toFixed(0)
|
||||||
|
),
|
||||||
|
"secret"
|
||||||
|
);
|
||||||
|
const invite_object : _espe.type.invite_object = {
|
||||||
|
"key": invite_key,
|
||||||
|
"expiry": (
|
||||||
|
((expiry !== null) && (expiry < 0))
|
||||||
|
?
|
||||||
|
(lib_plankton.base.get_current_timestamp(true) + default_lifetime)
|
||||||
|
:
|
||||||
|
expiry
|
||||||
|
),
|
||||||
|
"membership_number_mode": membership_number_mode,
|
||||||
|
"membership_number_value": membership_number_value,
|
||||||
|
"name_mode": name_mode,
|
||||||
|
"name_value": name_value,
|
||||||
|
"email_address_mode": email_address_mode,
|
||||||
|
"email_address_value": email_address_value,
|
||||||
|
"groups_mode": groups_mode,
|
||||||
|
"groups_value": groups_value,
|
||||||
|
};
|
||||||
|
const invite_id : _espe.type.invite_id = await _espe.repository.invite.create(invite_object);
|
||||||
|
return {
|
||||||
|
"id": invite_id,
|
||||||
|
"key": invite_key,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function get(
|
||||||
|
key : _espe.type.invite_key
|
||||||
|
) : Promise<_espe.type.invite_object>
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
_espe.repository.invite.identify(key)
|
||||||
|
.then(
|
||||||
|
(id) => _espe.repository.invite.read(id)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export async function examine(
|
||||||
|
key : _espe.type.invite_key
|
||||||
|
) : Promise<_espe.type.invite_object>
|
||||||
|
{
|
||||||
|
let invite_object : (null | _espe.type.invite_object);
|
||||||
|
try {
|
||||||
|
invite_object = await get(key)
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
invite_object = null;
|
||||||
|
}
|
||||||
|
if (invite_object === null) {
|
||||||
|
return Promise.reject(new Error("not found"))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const now : int = lib_plankton.base.get_current_timestamp(true);
|
||||||
|
if ((invite_object.expiry !== null) && (invite_object.expiry >= now)) {
|
||||||
|
return Promise.reject(new Error("expired"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Promise.resolve(invite_object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo heed expiry
|
||||||
|
* @todo password?
|
||||||
|
*/
|
||||||
|
export async function accept(
|
||||||
|
key : _espe.type.invite_key,
|
||||||
|
membership_number_value : (null | string),
|
||||||
|
name_value : (null | string),
|
||||||
|
email_address_value : (null | string),
|
||||||
|
groups_value : Array<string>
|
||||||
|
) : Promise<void>
|
||||||
|
{
|
||||||
|
const invite_id : _espe.type.invite_id = await _espe.repository.invite.identify(key);
|
||||||
|
const invite_object : _espe.type.invite_object = await _espe.repository.invite.read(invite_id);
|
||||||
|
const member_id : _espe.type.member_id = await _espe.service.member.project(
|
||||||
|
{
|
||||||
|
"membership_number": (
|
||||||
|
(invite_object.membership_number_mode === _espe.type.invite_prefill_mode.free)
|
||||||
|
?
|
||||||
|
membership_number_value
|
||||||
|
:
|
||||||
|
invite_object.membership_number_value
|
||||||
|
),
|
||||||
|
"name_real_value": (
|
||||||
|
(
|
||||||
|
(invite_object.name_mode === _espe.type.invite_prefill_mode.free)
|
||||||
|
&&
|
||||||
|
(name_value !== null)
|
||||||
|
)
|
||||||
|
?
|
||||||
|
name_value
|
||||||
|
:
|
||||||
|
invite_object.name_value
|
||||||
|
),
|
||||||
|
"email_address_private": (
|
||||||
|
(
|
||||||
|
(invite_object.email_address_mode === _espe.type.invite_prefill_mode.free)
|
||||||
|
&&
|
||||||
|
(email_address_value !== null)
|
||||||
|
)
|
||||||
|
?
|
||||||
|
email_address_value
|
||||||
|
:
|
||||||
|
invite_object.email_address_value
|
||||||
|
),
|
||||||
|
"groups": (
|
||||||
|
(invite_object.groups_mode === _espe.type.invite_prefill_mode.free)
|
||||||
|
?
|
||||||
|
groups_value
|
||||||
|
:
|
||||||
|
invite_object.groups_value
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
await _espe.repository.invite.delete_(invite_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -46,7 +46,7 @@ namespace _espe.service.member
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export function validate_password(
|
function validate_password(
|
||||||
password : string
|
password : string
|
||||||
) : Array<{incident : string; details : Record<string, any>}>
|
) : Array<{incident : string; details : Record<string, any>}>
|
||||||
{
|
{
|
||||||
|
|
@ -59,7 +59,7 @@ namespace _espe.service.member
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export function generate_password(
|
function generate_password(
|
||||||
) : string
|
) : string
|
||||||
{
|
{
|
||||||
return _espe.helper.password.generate(
|
return _espe.helper.password.generate(
|
||||||
|
|
@ -79,7 +79,7 @@ namespace _espe.service.member
|
||||||
"{{object}}{{extension}}",
|
"{{object}}{{extension}}",
|
||||||
{
|
{
|
||||||
"object": lib_plankton.call.convey(
|
"object": lib_plankton.call.convey(
|
||||||
object.name,
|
object.name_real_value,
|
||||||
[
|
[
|
||||||
(x : string) => x.toLowerCase(),
|
(x : string) => x.toLowerCase(),
|
||||||
(x : string) => x.replace(new RegExp(" ", "g"), "."),
|
(x : string) => x.replace(new RegExp(" ", "g"), "."),
|
||||||
|
|
@ -90,7 +90,11 @@ namespace _espe.service.member
|
||||||
(x : string) => x.replace(new RegExp("[^0-9a-z-\.]", "g"), "_"),
|
(x : string) => x.replace(new RegExp("[^0-9a-z-\.]", "g"), "_"),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
"extension": "",
|
"extension": (
|
||||||
|
(object.name_real_index <= 1)
|
||||||
|
? ""
|
||||||
|
: ("." + object.name_real_index.toFixed(0))
|
||||||
|
),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -102,11 +106,46 @@ namespace _espe.service.member
|
||||||
export function name_display(
|
export function name_display(
|
||||||
object : _espe.type.member_object
|
object : _espe.type.member_object
|
||||||
) : string
|
) : string
|
||||||
|
{
|
||||||
|
return object.name_real_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ermittelt die verschleierte E-Mail-Adresse des Mitglieds
|
||||||
|
*/
|
||||||
|
export function email_address_veiled(
|
||||||
|
object : _espe.type.member_object
|
||||||
|
) : (null | string)
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
object.label
|
(object.membership_number === null)
|
||||||
??
|
? null
|
||||||
object.name
|
: lib_plankton.string.coin(
|
||||||
|
"{{prefix}}{{membership_number}}@{{domain}}",
|
||||||
|
{
|
||||||
|
"prefix": _espe.conf.get().settings.misc.prefix_for_veiled_email_addresses,
|
||||||
|
"membership_number": object.membership_number,
|
||||||
|
"domain": _espe.conf.get().settings.organisation.domain,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ermittelt die namentliche E-Mail-Adresse des Mitglieds
|
||||||
|
*/
|
||||||
|
export function email_address_nominal(
|
||||||
|
object : _espe.type.member_object
|
||||||
|
) : string
|
||||||
|
{
|
||||||
|
return lib_plankton.string.coin(
|
||||||
|
"{{user}}@{{domain}}",
|
||||||
|
{
|
||||||
|
"user": name_login(object),
|
||||||
|
"domain": _espe.conf.get().settings.organisation.domain,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,7 +157,15 @@ namespace _espe.service.member
|
||||||
object : _espe.type.member_object
|
object : _espe.type.member_object
|
||||||
) : (null | string)
|
) : (null | string)
|
||||||
{
|
{
|
||||||
return object.email_address;
|
return (
|
||||||
|
object.email_use_nominal_address
|
||||||
|
? email_address_nominal(object)
|
||||||
|
: (
|
||||||
|
object.email_use_veiled_address
|
||||||
|
? email_address_veiled(object)
|
||||||
|
: object.email_address_private
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -145,27 +192,28 @@ namespace _espe.service.member
|
||||||
*/
|
*/
|
||||||
async function send_activation_email(
|
async function send_activation_email(
|
||||||
member_object : _espe.type.member_object,
|
member_object : _espe.type.member_object,
|
||||||
{
|
options : {
|
||||||
"password": password = null,
|
|
||||||
} : {
|
|
||||||
password ?: (null | string);
|
password ?: (null | string);
|
||||||
} = {}
|
} = {}
|
||||||
) : Promise<void>
|
) : Promise<void>
|
||||||
{
|
{
|
||||||
if (! member_object.enabled)
|
options = Object.assign(
|
||||||
{
|
{
|
||||||
|
"password": null,
|
||||||
|
},
|
||||||
|
options
|
||||||
|
);
|
||||||
|
if (! member_object.enabled) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (member_object.email_address === null)
|
if (member_object.email_address_private === null) {
|
||||||
{
|
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
await _espe.helpers.email_send(
|
await _espe.helpers.email_send(
|
||||||
[
|
[
|
||||||
member_object.email_address,
|
member_object.email_address_private,
|
||||||
],
|
],
|
||||||
lib_plankton.string.coin(
|
lib_plankton.string.coin(
|
||||||
"{{head}} | {{core}}",
|
"{{head}} | {{core}}",
|
||||||
|
|
@ -182,17 +230,15 @@ namespace _espe.service.member
|
||||||
"url": (_espe.conf.get().settings.connections.login_url ?? "--"),
|
"url": (_espe.conf.get().settings.connections.login_url ?? "--"),
|
||||||
"password_info": (
|
"password_info": (
|
||||||
(
|
(
|
||||||
(password === undefined)
|
(options.password === undefined)
|
||||||
||
|
||
|
||||||
(password === null)
|
(options.password === null)
|
||||||
)
|
)
|
||||||
?
|
? ""
|
||||||
""
|
: lib_plankton.string.coin(
|
||||||
:
|
|
||||||
lib_plankton.string.coin(
|
|
||||||
lib_plankton.translate.get("email.activation.password_info"),
|
lib_plankton.translate.get("email.activation.password_info"),
|
||||||
{
|
{
|
||||||
"password": password,
|
"password": options.password,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
@ -231,19 +277,15 @@ namespace _espe.service.member
|
||||||
{
|
{
|
||||||
id : _espe.type.member_id;
|
id : _espe.type.member_id;
|
||||||
preview : {
|
preview : {
|
||||||
name : string;
|
membership_number : string;
|
||||||
label : string;
|
name_real_value : string;
|
||||||
|
name_real_index : int;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
return lib_plankton.list.sorted(
|
return _espe.repository.member.list(search_term);
|
||||||
await _espe.repository.member.list(search_term),
|
|
||||||
{
|
|
||||||
"compare_element": (entry1, entry2) => (entry1.id <= entry2.id)
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -262,75 +304,206 @@ namespace _espe.service.member
|
||||||
/**
|
/**
|
||||||
* legt ein Mitglied an
|
* legt ein Mitglied an
|
||||||
*/
|
*/
|
||||||
export async function add(
|
export async function project(
|
||||||
data : {
|
data : {
|
||||||
name : string;
|
membership_number : (null | string);
|
||||||
label : string;
|
name_real_value : string;
|
||||||
email_address : (null | string);
|
email_address_private : (null | string);
|
||||||
groups : Array<_espe.type.group_id>;
|
groups : Array<string>;
|
||||||
password : string;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"password_generated": password_generated = false,
|
|
||||||
"signal_change": flag_signal_change = false,
|
|
||||||
"greet_member": flag_greet_member = false,
|
|
||||||
"notify_admins": flag_notify_admins = false,
|
|
||||||
} : {
|
|
||||||
password_generated ?: boolean;
|
|
||||||
signal_change ?: boolean;
|
|
||||||
greet_member ?: boolean;
|
|
||||||
notify_admins ?: boolean;
|
|
||||||
} = {
|
|
||||||
}
|
}
|
||||||
) : Promise<_espe.type.member_id>
|
) : Promise<_espe.type.member_id>
|
||||||
{
|
{
|
||||||
|
const name_real_index : int = await _espe.service.name_index.next(data.name_real_value);
|
||||||
const object : _espe.type.member_object = {
|
const object : _espe.type.member_object = {
|
||||||
"name": data.name,
|
"membership_number": data.membership_number,
|
||||||
"label": data.label,
|
"name_real_value": data.name_real_value,
|
||||||
"email_address": data.email_address,
|
"name_real_index": name_real_index,
|
||||||
"groups": data.groups,
|
"email_address_private": data.email_address_private,
|
||||||
|
"registered": false,
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"password_image": await password_image(data.password),
|
"email_use_veiled_address": false,
|
||||||
|
"email_use_nominal_address": false,
|
||||||
|
"email_redirect_to_private_address": false,
|
||||||
|
"email_allow_sending": false,
|
||||||
|
"password_image": null,
|
||||||
"password_change_last_attempt": null,
|
"password_change_last_attempt": null,
|
||||||
"password_change_token": null,
|
"password_change_token": null,
|
||||||
|
"groups": data.groups,
|
||||||
};
|
};
|
||||||
const id : _espe.type.member_id = await _espe.repository.member.create(object);
|
const id : _espe.type.member_id = await _espe.repository.member.create(object);
|
||||||
// change
|
|
||||||
{
|
|
||||||
if (! flag_signal_change)
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
signal_change();
|
signal_change();
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sendet an ein Mitglied eine E-Mail mit Aufforderung zur Registrierung
|
||||||
|
*/
|
||||||
|
export async function summon(
|
||||||
|
member_id : _espe.type.member_id,
|
||||||
|
url_template : string
|
||||||
|
) : Promise<(null | string)>
|
||||||
|
{
|
||||||
|
_espe.helpers.frontend_url_check();
|
||||||
|
const member_object : _espe.type.member_object = await get(member_id);
|
||||||
|
if (member_object.email_address_private === null) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
// greet member
|
else {
|
||||||
|
const url : (null | string) = _espe.helpers.frontend_url_get(
|
||||||
|
url_template,
|
||||||
{
|
{
|
||||||
if (! flag_greet_member)
|
"verification": await _espe.helpers.verification_get(member_id),
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await send_activation_email(
|
|
||||||
object,
|
|
||||||
{
|
|
||||||
"password": (password_generated ? data.password : null),
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
if (url === null) {
|
||||||
}
|
|
||||||
// notify admins
|
|
||||||
{
|
|
||||||
if (! flag_notify_admins)
|
|
||||||
{
|
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
|
await _espe.helpers.email_send(
|
||||||
|
[
|
||||||
|
member_object.email_address_private,
|
||||||
|
],
|
||||||
|
lib_plankton.string.coin(
|
||||||
|
"{{head}} | {{core}}",
|
||||||
{
|
{
|
||||||
_espe.service.admin.notify_all(
|
"head": _espe.conf.get().settings.organisation.name,
|
||||||
|
"core": lib_plankton.translate.get("email.summon.subject"),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
lib_plankton.string.coin(
|
||||||
|
lib_plankton.translate.get("email.summon.body"),
|
||||||
|
{
|
||||||
|
"name": name_display(member_object),
|
||||||
|
"url": url,
|
||||||
|
"remark": (
|
||||||
|
(_espe.conf.get().settings.summon_email.remark === null)
|
||||||
|
? ""
|
||||||
|
: (_espe.conf.get().settings.summon_email.remark + "\n\n")
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gibt Daten über ein Mitglied aus, die relevant für die Registrierung sind
|
||||||
|
*/
|
||||||
|
export async function info(
|
||||||
|
member_id : _espe.type.member_id
|
||||||
|
) : Promise<
|
||||||
|
(
|
||||||
|
null
|
||||||
|
|
|
||||||
|
{
|
||||||
|
name_real_value : string;
|
||||||
|
name_real_index : int;
|
||||||
|
name_login : string;
|
||||||
|
email_address_veiled : (null | string);
|
||||||
|
email_address_nominal : string;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
>
|
||||||
|
{
|
||||||
|
const member_object : _espe.type.member_object = await _espe.repository.member.read(member_id);
|
||||||
|
if (! member_object.registered) {
|
||||||
|
return {
|
||||||
|
"name_real_value": member_object.name_real_value,
|
||||||
|
"name_real_index": member_object.name_real_index,
|
||||||
|
"name_login": name_login(member_object),
|
||||||
|
"email_address_veiled": email_address_veiled(member_object),
|
||||||
|
"email_address_nominal": email_address_nominal(member_object),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* führt die Registrierung für ein Mitglied durch
|
||||||
|
*/
|
||||||
|
export async function register(
|
||||||
|
member_id : _espe.type.member_id,
|
||||||
|
data : {
|
||||||
|
email_use_veiled_address : boolean;
|
||||||
|
email_use_nominal_address : boolean;
|
||||||
|
email_redirect_to_private_address : boolean;
|
||||||
|
password : (null | string);
|
||||||
|
},
|
||||||
|
options : {
|
||||||
|
notification_target_url_template ?: (null | string);
|
||||||
|
} = {}
|
||||||
|
) : Promise<Array<{incident : string; details : Record<string, any>;}>>
|
||||||
|
{
|
||||||
|
options = Object.assign(
|
||||||
|
{
|
||||||
|
"notification_target_url_template": null,
|
||||||
|
},
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
|
const member_object : _espe.type.member_object = await get(member_id);
|
||||||
|
|
||||||
|
let flaws : Array<{incident : string; details : Record<string, any>;}> = [];
|
||||||
|
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 (
|
||||||
|
(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 {
|
||||||
|
password_value = generate_password();
|
||||||
|
password_generated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flaws.length > 0) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
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(password_value);
|
||||||
|
member_object.registered = true;
|
||||||
|
await _espe.repository.member.update(member_id, member_object);
|
||||||
|
signal_change();
|
||||||
|
{
|
||||||
|
const url : (null | string) = (
|
||||||
|
(
|
||||||
|
(options.notification_target_url_template === undefined)
|
||||||
|
||
|
||||||
|
(options.notification_target_url_template === null)
|
||||||
|
)
|
||||||
|
? null
|
||||||
|
: _espe.helpers.frontend_url_get(
|
||||||
|
options.notification_target_url_template,
|
||||||
|
{
|
||||||
|
"id": member_id.toFixed(0),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
/*await*/ _espe.service.admin.notify_all(
|
||||||
lib_plankton.string.coin(
|
lib_plankton.string.coin(
|
||||||
"{{head}} | {{core}}",
|
"{{head}} | {{core}}",
|
||||||
{
|
{
|
||||||
|
|
@ -341,14 +514,16 @@ namespace _espe.service.member
|
||||||
lib_plankton.string.coin(
|
lib_plankton.string.coin(
|
||||||
lib_plankton.translate.get("email.registration.body"),
|
lib_plankton.translate.get("email.registration.body"),
|
||||||
{
|
{
|
||||||
"name": object.name,
|
"name_display": name_display(member_object),
|
||||||
"label": object.label,
|
"url": (url ?? "?"),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
/*await*/ send_activation_email(member_object, {"password": password_generated ? password_value : null});
|
||||||
}
|
}
|
||||||
return id;
|
|
||||||
|
return Promise.resolve(flaws);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -358,27 +533,33 @@ namespace _espe.service.member
|
||||||
export async function modify(
|
export async function modify(
|
||||||
member_id : _espe.type.member_id,
|
member_id : _espe.type.member_id,
|
||||||
data : {
|
data : {
|
||||||
label : string;
|
email_address_private : (null | string);
|
||||||
email_address : (null | string);
|
registered : boolean;
|
||||||
enabled : boolean;
|
enabled : boolean;
|
||||||
groups : lib_plankton.pod.type_pod<Array<_espe.type.group_id>>;
|
groups : lib_plankton.pod.type_pod<Array<string>>;
|
||||||
}
|
}
|
||||||
) : Promise<void>
|
) : Promise<void>
|
||||||
{
|
{
|
||||||
const member_object_old : _espe.type.member_object = await get(member_id);
|
const member_object_old : _espe.type.member_object = await get(member_id);
|
||||||
const member_object_new : _espe.type.member_object = {
|
const member_object_new : _espe.type.member_object = {
|
||||||
"name": member_object_old.name,
|
"membership_number": member_object_old.membership_number,
|
||||||
"label": data.label,
|
"name_real_value": member_object_old.name_real_value,
|
||||||
"email_address": data.email_address,
|
"name_real_index": member_object_old.name_real_index,
|
||||||
"groups": (
|
"email_address_private": data.email_address_private,
|
||||||
lib_plankton.pod.is_filled<Array<_espe.type.group_id>>(data.groups)
|
"registered": data.registered,
|
||||||
? lib_plankton.pod.cull<Array<_espe.type.group_id>>(data.groups)
|
|
||||||
: member_object_old.groups
|
|
||||||
),
|
|
||||||
"enabled": data.enabled,
|
"enabled": data.enabled,
|
||||||
|
"email_use_veiled_address": member_object_old.email_use_veiled_address,
|
||||||
|
"email_use_nominal_address": member_object_old.email_use_nominal_address,
|
||||||
|
"email_redirect_to_private_address": member_object_old.email_redirect_to_private_address,
|
||||||
|
"email_allow_sending": member_object_old.email_allow_sending,
|
||||||
"password_image": member_object_old.password_image,
|
"password_image": member_object_old.password_image,
|
||||||
"password_change_last_attempt": member_object_old.password_change_last_attempt,
|
"password_change_last_attempt": member_object_old.password_change_last_attempt,
|
||||||
"password_change_token": member_object_old.password_change_token,
|
"password_change_token": member_object_old.password_change_token,
|
||||||
|
"groups": (
|
||||||
|
lib_plankton.pod.is_filled<Array<string>>(data.groups)
|
||||||
|
? lib_plankton.pod.cull<Array<string>>(data.groups)
|
||||||
|
: member_object_old.groups
|
||||||
|
),
|
||||||
};
|
};
|
||||||
await _espe.repository.member.update(member_id, member_object_new);
|
await _espe.repository.member.update(member_id, member_object_new);
|
||||||
signal_change();
|
signal_change();
|
||||||
|
|
@ -414,13 +595,15 @@ namespace _espe.service.member
|
||||||
(await _espe.repository.member.dump())
|
(await _espe.repository.member.dump())
|
||||||
.filter(
|
.filter(
|
||||||
member_entry => (
|
member_entry => (
|
||||||
|
member_entry.object.registered
|
||||||
|
&&
|
||||||
member_entry.object.enabled
|
member_entry.object.enabled
|
||||||
&&
|
&&
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
(! (member_entry.object.email_address === null))
|
(! (member_entry.object.email_address_private === null))
|
||||||
&&
|
&&
|
||||||
(member_entry.object.email_address === identifier)
|
(member_entry.object.email_address_private === identifier)
|
||||||
)
|
)
|
||||||
||
|
||
|
||||||
(name_login(member_entry.object) === identifier)
|
(name_login(member_entry.object) === identifier)
|
||||||
|
|
@ -449,9 +632,9 @@ namespace _espe.service.member
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (member_object_old.email_address === null) {
|
if (member_object_old.email_address_private === null) {
|
||||||
lib_plankton.log.notice(
|
lib_plankton.log.notice(
|
||||||
"member_password_change_impossible_due_to_missing_email_address",
|
"member_password_change_impossible_due_to_missing_private_email_address",
|
||||||
{
|
{
|
||||||
"member_id": member_id,
|
"member_id": member_id,
|
||||||
}
|
}
|
||||||
|
|
@ -462,14 +645,20 @@ namespace _espe.service.member
|
||||||
// keine echte Verifizierung, der Algorithmus ist aber der passende
|
// keine echte Verifizierung, der Algorithmus ist aber der passende
|
||||||
const token : string = await _espe.helpers.verification_get(Math.floor(Math.random() * (1 << 24)));
|
const token : string = await _espe.helpers.verification_get(Math.floor(Math.random() * (1 << 24)));
|
||||||
const member_object_new : _espe.type.member_object = {
|
const member_object_new : _espe.type.member_object = {
|
||||||
"name": member_object_old.name,
|
"membership_number": member_object_old.membership_number,
|
||||||
"label": member_object_old.label,
|
"name_real_value": member_object_old.name_real_value,
|
||||||
"email_address": member_object_old.email_address,
|
"name_real_index": member_object_old.name_real_index,
|
||||||
|
"email_address_private": member_object_old.email_address_private,
|
||||||
|
"registered": member_object_old.registered,
|
||||||
"enabled": member_object_old.enabled,
|
"enabled": member_object_old.enabled,
|
||||||
"groups": member_object_old.groups,
|
"email_use_veiled_address": member_object_old.email_use_veiled_address,
|
||||||
|
"email_use_nominal_address": member_object_old.email_use_nominal_address,
|
||||||
|
"email_redirect_to_private_address": member_object_old.email_redirect_to_private_address,
|
||||||
|
"email_allow_sending": member_object_old.email_allow_sending,
|
||||||
"password_image": member_object_old.password_image,
|
"password_image": member_object_old.password_image,
|
||||||
"password_change_last_attempt": now,
|
"password_change_last_attempt": now,
|
||||||
"password_change_token": token,
|
"password_change_token": token,
|
||||||
|
"groups": member_object_old.groups,
|
||||||
};
|
};
|
||||||
await _espe.repository.member.update(member_id, member_object_new);
|
await _espe.repository.member.update(member_id, member_object_new);
|
||||||
// signal_change();
|
// signal_change();
|
||||||
|
|
@ -487,7 +676,7 @@ namespace _espe.service.member
|
||||||
else {
|
else {
|
||||||
/*await*/ _espe.helpers.email_send(
|
/*await*/ _espe.helpers.email_send(
|
||||||
[
|
[
|
||||||
member_object_old.email_address,
|
member_object_old.email_address_private,
|
||||||
],
|
],
|
||||||
lib_plankton.string.coin(
|
lib_plankton.string.coin(
|
||||||
"{{head}} | {{core}}",
|
"{{head}} | {{core}}",
|
||||||
|
|
@ -523,12 +712,10 @@ namespace _espe.service.member
|
||||||
) : Promise<Array<{incident : string; details : Record<string, any>;}>>
|
) : Promise<Array<{incident : string; details : Record<string, any>;}>>
|
||||||
{
|
{
|
||||||
const member_object_old : _espe.type.member_object = await _espe.repository.member.read(member_id);
|
const member_object_old : _espe.type.member_object = await _espe.repository.member.read(member_id);
|
||||||
if (member_object_old.email_address === null)
|
if (member_object_old.email_address_private === null) {
|
||||||
{
|
|
||||||
return Promise.reject(new Error("private e-mail address missing"));
|
return Promise.reject(new Error("private e-mail address missing"));
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
let flaws : Array<{incident : string; details : Record<string, any>;}> = [];
|
let flaws : Array<{incident : string; details : Record<string, any>;}> = [];
|
||||||
if (
|
if (
|
||||||
(member_object_old.password_change_token === null)
|
(member_object_old.password_change_token === null)
|
||||||
|
|
@ -554,20 +741,26 @@ namespace _espe.service.member
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const member_object_new : _espe.type.member_object = {
|
const member_object_new : _espe.type.member_object = {
|
||||||
"name": member_object_old.name,
|
"membership_number": member_object_old.membership_number,
|
||||||
"label": member_object_old.label,
|
"name_real_value": member_object_old.name_real_value,
|
||||||
"email_address": member_object_old.email_address,
|
"name_real_index": member_object_old.name_real_index,
|
||||||
"groups": member_object_old.groups,
|
"email_address_private": member_object_old.email_address_private,
|
||||||
|
"registered": member_object_old.registered,
|
||||||
"enabled": member_object_old.enabled,
|
"enabled": member_object_old.enabled,
|
||||||
|
"email_use_veiled_address": member_object_old.email_use_veiled_address,
|
||||||
|
"email_use_nominal_address": member_object_old.email_use_nominal_address,
|
||||||
|
"email_redirect_to_private_address": member_object_old.email_redirect_to_private_address,
|
||||||
|
"email_allow_sending": member_object_old.email_allow_sending,
|
||||||
"password_image": await password_image(password_new),
|
"password_image": await password_image(password_new),
|
||||||
"password_change_last_attempt": member_object_old.password_change_last_attempt,
|
"password_change_last_attempt": member_object_old.password_change_last_attempt,
|
||||||
"password_change_token": null,
|
"password_change_token": null,
|
||||||
|
"groups": member_object_old.groups,
|
||||||
};
|
};
|
||||||
await _espe.repository.member.update(member_id, member_object_new);
|
await _espe.repository.member.update(member_id, member_object_new);
|
||||||
signal_change();
|
signal_change();
|
||||||
await _espe.helpers.email_send(
|
await _espe.helpers.email_send(
|
||||||
[
|
[
|
||||||
member_object_old.email_address,
|
member_object_old.email_address_private,
|
||||||
],
|
],
|
||||||
lib_plankton.string.coin(
|
lib_plankton.string.coin(
|
||||||
"{{head}} | {{core}}",
|
"{{head}} | {{core}}",
|
||||||
|
|
@ -594,14 +787,18 @@ namespace _espe.service.member
|
||||||
* @todo check validity (e.g. username characters)
|
* @todo check validity (e.g. username characters)
|
||||||
*/
|
*/
|
||||||
export async function export_authelia_user_data(
|
export async function export_authelia_user_data(
|
||||||
{
|
options : {
|
||||||
"custom_data": custom_data = null,
|
|
||||||
} : {
|
|
||||||
custom_data ?: (null | Array<_espe.type.member_object>);
|
custom_data ?: (null | Array<_espe.type.member_object>);
|
||||||
} = {
|
} = {}
|
||||||
}
|
|
||||||
) : Promise<any>
|
) : Promise<any>
|
||||||
{
|
{
|
||||||
|
options = Object.assign(
|
||||||
|
{
|
||||||
|
"custom_data": null,
|
||||||
|
},
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
type type_entry = {
|
type type_entry = {
|
||||||
disabled : boolean;
|
disabled : boolean;
|
||||||
displayname : string;
|
displayname : string;
|
||||||
|
|
@ -609,42 +806,14 @@ namespace _espe.service.member
|
||||||
groups : Array<string>;
|
groups : Array<string>;
|
||||||
password : string;
|
password : string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const groups_as_array : Array<
|
|
||||||
{
|
|
||||||
id : _espe.type.group_id;
|
|
||||||
preview : {
|
|
||||||
name : string;
|
|
||||||
label : string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
> = await _espe.service.group.list();
|
|
||||||
const groups_as_map : Map<
|
|
||||||
_espe.type.group_id,
|
|
||||||
_espe.type.group_object
|
|
||||||
> = new Map<
|
|
||||||
_espe.type.group_id,
|
|
||||||
_espe.type.group_object
|
|
||||||
>();
|
|
||||||
for (const group_entry of groups_as_array)
|
|
||||||
{
|
|
||||||
groups_as_map.set(
|
|
||||||
group_entry.id,
|
|
||||||
{
|
|
||||||
"name": group_entry.preview.name,
|
|
||||||
"label": group_entry.preview.label,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return lib_plankton.call.convey(
|
return lib_plankton.call.convey(
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
(custom_data !== undefined)
|
(options.custom_data !== undefined)
|
||||||
&&
|
&&
|
||||||
(custom_data !== null)
|
(options.custom_data !== null)
|
||||||
)
|
)
|
||||||
? (custom_data.map((member_object, index) => ({"id": index, "object": member_object})))
|
? (options.custom_data.map((member_object, index) => ({"id": index, "object": member_object})))
|
||||||
: await dump()
|
: await dump()
|
||||||
),
|
),
|
||||||
[
|
[
|
||||||
|
|
@ -656,6 +825,8 @@ namespace _espe.service.member
|
||||||
),
|
),
|
||||||
(x : Array<any>) => x.filter(
|
(x : Array<any>) => x.filter(
|
||||||
entry => (
|
entry => (
|
||||||
|
entry.object.registered
|
||||||
|
&&
|
||||||
(
|
(
|
||||||
(entry.object.password_image !== null)
|
(entry.object.password_image !== null)
|
||||||
&&
|
&&
|
||||||
|
|
@ -672,16 +843,7 @@ namespace _espe.service.member
|
||||||
"disabled": (! entry.object.enabled),
|
"disabled": (! entry.object.enabled),
|
||||||
"displayname": name_display(entry.object),
|
"displayname": name_display(entry.object),
|
||||||
"email": entry.email_address,
|
"email": entry.email_address,
|
||||||
"groups": (
|
"groups": entry.object.groups,
|
||||||
entry.object.groups
|
|
||||||
.map(
|
|
||||||
(group_id : _espe.type.group_id) => (
|
|
||||||
groups_as_map.get(group_id)?.name
|
|
||||||
??
|
|
||||||
group_id.toFixed(0)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
"password": entry.object.password_image,
|
"password": entry.object.password_image,
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
@ -696,16 +858,20 @@ namespace _espe.service.member
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export async function export_authelia_user_file(
|
export async function export_authelia_user_file(
|
||||||
{
|
options : {
|
||||||
"custom_data": custom_data = null,
|
|
||||||
} : {
|
|
||||||
custom_data ?: (null | Array<_espe.type.member_object>);
|
custom_data ?: (null | Array<_espe.type.member_object>);
|
||||||
} = {
|
} = {}
|
||||||
}
|
|
||||||
) : Promise<string>
|
) : Promise<string>
|
||||||
{
|
{
|
||||||
|
options = Object.assign(
|
||||||
|
{
|
||||||
|
"custom_data": null,
|
||||||
|
},
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
const nm_yaml = require("yaml");
|
const nm_yaml = require("yaml");
|
||||||
return nm_yaml.stringify(await export_authelia_user_data({"custom_data": custom_data}));
|
return nm_yaml.stringify(await export_authelia_user_data(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
31
source/services/name_index.ts
Normal file
31
source/services/name_index.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
|
||||||
|
Copyright (C) 2024 Christian Fraß
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||||
|
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with this program. If not, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace _espe.service.name_index
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export async function next(
|
||||||
|
name : string
|
||||||
|
) : Promise<int>
|
||||||
|
{
|
||||||
|
const current : int = await _espe.repository.name_index.read(name);
|
||||||
|
const result : int = (current + 1);
|
||||||
|
await _espe.repository.name_index.write(name, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -235,6 +235,9 @@
|
||||||
"settings": {
|
"settings": {
|
||||||
"organisation": {
|
"organisation": {
|
||||||
"domain": "testdomain.org"
|
"domain": "testdomain.org"
|
||||||
|
},
|
||||||
|
"misc": {
|
||||||
|
"prefix_for_veiled_email_addresses": "wicht-"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -16,19 +16,6 @@ You should have received a copy of the GNU General Public License along with thi
|
||||||
namespace _espe.type
|
namespace _espe.type
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export type group_id = int;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export type group_object = {
|
|
||||||
name : string;
|
|
||||||
label : string;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export type admin_id = int;
|
export type admin_id = int;
|
||||||
|
|
@ -52,11 +39,17 @@ namespace _espe.type
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export type member_object = {
|
export type member_object = {
|
||||||
name : string;
|
membership_number : (null | string);
|
||||||
label : string;
|
name_real_value : string;
|
||||||
email_address : (null | string);
|
name_real_index : int;
|
||||||
groups : Array<group_id>;
|
email_address_private : (null | string);
|
||||||
|
groups : Array<string>;
|
||||||
|
registered : boolean;
|
||||||
enabled : boolean;
|
enabled : boolean;
|
||||||
|
email_use_veiled_address : boolean;
|
||||||
|
email_use_nominal_address : boolean;
|
||||||
|
email_redirect_to_private_address : boolean;
|
||||||
|
email_allow_sending : boolean;
|
||||||
password_image : (null | string);
|
password_image : (null | string);
|
||||||
password_change_last_attempt : (null | int);
|
password_change_last_attempt : (null | int);
|
||||||
password_change_token : (null | string);
|
password_change_token : (null | string);
|
||||||
|
|
@ -65,28 +58,36 @@ namespace _espe.type
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export type invitation_id = int;
|
export type invite_id = int;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export type invitation_key = string;
|
export type invite_key = string;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @todo use "pod" instead of "changable"/"value"
|
|
||||||
*/
|
*/
|
||||||
export type invitation_object = {
|
export enum invite_prefill_mode {
|
||||||
key : invitation_key;
|
hidden,
|
||||||
|
locked,
|
||||||
|
free,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export type invite_object = {
|
||||||
|
key : invite_key;
|
||||||
expiry : (null | int);
|
expiry : (null | int);
|
||||||
name_changeable : boolean;
|
membership_number_mode : invite_prefill_mode;
|
||||||
name_value : (null | string);
|
membership_number_value : (null | string);
|
||||||
label_changeable : boolean;
|
name_mode : invite_prefill_mode;
|
||||||
label_value : (null | string);
|
name_value : string;
|
||||||
email_address_changeable : boolean;
|
email_address_mode : invite_prefill_mode;
|
||||||
email_address_value : (null | string);
|
email_address_value : (null | string);
|
||||||
groups_changeable : boolean;
|
groups_mode : invite_prefill_mode;
|
||||||
groups_value : (null | Array<_espe.type.group_id>);
|
groups_value : Array<string>;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
24
tools/build
24
tools/build
|
|
@ -15,21 +15,12 @@
|
||||||
|
|
||||||
import sys as _sys
|
import sys as _sys
|
||||||
import os as _os
|
import os as _os
|
||||||
import shutil as _shutil
|
|
||||||
import argparse as _argparse
|
import argparse as _argparse
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
## args
|
## args
|
||||||
argument_parser = _argparse.ArgumentParser()
|
argument_parser = _argparse.ArgumentParser()
|
||||||
argument_parser.add_argument(
|
|
||||||
"-o",
|
|
||||||
"--output-directory",
|
|
||||||
type = str,
|
|
||||||
default = "/tmp/espe",
|
|
||||||
metavar = "<output-directory>",
|
|
||||||
help = "output directory",
|
|
||||||
)
|
|
||||||
argument_parser.add_argument(
|
argument_parser.add_argument(
|
||||||
"-t",
|
"-t",
|
||||||
"--tests",
|
"--tests",
|
||||||
|
|
@ -38,12 +29,12 @@ def main():
|
||||||
help = "whether to also build the test routines",
|
help = "whether to also build the test routines",
|
||||||
)
|
)
|
||||||
argument_parser.add_argument(
|
argument_parser.add_argument(
|
||||||
"-c",
|
"-o",
|
||||||
"--conf-path",
|
"--output-directory",
|
||||||
type = str,
|
type = str,
|
||||||
default = "",
|
default = "/tmp/espe",
|
||||||
metavar = "<conf-path>",
|
metavar = "<output-directory>",
|
||||||
help = "path to conf file to be put",
|
help = "output directory",
|
||||||
)
|
)
|
||||||
args = argument_parser.parse_args()
|
args = argument_parser.parse_args()
|
||||||
|
|
||||||
|
|
@ -59,11 +50,6 @@ def main():
|
||||||
" ".join(targets),
|
" ".join(targets),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if (args.conf_path != ""):
|
|
||||||
_shutil.copyfile(
|
|
||||||
args.conf_path,
|
|
||||||
_os.path.join(args.output_directory, "conf.json")
|
|
||||||
)
|
|
||||||
_sys.stdout.write("%s\n" % args.output_directory)
|
_sys.stdout.write("%s\n" % args.output_directory)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,6 @@ def main():
|
||||||
"--verbose",
|
"--verbose",
|
||||||
"--exclude='conf.json'",
|
"--exclude='conf.json'",
|
||||||
"--exclude='data.sqlite'",
|
"--exclude='data.sqlite'",
|
||||||
"--exclude='log.jsonl'",
|
|
||||||
("%s/" % args.build_directory),
|
("%s/" % args.build_directory),
|
||||||
(
|
(
|
||||||
("%s" % args.target_directory)
|
("%s" % args.target_directory)
|
||||||
|
|
|
||||||
|
|
@ -48,35 +48,32 @@ ${dir_temp}/espe-core.js ${dir_temp}/espe-core.d.ts: \
|
||||||
${dir_source}/helpers/password.ts \
|
${dir_source}/helpers/password.ts \
|
||||||
${dir_source}/database.ts \
|
${dir_source}/database.ts \
|
||||||
${dir_source}/types.ts \
|
${dir_source}/types.ts \
|
||||||
${dir_source}/repositories/group.ts \
|
|
||||||
${dir_source}/repositories/admin.ts \
|
${dir_source}/repositories/admin.ts \
|
||||||
|
${dir_source}/repositories/name_index.ts \
|
||||||
${dir_source}/repositories/member.ts \
|
${dir_source}/repositories/member.ts \
|
||||||
${dir_source}/repositories/invitation.ts \
|
${dir_source}/repositories/invite.ts \
|
||||||
${dir_source}/services/group.ts \
|
|
||||||
${dir_source}/services/admin.ts \
|
${dir_source}/services/admin.ts \
|
||||||
|
${dir_source}/services/name_index.ts \
|
||||||
${dir_source}/services/member.ts \
|
${dir_source}/services/member.ts \
|
||||||
${dir_source}/services/invitation.ts \
|
${dir_source}/services/invite.ts \
|
||||||
${dir_source}/api/base.ts \
|
${dir_source}/api/base.ts \
|
||||||
${dir_source}/api/actions/meta_ping.ts \
|
${dir_source}/api/actions/meta_ping.ts \
|
||||||
${dir_source}/api/actions/meta_spec.ts \
|
${dir_source}/api/actions/meta_spec.ts \
|
||||||
${dir_source}/api/actions/session_begin.ts \
|
${dir_source}/api/actions/session_begin.ts \
|
||||||
${dir_source}/api/actions/session_end.ts \
|
${dir_source}/api/actions/session_end.ts \
|
||||||
${dir_source}/api/actions/group_list.ts \
|
${dir_source}/api/actions/member_project.ts \
|
||||||
${dir_source}/api/actions/group_read.ts \
|
${dir_source}/api/actions/member_summon.ts \
|
||||||
${dir_source}/api/actions/group_add.ts \
|
${dir_source}/api/actions/member_info.ts \
|
||||||
${dir_source}/api/actions/group_modify.ts \
|
${dir_source}/api/actions/member_register.ts \
|
||||||
${dir_source}/api/actions/member_list.ts \
|
${dir_source}/api/actions/member_list.ts \
|
||||||
${dir_source}/api/actions/member_read.ts \
|
${dir_source}/api/actions/member_read.ts \
|
||||||
${dir_source}/api/actions/member_modify.ts \
|
${dir_source}/api/actions/member_modify.ts \
|
||||||
${dir_source}/api/actions/member_delete.ts \
|
${dir_source}/api/actions/member_delete.ts \
|
||||||
${dir_source}/api/actions/member_password_change_initialize.ts \
|
${dir_source}/api/actions/member_password_change_initialize.ts \
|
||||||
${dir_source}/api/actions/member_password_change_execute.ts \
|
${dir_source}/api/actions/member_password_change_execute.ts \
|
||||||
${dir_source}/api/actions/invitation_list.ts \
|
${dir_source}/api/actions/invite_create.ts \
|
||||||
${dir_source}/api/actions/invitation_read.ts \
|
${dir_source}/api/actions/invite_examine.ts \
|
||||||
${dir_source}/api/actions/invitation_create.ts \
|
${dir_source}/api/actions/invite_accept.ts \
|
||||||
${dir_source}/api/actions/invitation_delete.ts \
|
|
||||||
${dir_source}/api/actions/invitation_examine.ts \
|
|
||||||
${dir_source}/api/actions/invitation_accept.ts \
|
|
||||||
${dir_source}/api/functions.ts \
|
${dir_source}/api/functions.ts \
|
||||||
${dir_source}/conf.ts
|
${dir_source}/conf.ts
|
||||||
@ ${cmd_log} "compile | core …"
|
@ ${cmd_log} "compile | core …"
|
||||||
|
|
@ -89,7 +86,6 @@ main: core ${dir_build}/espe data
|
||||||
${dir_temp}/espe-main-raw.js: \
|
${dir_temp}/espe-main-raw.js: \
|
||||||
${dir_lib}/plankton/plankton.d.ts \
|
${dir_lib}/plankton/plankton.d.ts \
|
||||||
${dir_temp}/espe-core.d.ts \
|
${dir_temp}/espe-core.d.ts \
|
||||||
${dir_source}/sample.ts \
|
|
||||||
${dir_source}/main.ts
|
${dir_source}/main.ts
|
||||||
@ ${cmd_log} "compile | main …"
|
@ ${cmd_log} "compile | main …"
|
||||||
@ ${cmd_mkdir} $(dir $@)
|
@ ${cmd_mkdir} $(dir $@)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue