2025-08-25 14:23:44 +02:00
|
|
|
/*
|
|
|
|
|
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Frontend
|
|
|
|
|
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/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
lib_plankton.zoo_page.register(
|
|
|
|
|
"invitation_handle",
|
|
|
|
|
async (parameters, target_element) => {
|
2025-10-06 18:06:15 +02:00
|
|
|
async function set_state(
|
|
|
|
|
state : ("load" | "fill" | "wait" | "error" | "success"),
|
2025-08-25 14:23:44 +02:00
|
|
|
messages : Array<string> = []
|
2025-10-06 18:06:15 +02:00
|
|
|
) : Promise<void>
|
2025-08-25 14:23:44 +02:00
|
|
|
{
|
|
|
|
|
target_element.querySelector(".invitation_handle").setAttribute("rel", state);
|
|
|
|
|
target_element.querySelector(".invitation_handle-message").textContent = "";
|
2025-10-06 18:06:15 +02:00
|
|
|
const class_ = (() => {
|
|
|
|
|
switch (state)
|
|
|
|
|
{
|
|
|
|
|
case "load": return lib_plankton.zoo_widget.class_panel_info;
|
|
|
|
|
case "wait": return lib_plankton.zoo_widget.class_panel_info;
|
|
|
|
|
case "error": return lib_plankton.zoo_widget.class_panel_error;
|
|
|
|
|
case "success": return lib_plankton.zoo_widget.class_panel_success;
|
|
|
|
|
default: return lib_plankton.zoo_widget.class_panel;
|
2025-08-25 14:23:44 +02:00
|
|
|
}
|
2025-10-06 18:06:15 +02:00
|
|
|
}) ();
|
|
|
|
|
const widget : lib_plankton.zoo_widget.interface_widget = (
|
|
|
|
|
(messages.length <= 0)
|
|
|
|
|
?
|
|
|
|
|
new lib_plankton.zoo_widget.class_empty()
|
|
|
|
|
:
|
|
|
|
|
new class_(
|
|
|
|
|
(
|
|
|
|
|
(messages.length === 1)
|
|
|
|
|
?
|
|
|
|
|
new lib_plankton.zoo_widget.class_string(messages[0])
|
|
|
|
|
:
|
|
|
|
|
new lib_plankton.zoo_widget.class_list(
|
|
|
|
|
messages
|
|
|
|
|
.map(x => new lib_plankton.zoo_widget.class_string(x))
|
|
|
|
|
)
|
|
|
|
|
),
|
|
|
|
|
{
|
|
|
|
|
"collapseable": false,
|
|
|
|
|
"collapsed_initial_value": false,
|
|
|
|
|
}
|
|
|
|
|
)
|
2025-08-25 14:23:44 +02:00
|
|
|
);
|
2025-10-06 18:06:15 +02:00
|
|
|
await widget.load(target_element.querySelector(".invitation_handle-message"));
|
2025-08-25 14:23:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// parameters
|
|
|
|
|
const key : string = parameters["key"];
|
|
|
|
|
|
|
|
|
|
update_nav({"mode": null});
|
2025-10-06 18:06:15 +02:00
|
|
|
target_element.appendChild(_zackeneule.helpers.template_request("invitation_handle"));
|
|
|
|
|
await set_state(
|
2025-08-25 14:23:44 +02:00
|
|
|
"load",
|
|
|
|
|
[
|
2025-10-06 18:06:15 +02:00
|
|
|
lib_plankton.translate.get("common.loading"),
|
2025-08-25 14:23:44 +02:00
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
target_element.querySelector(".invitation_handle-title").textContent = lib_plankton.translate.get("page.invitation_handle.title");
|
|
|
|
|
|
|
|
|
|
let data : (
|
|
|
|
|
null
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
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<int>;
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
try
|
|
|
|
|
{
|
2025-10-06 18:06:15 +02:00
|
|
|
data = await _zackeneule.backend.invitation_examine(key);
|
2025-08-25 14:23:44 +02:00
|
|
|
}
|
|
|
|
|
catch (error)
|
|
|
|
|
{
|
|
|
|
|
data = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (data === null)
|
|
|
|
|
{
|
2025-10-06 18:06:15 +02:00
|
|
|
await set_state(
|
|
|
|
|
"error",
|
2025-08-25 14:23:44 +02:00
|
|
|
[
|
|
|
|
|
lib_plankton.translate.get("page.invitation_handle.message.invalid"),
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-10-06 18:06:15 +02:00
|
|
|
const password_policy : lib_plankton.password.type_policy = await _zackeneule.backend.password_policy();
|
|
|
|
|
const group_data = await _zackeneule.logic.group_data();
|
2025-08-25 14:23:44 +02:00
|
|
|
|
|
|
|
|
const form = new lib_plankton.zoo_form.class_form<
|
|
|
|
|
{
|
|
|
|
|
name : string;
|
|
|
|
|
label : string;
|
|
|
|
|
email_address : (null | string);
|
|
|
|
|
groups : Array<int>;
|
|
|
|
|
password_value : string;
|
|
|
|
|
password_confirmation : string;
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name : string;
|
|
|
|
|
label : string;
|
|
|
|
|
email_address : string;
|
|
|
|
|
groups : Array<int>;
|
|
|
|
|
password_value : string;
|
|
|
|
|
password_confirmation : string;
|
|
|
|
|
}
|
|
|
|
|
>(
|
|
|
|
|
value => ({
|
|
|
|
|
"name": value.name,
|
|
|
|
|
"label": value.label,
|
|
|
|
|
"email_address": (value.email_address ?? ""),
|
|
|
|
|
"groups": value.groups,
|
|
|
|
|
"password_value": value.password_value,
|
|
|
|
|
"password_confirmation": value.password_confirmation,
|
|
|
|
|
}),
|
|
|
|
|
representation => ({
|
|
|
|
|
"name": representation.name,
|
|
|
|
|
"label": representation.label,
|
|
|
|
|
"email_address": representation.email_address,
|
|
|
|
|
"groups": representation.groups,
|
|
|
|
|
"password_value": representation.password_value,
|
|
|
|
|
"password_confirmation": representation.password_confirmation,
|
|
|
|
|
}),
|
|
|
|
|
new lib_plankton.zoo_input.class_input_group(
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
"name": "name",
|
|
|
|
|
"input": new lib_plankton.zoo_input.class_input_text(
|
|
|
|
|
{
|
|
|
|
|
"read_only": (! data.name_changeable),
|
2025-08-25 16:08:35 +02:00
|
|
|
"pattern": "^[a-z0-9_\.]+$",
|
2025-08-25 14:23:44 +02:00
|
|
|
}
|
|
|
|
|
),
|
|
|
|
|
"label": lib_plankton.translate.get("domain.member.name.label"),
|
2025-10-06 18:06:15 +02:00
|
|
|
"help": new lib_plankton.zoo_widget.class_panel_info(
|
|
|
|
|
new lib_plankton.zoo_widget.class_list(
|
|
|
|
|
lib_plankton.translate.get("domain.member.name.help")
|
|
|
|
|
.split("\n\n")
|
|
|
|
|
.map(x => new lib_plankton.zoo_widget.class_string(x))
|
|
|
|
|
),
|
|
|
|
|
{
|
|
|
|
|
"collapseable": true,
|
|
|
|
|
"collapsed_initial_value": true,
|
|
|
|
|
}
|
|
|
|
|
),
|
2025-08-25 14:23:44 +02:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"name": "label",
|
|
|
|
|
"input": new lib_plankton.zoo_input.class_input_text(
|
|
|
|
|
{
|
|
|
|
|
"read_only": (! data.label_changeable),
|
|
|
|
|
}
|
|
|
|
|
),
|
|
|
|
|
"label": lib_plankton.translate.get("domain.member.label.label"),
|
2025-10-06 18:06:15 +02:00
|
|
|
"help": new lib_plankton.zoo_widget.class_panel_info(
|
|
|
|
|
new lib_plankton.zoo_widget.class_list(
|
|
|
|
|
lib_plankton.translate.get("domain.member.label.help")
|
|
|
|
|
.split("\n\n")
|
|
|
|
|
.map(x => new lib_plankton.zoo_widget.class_string(x))
|
|
|
|
|
),
|
|
|
|
|
{
|
|
|
|
|
"collapseable": true,
|
|
|
|
|
"collapsed_initial_value": true,
|
|
|
|
|
}
|
|
|
|
|
),
|
2025-08-25 14:23:44 +02:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"name": "email_address",
|
|
|
|
|
"input": new lib_plankton.zoo_input.class_input_text(
|
|
|
|
|
{
|
|
|
|
|
"read_only": (! data.email_address_changeable),
|
|
|
|
|
}
|
|
|
|
|
),
|
|
|
|
|
"label": lib_plankton.translate.get("domain.member.email_address.label"),
|
2025-10-06 18:06:15 +02:00
|
|
|
"help": new lib_plankton.zoo_widget.class_panel_info(
|
|
|
|
|
new lib_plankton.zoo_widget.class_list(
|
|
|
|
|
lib_plankton.translate.get("domain.member.email_address.help")
|
|
|
|
|
.split("\n\n")
|
|
|
|
|
.map(x => new lib_plankton.zoo_widget.class_string(x))
|
|
|
|
|
),
|
|
|
|
|
{
|
|
|
|
|
"collapseable": true,
|
|
|
|
|
"collapsed_initial_value": true,
|
|
|
|
|
}
|
|
|
|
|
),
|
2025-08-25 14:23:44 +02:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"name": "groups",
|
|
|
|
|
"input": new lib_plankton.zoo_input.class_input_wrapped<Set<string>, Array<int>>(
|
|
|
|
|
new lib_plankton.zoo_input.class_input_set(
|
|
|
|
|
group_data.order.map(
|
|
|
|
|
group_id => group_id.toFixed(0)
|
|
|
|
|
),
|
2025-10-05 23:26:40 +02:00
|
|
|
group_id_encoded => group_data.pool.get(parseInt(group_id_encoded)).label,
|
|
|
|
|
{
|
|
|
|
|
"read_only": (! data.groups_changeable),
|
|
|
|
|
}
|
2025-08-25 14:23:44 +02:00
|
|
|
),
|
|
|
|
|
(value_inner) => {
|
|
|
|
|
const array : Array<int> = [];
|
|
|
|
|
for (const group_id_encoded of value_inner)
|
|
|
|
|
{
|
|
|
|
|
array.push(parseInt(group_id_encoded));
|
|
|
|
|
}
|
|
|
|
|
return array;
|
|
|
|
|
},
|
|
|
|
|
(value_outer) => new Set<string>(value_outer.map(group_id => group_id.toFixed(0)))
|
|
|
|
|
),
|
|
|
|
|
"label": lib_plankton.translate.get("domain.member.groups.label"),
|
2025-10-06 18:06:15 +02:00
|
|
|
"help": new lib_plankton.zoo_widget.class_panel_info(
|
|
|
|
|
new lib_plankton.zoo_widget.class_list(
|
|
|
|
|
(
|
|
|
|
|
lib_plankton.translate.get("domain.member.groups.help")
|
|
|
|
|
.split("\n\n")
|
|
|
|
|
.map(x => new lib_plankton.zoo_widget.class_string(x))
|
|
|
|
|
)
|
|
|
|
|
),
|
|
|
|
|
{
|
|
|
|
|
"collapseable": true,
|
|
|
|
|
"collapsed_initial_value": true,
|
|
|
|
|
}
|
|
|
|
|
),
|
2025-08-25 14:23:44 +02:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"name": "password_value",
|
|
|
|
|
"input": new lib_plankton.zoo_input.class_input_password(
|
2025-10-06 18:06:15 +02:00
|
|
|
{
|
|
|
|
|
"exhibit_initial_value": true,
|
|
|
|
|
}
|
2025-08-25 14:23:44 +02:00
|
|
|
),
|
|
|
|
|
"label": lib_plankton.translate.get("page.invitation_handle.form.field.password_value.label"),
|
2025-10-06 18:06:15 +02:00
|
|
|
"help": new lib_plankton.zoo_widget.class_panel_info(
|
|
|
|
|
new lib_plankton.zoo_widget.class_list(
|
|
|
|
|
(
|
|
|
|
|
lib_plankton.translate.get("page.invitation_handle.form.field.password_value.help")
|
|
|
|
|
.split("\n\n")
|
|
|
|
|
.map<lib_plankton.zoo_widget.interface_widget>(x => new lib_plankton.zoo_widget.class_string(x))
|
|
|
|
|
)
|
|
|
|
|
.concat(
|
|
|
|
|
[
|
|
|
|
|
new _zackeneule.widget.password_policy.class_password_policy(
|
|
|
|
|
password_policy,
|
|
|
|
|
{
|
|
|
|
|
"title": "Richtlinien",
|
|
|
|
|
}
|
|
|
|
|
),
|
|
|
|
|
]
|
|
|
|
|
)
|
|
|
|
|
),
|
|
|
|
|
{
|
|
|
|
|
"collapseable": true,
|
|
|
|
|
"collapsed_initial_value": true,
|
|
|
|
|
}
|
|
|
|
|
),
|
2025-08-25 14:23:44 +02:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"name": "password_confirmation",
|
|
|
|
|
"input": new lib_plankton.zoo_input.class_input_password(
|
|
|
|
|
),
|
|
|
|
|
"label": lib_plankton.translate.get("page.invitation_handle.form.field.password_confirmation.label"),
|
2025-10-06 18:06:15 +02:00
|
|
|
/*
|
|
|
|
|
"help": new lib_plankton.zoo_widget.class_panel_info(
|
|
|
|
|
new lib_plankton.zoo_widget.class_string(
|
|
|
|
|
lib_plankton.translate.get("page.invitation_handle.form.field.password_confirmation.help")
|
|
|
|
|
),
|
|
|
|
|
{
|
|
|
|
|
"collapseable": true,
|
|
|
|
|
"collapsed_initial_value": true,
|
|
|
|
|
}
|
|
|
|
|
),
|
|
|
|
|
*/
|
2025-08-25 14:23:44 +02:00
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
),
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
"label": lib_plankton.translate.get("page.invitation_handle.form.action.submit"),
|
|
|
|
|
"procedure": async (get_value, get_representation) => {
|
|
|
|
|
const value = await get_value();
|
|
|
|
|
let flaws : Array<{incident : string; details : Record<string, any>;}>;
|
2025-10-06 18:06:15 +02:00
|
|
|
await set_state(
|
2025-08-25 14:23:44 +02:00
|
|
|
"wait",
|
|
|
|
|
[
|
2025-10-06 18:06:15 +02:00
|
|
|
lib_plankton.translate.get("common.checking"),
|
2025-08-25 14:23:44 +02:00
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
if (value.password_value !== value.password_confirmation)
|
|
|
|
|
{
|
|
|
|
|
flaws = [
|
|
|
|
|
{"incident": "password_mismatch", "details": {}},
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2025-10-06 18:06:15 +02:00
|
|
|
const flaws_ = await _zackeneule.backend.invitation_accept(
|
2025-08-25 14:23:44 +02:00
|
|
|
key,
|
|
|
|
|
{
|
|
|
|
|
"label": value.label,
|
|
|
|
|
"name": value.name,
|
|
|
|
|
"email_address": value.email_address,
|
|
|
|
|
"groups": value.groups,
|
|
|
|
|
"password": value.password_value,
|
|
|
|
|
}
|
|
|
|
|
);
|
2025-10-06 18:06:15 +02:00
|
|
|
flaws = (
|
|
|
|
|
(
|
|
|
|
|
flaws_
|
|
|
|
|
.filter(
|
|
|
|
|
flaw => (! flaw.incident.startsWith("password_"))
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
.concat(
|
|
|
|
|
(flaws_.find(flaw => flaw.incident.startsWith("password_")) !== undefined)
|
|
|
|
|
?
|
|
|
|
|
[{"incident": "password_invalid", "details": {}}]
|
|
|
|
|
:
|
|
|
|
|
[]
|
|
|
|
|
)
|
|
|
|
|
);
|
2025-08-25 14:23:44 +02:00
|
|
|
}
|
|
|
|
|
catch (error)
|
|
|
|
|
{
|
|
|
|
|
flaws = [
|
|
|
|
|
{"incident": "unhandled_error", "details": {}},
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (flaws.length > 0)
|
|
|
|
|
{
|
2025-10-06 18:06:15 +02:00
|
|
|
await set_state(
|
|
|
|
|
"error",
|
2025-08-25 14:23:44 +02:00
|
|
|
flaws.map(
|
|
|
|
|
flaw => lib_plankton.string.coin(
|
|
|
|
|
lib_plankton.translate.get("page.invitation_handle.flaw." + flaw.incident),
|
|
|
|
|
flaw.details
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-10-06 18:06:15 +02:00
|
|
|
await set_state(
|
|
|
|
|
"success",
|
2025-08-25 14:23:44 +02:00
|
|
|
[
|
|
|
|
|
lib_plankton.translate.get("page.invitation_handle.message.successful"),
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
await form.setup(target_element.querySelector(".invitation_handle-form") as HTMLElement);
|
|
|
|
|
form.input_write(
|
|
|
|
|
{
|
|
|
|
|
"name": data.name_value,
|
|
|
|
|
"label": data.label_value,
|
|
|
|
|
"email_address": data.email_address_value,
|
|
|
|
|
"groups": data.groups_value,
|
2025-10-06 18:06:15 +02:00
|
|
|
"password_value": lib_plankton.password.generate(password_policy),
|
2025-08-25 14:23:44 +02:00
|
|
|
"password_confirmation": "",
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
set_state(
|
|
|
|
|
"fill",
|
|
|
|
|
[
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
);
|