/* 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 . */ namespace _espe.repository.member { /** */ type type_group_chest = lib_plankton.storage.type_chest< Array, Record, lib_plankton.database.type_description_create_table, lib_plankton.storage.sql_table_common.type_sql_table_common_search_term, Record >; /** */ var _core_store : ( null | lib_plankton.storage.type_store< _espe.type.member_id, Record, {}, lib_plankton.storage.type_sql_table_autokey_search_term, Record > ) = null; /** */ var _group_chest : ( null | type_group_chest ) = null; /** */ function get_core_store( ) : lib_plankton.storage.type_store< _espe.type.member_id, Record, {}, lib_plankton.storage.type_sql_table_autokey_search_term, Record > { if (_core_store === null) { _core_store = lib_plankton.storage.sql_table_autokey_store( { "database_implementation": _espe.helpers.database_implementation(), "table_name": "members", "key_name": "id", } ); } else { // do nothing } return _core_store; } /** */ function get_group_chest( ) : type_group_chest { if (_group_chest === null) { _group_chest = lib_plankton.storage.sql_table_common.chest( { "database_implementation": _espe.helpers.database_implementation(), "table_name": "member_groups", "key_names": ["member_id","group_name"], } ); } else { // do nothing } return _group_chest; } /** */ type type_dispersal = { core_row : Record; group_rows : Array< Record >; }; /** */ function encode( object : _espe.type.member_object ) : type_dispersal { return { "core_row": { "membership_number": object.membership_number, "name_real_value": object.name_real_value, "name_real_index": object.name_real_index, "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_change_last_attempt": object.password_change_last_attempt, "password_change_token": object.password_change_token, }, "group_rows": ( object.groups .map( group => ({ "group_name": group, }) ) ) }; } /** */ function decode( dispersal : type_dispersal ) : _espe.type.member_object { return { "membership_number": dispersal.core_row["membership_number"], "name_real_value": dispersal.core_row["name_real_value"], "name_real_index": dispersal.core_row["name_real_index"], "email_address_private": dispersal.core_row["email_address_private"], "groups": lib_plankton.list.sorted( dispersal.group_rows.map(row => row["group_name"]), { "compare_element": (group1, group2) => (group1 <= group2) } ), "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_change_last_attempt": dispersal.core_row["password_change_last_attempt"], "password_change_token": dispersal.core_row["password_change_token"], }; } /** * @todo optimize */ export async function list( search_term : (null | string) ) : Promise< Array< { id : _espe.type.member_id; preview : { membership_number : string; name_real_value : string; name_real_index : int; }; } > > { return ( (await get_core_store().search(null)) .filter( ({"key": key, "preview": preview}) => ( ( (search_term === null) || (search_term.length <= 1) ) ? true : ( preview["membership_number"].toLowerCase().includes(search_term.toLowerCase()) || preview["name_real_value"].toLowerCase().includes(search_term.toLowerCase()) ) ) ) .map( ({"key": key, "preview": preview}) => ({ "id": key, "preview": { "membership_number": preview["membership_number"], "name_real_value": preview["name_real_value"], "name_real_index": preview["name_real_index"], } }) ) ); } /** */ export async function read( id : _espe.type.member_id ) : Promise<_espe.type.member_object> { const core_row : Record = await get_core_store().read(id); const group_hits : Array<{key : Record; preview : Record;}> = await get_group_chest().search( { "expression": "member_id = $member_id", "arguments": {"member_id": id} } ); const dispersal : type_dispersal = { "core_row": core_row, "group_rows": group_hits.map( hit => ({ "group_name": hit.preview["group_name"] }) ), }; return decode(dispersal); } /** */ export async function create( value : _espe.type.member_object ) : Promise<_espe.type.member_id> { const dispersal : type_dispersal = encode(value); // core const id : _espe.type.member_id = await get_core_store().create(dispersal.core_row); // groups for await (const group_row of dispersal.group_rows) { await get_group_chest().write( [ id, group_row["group_name"], ], { "_dummy": null, } ); } return id; } /** * @todo replace groups smartly */ export async function update( id : _espe.type.member_id, value : _espe.type.member_object ) : Promise { const dispersal : type_dispersal = encode(value); // core await get_core_store().update(id, dispersal.core_row); // groups const hits : Array<{key : Array; preview : Record;}> = await get_group_chest().search( { "expression": "member_id = $member_id", "arguments": {"member_id": id} } ); lib_plankton.log.info("update_hit", hits); for (const hit of hits) { await get_group_chest().delete(hit.key); } for await (const group_row of dispersal.group_rows) { await get_group_chest().write( [ id, group_row["group_name"], ], { "_dummy": null, } ); } } /** */ export async function delete_( id : _espe.type.member_id ) : Promise { // groups const hits : Array<{key : Array; preview : Record;}> = await get_group_chest().search( { "expression": "member_id = $member_id", "arguments": {"member_id": id} } ); for (const hit of hits) { await get_group_chest().delete(hit.key); } // core await get_core_store().delete(id); } /** */ export async function dump( ) : Promise< Array< { id : _espe.type.member_id; object : _espe.type.member_object; } > > { return ( Promise.all( (await get_core_store().search(null)) .map(hit => hit.key) .map( id => ( read(id) .then( (object) => ({ "id": id, "object": object }) ) ) ) ) ); } }