From ba21a1c6327a20fefc943e15681b26de96f7c70b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Mon, 29 Apr 2024 20:48:20 +0200 Subject: [PATCH] [int] --- source/api/actions/member_create.ts | 58 ++--- source/api/actions/member_read.ts | 38 +-- source/api/functions.ts | 2 +- source/repositories/member.ts | 192 ++++++++++++++ source/repositories/name_index.ts | 74 ++++++ .../{service-member.ts => services/member.ts} | 243 ++++-------------- source/services/name_index.ts | 16 ++ source/types/member.ts | 25 ++ tools/makefile | 6 +- 9 files changed, 413 insertions(+), 241 deletions(-) create mode 100644 source/repositories/member.ts create mode 100644 source/repositories/name_index.ts rename source/{service-member.ts => services/member.ts} (51%) create mode 100644 source/services/name_index.ts create mode 100644 source/types/member.ts diff --git a/source/api/actions/member_create.ts b/source/api/actions/member_create.ts index e4ce03d..9dffde1 100644 --- a/source/api/actions/member_create.ts +++ b/source/api/actions/member_create.ts @@ -7,10 +7,13 @@ namespace _espe.api rest_subject : lib_plankton.rest.type_rest ) : void { - lib_plankton.rest.register<_espe.service.member.type_value, _espe.service.member.type_id>( + lib_plankton.rest.register< + _espe.service.member.type_value, + _espe.service.member.type_id + >( rest_subject, lib_plankton.http.enum_method.post, - "/member", + "/member/create", { "description": "erstellt ein neues Mitglied und gibt die erzeugte ID aus", "input_schema": () => ({ @@ -18,54 +21,43 @@ namespace _espe.api "nullable": false, "additionalProperties": false, "properties": { - "name": { + "membership_number": { "type": "string", "nullable": false, }, - "password_image": { + "name_real_value": { + "type": "string", + "nullable": false, + }, + "email_address_private_value": { "type": "string", "nullable": true, }, - "email_address": { - "type": "string", - "nullable": true, - }, - "data": { - "type": "object", - "nullable": true, - "properties": { - }, - "additionalPropertis": { - "type": "string", - "nullable": false, - }, - "required": [ - ] - }, }, "required": [ - "name", + "membership_number", + "name_real_value", ] }), "output_schema": () => ({ - "type": "integer", + "type": "number", "nullable": false, }), "restriction": restriction_logged_in, "execution": async ({"input": input}) => { const member_value : _espe.service.member.type_value = { + "membership_number": input.membership_number, + "name_real_value": input.name_real_value, + "name_real_extension": null, + "email_address_private_value": input.email_address_private_value, "enabled": false, - "membership_number": input["membership_number"], - "name_real_value": input["name_real_value"], - "name_real_extension": input["name_real_extension"], - "name_display": input["name_display"], - "name_login": input["name_login"], - "password_image": input["password_image"], - "email_address_private_value": input["email_address_private_value"], - "email_address_numberbased_use": input["email_address_numberbased_use"], - "email_address_namebased_use": input["email_address_namebased_use"], - "email_redirect_to_private": input["email_redirect_to_private"], - "salutation": input["salutation"], + "name_display": null, + "name_login": null, + "password_image": null, + "email_address_numberbased_use": false, + "email_address_namebased_use": false, + "email_redirect_to_private": false, + "salutation": null, "registered": false, }; const member_id : _espe.service.member.type_id = await _espe.service.member.add(member_value); diff --git a/source/api/actions/member_read.ts b/source/api/actions/member_read.ts index c7fd4e3..987e158 100644 --- a/source/api/actions/member_read.ts +++ b/source/api/actions/member_read.ts @@ -7,36 +7,36 @@ namespace _espe.api rest_subject : lib_plankton.rest.type_rest ) : void { - // todo: genauerer Ausgabe-Typ - lib_plankton.rest.register( + lib_plankton.rest.register< + int, + _espe.service.member.type_value + >( rest_subject, lib_plankton.http.enum_method.get, - "/member/:id", + "/member/read", { "description": "gibt ein Mitglied anhand seiner ID aus", + "input_schema": () => ({ + "nullable": false, + "type": "number" + }), + // TODO "output_schema": () => ({ "nullable": false, + "type": "object", + "properties": { + }, + "additionalProperties": false, + "required": [ + ] }), "restriction": restriction_logged_in, - "execution": async ({"path_parameters": path_parameters}) => { - const member_id : _espe.service.member.type_id = parseInt(path_parameters["id"]); + "execution": async ({"input": input}) => { + const member_id : _espe.service.member.type_id = input; const member_value : _espe.service.member.type_value = await _espe.service.member.get(member_id); return Promise.resolve({ "status_code": 200, - "data": { - "membership_number": member_value.membership_number, - "enabled": member_value.enabled, - "name_real_value": member_value.name_real_value, - "name_real_extension": member_value.name_real_extension, - "name_display": member_value.name_display, - "name_login": member_value.name_login, - "password_image": member_value.password_image, - "email_address_private_value": member_value.email_address_private_value, - "email_address_numberbased_use": member_value.email_address_numberbased_use, - "email_address_namebased_use": member_value.email_address_namebased_use, - "email_redirect_to_private": member_value.email_redirect_to_private, - "salutation": member_value.salutation, - }, + "data": member_value, }); } } diff --git a/source/api/functions.ts b/source/api/functions.ts index 03b622c..525c09a 100644 --- a/source/api/functions.ts +++ b/source/api/functions.ts @@ -35,7 +35,7 @@ namespace _espe.api _espe.api.register_member_list(rest_subject); _espe.api.register_member_read(rest_subject); _espe.api.register_member_create(rest_subject); - _espe.api.register_member_update(rest_subject); + // _espe.api.register_member_update(rest_subject); // _espe.api.register_member_delete(rest_subject); _espe.api.register_member_get(rest_subject); _espe.api.register_member_register(rest_subject); diff --git a/source/repositories/member.ts b/source/repositories/member.ts new file mode 100644 index 0000000..bdefafb --- /dev/null +++ b/source/repositories/member.ts @@ -0,0 +1,192 @@ +namespace _espe.repository.member +{ + + /** + */ + var _store : ( + null + | + lib_plankton.storage.type_store< + _espe.type.member.id, + Record, + {}, + lib_plankton.storage.type_sql_table_autokey_search_term, + Record + > + ) = null; + + + /** + */ + function get_store( + ) : lib_plankton.storage.type_store< + _espe.type.member.id, + Record, + {}, + lib_plankton.storage.type_sql_table_autokey_search_term, + Record + > + { + if (_store === null) { + _store = lib_plankton.storage.sql_table_autokey_store( + { + "database_implementation": _espe.helpers.database_implementation(), + "table_name": "members", + "key_name": "id", + } + ); + } + else { + // do nothing + } + return _store; + } + + + /** + */ + function encode( + object : _espe.type.member.object + ) : Record + { + return { + "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, + }; + } + + + /** + */ + function decode( + row : Record + ) : _espe.type.member.object + { + return { + "membership_number": row["membership_number"], + "name_real_value": row["name_real_value"], + "name_real_index": row["name_real_index"], + "email_address_private": row["email_address_private"], + "registered": (row["registered"] > 0), + "enabled": (row["enabled"] > 0), + "email_use_veiled_address": (row["email_use_veiled_address"] > 0), + "email_use_nominal_address": (row["email_use_nominal_address"] > 0), + "email_redirect_to_private_address": (row["email_redirect_to_private_address"] > 0), + "email_allow_sending": (row["email_allow_sending"] > 0), + "password_image": row["password_image"], + }; + } + + + /** + */ + export async function dump( + ) : Promise< + Array< + { + id : _espe.type.member.id; + value : _espe.type.member.object; + } + > + > + { + return ( + (await get_store().search(null)) + .map( + ({"key": key, "preview": preview}) => ({ + "id": key, + "value": (preview as _espe.type.member.object), + }) + ) + ); + } + + + /** + */ + export async function list( + ) : Promise< + Array< + { + id : _espe.type.member.id; + preview : { + membership_number : string, + name_real : string; + }; + } + > + > + { + return ( + (await get_store().search(null)) + .map( + ({"key": key, "preview": preview}) => ({ + "id": key, + "preview": { + "membership_number": preview["membership_number"], + "name_real": preview["name_real"], + } + }) + ) + ); + } + + + /** + */ + export async function read( + id : _espe.type.member.id + ) : Promise<_espe.type.member.object> + { + const row : Record = await get_store().read(id); + + return decode(row); + } + + + /** + */ + export async function create( + value : _espe.type.member.object + ) : Promise<_espe.type.member.id> + { + const row : Record = encode(value); + const id : _espe.type.member.id = await get_store().create(row); + + return id; + } + + + /** + */ + export async function update( + id : _espe.type.member.id, + value : _espe.type.member.object + ) : Promise + { + const row : Record = encode(value); + + await get_store().update(id, row); + } + + + /** + */ + export async function delete( + id : _espe.type.member.id + ) : Promise + { + await get_store().delete(id); + } + +} + diff --git a/source/repositories/name_index.ts b/source/repositories/name_index.ts new file mode 100644 index 0000000..02e851d --- /dev/null +++ b/source/repositories/name_index.ts @@ -0,0 +1,74 @@ +namespace _espe.repository.member +{ + + /** + */ + var _chest : ( + null + | + lib_plankton.storage.type_chest< + Array, + Record, + lib_plankton.database.type_description_create_table, + lib_plankton.storage.type_sql_table_common_search_term, + Record + > + ) = null; + + + /** + */ + function get_chest( + ) : lib_plankton.storage.type_chest< + Array, + Record, + lib_plankton.database.type_description_create_table, + lib_plankton.storage.type_sql_table_common_search_term, + Record + > + { + 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; + } + + + /** + */ + export async function read( + name : string + ) : Promise + { + let row : Record; + try { + row = await get_chest().read(name); + return row["index"]; + } + catch (error) { + return 0; + } + } + + + /** + */ + export async function write( + name : string, + index : int + ) : Promise + { + return get_chest().write(name, index); + } + +} + diff --git a/source/service-member.ts b/source/services/member.ts similarity index 51% rename from source/service-member.ts rename to source/services/member.ts index 95052a2..ce79cf7 100644 --- a/source/service-member.ts +++ b/source/services/member.ts @@ -1,30 +1,6 @@ namespace _espe.service.member { - /** - */ - export type type_id = int; - - - /** - */ - export type type_value = { - membership_number : string; - enabled : boolean; - name_real_value : string; - name_real_extension : (null | string); - name_display : (null | string); - name_login : string; - password_image : (null | string); - email_address_private_value : (null | string); - email_address_numberbased_use : boolean; - email_address_namebased_use : boolean; - email_redirect_to_private : boolean; - salutation : (null | string); - registered : boolean; - }; - - /** */ var _hooks_change : Array<() => void> = []; @@ -55,176 +31,78 @@ namespace _espe.service.member /** */ - function store( - ) : lib_plankton.storage.type_store, {}, lib_plankton.storage.type_sql_table_autokey_search_term, Record> + export async function draft( + data : { + membership_number : string; + name_real_value : string; + email_address_private : (null | string); + } + ) : Promise<_espe.type.member.id> { - const store : lib_plankton.storage.type_store, {}, lib_plankton.storage.type_sql_table_autokey_search_term, Record> = lib_plankton.storage.sql_table_autokey_store( - { - "database_implementation": _espe.helpers.database_implementation(), - "table_name": "members", - "key_name": "id", - } - ); - return store; - } - - - /** - */ - function encode( - value : type_value - ) : Record - { - return { - "membership_number": value.membership_number, - "enabled": (value.enabled ? 1 : 0), - "name_real_value": value.name_real_value, - "name_real_extension": value.name_real_extension, - "name_display": value.name_display, - "name_login": value.name_login, - "password_image": value.password_image, - "email_address_private_value": value.email_address_private_value, - "email_address_numberbased_use": (value.email_address_numberbased_use ? 1 : 0), - "email_address_namebased_use": (value.email_address_namebased_use ? 1 : 0), - "email_redirect_to_private": (value.email_redirect_to_private ? 1 : 0), - "salutation": value.salutation, - "registered": (value.registered ? 1 : 0), + const name_real_index : int = await _espe.service.name_index.next(object.name_real_value); + const object : _espe.type.member.object = { + "membership_number": data.membership_number, + "name_real_value": data.name_real_value, + "name_real_index": name_real_index, + "email_address_private": data.email_address_private, + "registered": false, + "enabled": false, + "email_use_veiled_address": false, + "email_use_nominal_address": false, + "email_redirect_to_private_address": false, + "email_allow_sending": false, + "password_image": null, }; - } - - - /** - */ - function decode( - row : Record - ) : type_value - { - return { - "membership_number": row["membership_number"], - "enabled": (row["enabled"] > 0), - "name_real_value": row["name_real_value"], - "name_real_extension": row["name_real_extension"], - "name_display": row["name_display"], - "name_login": row["name_login"], - "password_image": row["password_image"], - "email_address_private_value": row["email_address_private_value"], - "email_address_numberbased_use": (row["email_address_numberbased_use"] > 0), - "email_address_namebased_use": (row["email_address_namebased_use"] > 0), - "email_redirect_to_private": (row["email_redirect_to_private"] > 0), - "salutation": row["salutation"], - "registered": (row["registered"] > 0), - }; - } - - - /** - */ - export async function dump( - ) : Promise> - { - const my_store = store(); - - return ( - (await my_store.search(null)) - .map( - ({"key": key, "preview": preview}) => ({ - "id": key, - "value": (preview as type_value), - }) - ) - ); - } - - - /** - */ - export async function list( - ) : Promise> - { - const my_store = store(); - - return ( - (await my_store.search(null)) - .map( - ({"key": key, "preview": preview}) => ({ - "id": key, - "preview": { - "membership_number": preview["membership_number"], - "name_real_value": preview["name_real_value"], - } - }) - ) - ); - } - - - /** - * @todo data - */ - export async function get( - id : type_id - ) : Promise - { - const my_store = store(); - - const row : Record = await my_store.read(id); - - return decode(row); - } - - - /** - */ - export async function add( - value : type_value - ) : Promise - { - const my_store = store(); - - const row : Record = encode(value); - const id : type_id = await my_store.create(row); - + const id : _espe.type.member.id = _espe.repository.member.create(object); notify_change(); - return id; } - /** - */ + /* + export async function dump( + ) : Promise> + { + return _espe.repository.member.dump(); + } + + + export async function list( + ) : Promise> + { + return _espe.repository.member.list(); + } + + + export async function get( + id : _espe.type.member.id + ) : Promise<_espe.type.member.object> + { + return _espe.repository.member.read(id); + } + + export async function modify( - id : type_id, - value : type_value + id : _espe.type.member.id, + object : _espe.type.member.object ) : Promise { - const my_store = store(); - - const row : Record = encode(value); - - await my_store.update(id, row); - + await _espe.repository.member.update(id, object); notify_change(); } - /** - */ export async function remove( - id : type_id + id : _espe.type.member.id ) : Promise { - const my_store = store(); - - await my_store.delete(id); - + await _espe.repository.member.delete(id); notify_change(); } - /** - */ export async function register( - id : type_id, + id : _espe.type.member.id, data : { name_login : string; name_display : string; @@ -236,7 +114,7 @@ namespace _espe.service.member } ) : Promise { - const member : type_value = await get(id); + const member : _espe.type.member.object = await get(id); if (member.name_login !== null) { return Promise.reject(new Error("already registered")); @@ -256,10 +134,8 @@ namespace _espe.service.member } - /** - */ export function derive_login_name( - value : type_value + value : _espe.type.member.object ) : string { return lib_plankton.string.coin( @@ -280,10 +156,8 @@ namespace _espe.service.member } - /** - */ export function derive_email_address_namely( - value : type_value + value : _espe.type.member.object ) : string { return lib_plankton.string.coin( @@ -305,10 +179,8 @@ namespace _espe.service.member } - /** - */ export function derive_email_address_numerical( - value : type_value + value : _espe.type.member.object ) : string { return lib_plankton.string.coin( @@ -322,10 +194,8 @@ namespace _espe.service.member } - /** - */ function derive_email_address_to_use( - value : type_value + value : _espe.type.member.object ) : (null | string) { return ( @@ -340,9 +210,7 @@ namespace _espe.service.member } - /** * @todo check validity (e.g. username characters) - */ export async function export_authelia_user_file( ) : Promise { @@ -400,6 +268,7 @@ namespace _espe.service.member ] ); } + */ } diff --git a/source/services/name_index.ts b/source/services/name_index.ts new file mode 100644 index 0000000..0697697 --- /dev/null +++ b/source/services/name_index.ts @@ -0,0 +1,16 @@ +namespace _espe.service.name_index +{ + + /** + */ + export async function next( + name : string + ) : Promise + { + 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; + } + +} diff --git a/source/types/member.ts b/source/types/member.ts new file mode 100644 index 0000000..a29acdd --- /dev/null +++ b/source/types/member.ts @@ -0,0 +1,25 @@ +namespace _espe.type.member +{ + + /** + */ + export type id = int; + + + /** + */ + export type object = { + membership_number : string; + name_real_value : string; + name_real_index : string; + email_address_private : (null | string); + registered : 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); + }; + +} diff --git a/tools/makefile b/tools/makefile index 0666240..5c1e3ea 100644 --- a/tools/makefile +++ b/tools/makefile @@ -28,7 +28,11 @@ ${dir_temp}/espe-unlinked.js: \ ${dir_lib}/plankton/plankton.d.ts \ ${dir_source}/helpers.ts \ ${dir_source}/database.ts \ - ${dir_source}/service-member.ts \ + ${dir_source}/types/member.ts \ + ${dir_source}/repositories/name_index.ts \ + ${dir_source}/repositories/member.ts \ + ${dir_source}/services/name_index.ts \ + ${dir_source}/services/member.ts \ ${dir_source}/service-admin.ts \ ${dir_source}/api/base.ts \ ${dir_source}/api/actions/session_begin.ts \