From c755a6c9c85db0d01a606dd542475c0c2a1d1cbc Mon Sep 17 00:00:00 2001 From: Gavin Jaeger-Freeborn Date: Wed, 31 Jul 2024 15:34:02 -0700 Subject: [PATCH 1/5] Add REST endpoints for hard deleting tenants Signed-off-by: Gavin Jaeger-Freeborn --- .../v1_0/innkeeper/routes.py | 51 +++++++++++++++---- .../traction_innkeeper/v1_0/tenant/routes.py | 28 ++++++++++ 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/plugins/traction_innkeeper/traction_innkeeper/v1_0/innkeeper/routes.py b/plugins/traction_innkeeper/traction_innkeeper/v1_0/innkeeper/routes.py index c763a8d14..89eac03c2 100644 --- a/plugins/traction_innkeeper/traction_innkeeper/v1_0/innkeeper/routes.py +++ b/plugins/traction_innkeeper/traction_innkeeper/v1_0/innkeeper/routes.py @@ -809,7 +809,35 @@ async def innkeeper_tenant_delete(request: web.BaseRequest): return web.json_response({"success": f"Tenant {tenant_id} soft deleted."}) else: raise web.HTTPNotFound(reason=f"Tenant {tenant_id} not found.") - + + +@docs( + tags=[SWAGGER_CATEGORY], +) +@match_info_schema(TenantIdMatchInfoSchema()) +@response_schema(TenantRecordSchema(), 200, description="") +@innkeeper_only +@error_handler +async def innkeeper_tenant_hard_delete(request: web.BaseRequest): + context: AdminRequestContext = request["context"] + tenant_id = request.match_info["tenant_id"] + + mgr = context.inject(TenantManager) + profile = mgr.profile + async with profile.session() as session: + rec = await TenantRecord.retrieve_by_id(session, tenant_id) + if rec: + multitenant_mgr = context.profile.inject(BaseMultitenantManager) + wallet_id = rec.wallet_id + wallet_record = await WalletRecord.retrieve_by_id(session, wallet_id) + + await multitenant_mgr.remove_wallet(wallet_id) + await rec.delete_record(session) + LOGGER.info("Tenant %s rd deleted.", tenant_id) + return web.json_response({"success": f"Tenant {tenant_id} hard deleted."}) + else: + raise web.HTTPNotFound(reason=f"Tenant {tenant_id} not found.") + @docs( tags=[SWAGGER_CATEGORY], @@ -822,10 +850,10 @@ async def innkeeper_tenant_delete(request: web.BaseRequest): async def innkeeper_tenant_restore(request: web.BaseRequest): context: AdminRequestContext = request["context"] tenant_id = request.match_info["tenant_id"] - + mgr = context.inject(TenantManager) profile = mgr.profile - + async with profile.session() as session: rec = await TenantRecord.retrieve_by_id(session, tenant_id) if rec: @@ -837,7 +865,7 @@ async def innkeeper_tenant_restore(request: web.BaseRequest): return web.json_response({"success": f"Tenant {tenant_id} restored."}) else: raise web.HTTPNotFound(reason=f"Tenant {tenant_id} not found.") - + @docs(tags=[SWAGGER_CATEGORY], summary="Create API Key Record") @request_schema(TenantAuthenticationsApiRequestSchema()) @@ -960,9 +988,7 @@ async def innkeeper_config_handler(request: web.BaseRequest): profile = mgr.profile config = { - key: ( - profile.context.settings[key] - ) + key: (profile.context.settings[key]) for key in profile.context.settings if key not in [ @@ -975,9 +1001,13 @@ async def innkeeper_config_handler(request: web.BaseRequest): ] } try: - del config["plugin_config"]["traction_innkeeper"]["innkeeper_wallet"]["wallet_key"] + del config["plugin_config"]["traction_innkeeper"]["innkeeper_wallet"][ + "wallet_key" + ] except KeyError as e: - LOGGER.warn(f"The key to be removed: '{e.args[0]}' is missing from the dictionary.") + LOGGER.warn( + f"The key to be removed: '{e.args[0]}' is missing from the dictionary." + ) config["version"] = __version__ return web.json_response({"config": config}) @@ -1033,6 +1063,9 @@ async def register(app: web.Application): ), web.put("/innkeeper/tenants/{tenant_id}/config", tenant_config_update), web.delete("/innkeeper/tenants/{tenant_id}", innkeeper_tenant_delete), + web.delete( + "/innkeeper/tenants/{tenant_id}/hard", innkeeper_tenant_hard_delete + ), web.put("/innkeeper/tenants/{tenant_id}/restore", innkeeper_tenant_restore), web.get( "/innkeeper/default-config", diff --git a/plugins/traction_innkeeper/traction_innkeeper/v1_0/tenant/routes.py b/plugins/traction_innkeeper/traction_innkeeper/v1_0/tenant/routes.py index 993403793..87d9f4c85 100644 --- a/plugins/traction_innkeeper/traction_innkeeper/v1_0/tenant/routes.py +++ b/plugins/traction_innkeeper/traction_innkeeper/v1_0/tenant/routes.py @@ -80,6 +80,7 @@ class TenantLedgerIdConfigSchema(OpenAPISchema): required=True, ) + @web.middleware async def setup_tenant_context(request: web.Request, handler): """Middle ware to extract tenant_id and provide it to log formatter @@ -465,6 +466,32 @@ async def tenant_server_config_handler(request: web.BaseRequest): return web.json_response({"config": config}) +@docs( + tags=[SWAGGER_CATEGORY], +) +@response_schema(TenantRecordSchema(), 200, description="") +@error_handler +async def tenant_delete(request: web.BaseRequest): + context: AdminRequestContext = request["context"] + wallet_id = context.profile.settings.get("wallet.id") + + mgr = context.inject(TenantManager) + profile = mgr.profile + async with profile.session() as session: + rec = await TenantRecord.query_by_wallet_id(session, wallet_id) + if rec: + multitenant_mgr = context.profile.inject(BaseMultitenantManager) + + await multitenant_mgr.remove_wallet(rec.wallet_id) + await rec.delete_record(session) + LOGGER.info("Tenant %s rd deleted.", rec.tenant_id) + return web.json_response(rec.serialize()) + else: + raise web.HTTPNotFound( + reason=f"Tenant with wallet id {wallet_id} not found." + ) + + async def register(app: web.Application): """Register routes.""" LOGGER.info("> registering routes") @@ -499,6 +526,7 @@ async def register(app: web.Application): tenant_server_config_handler, allow_head=False, ), + web.delete("/tenant", tenant_delete), ] ) LOGGER.info("< registering routes") From 2a0efae55b1ec8d0f4905ee99e0b6c966ca44a8f Mon Sep 17 00:00:00 2001 From: Gavin Jaeger-Freeborn Date: Wed, 31 Jul 2024 15:34:51 -0700 Subject: [PATCH 2/5] Add options for hard deleting tenants in tenant UI Signed-off-by: Gavin Jaeger-Freeborn --- .../deleteTenant/ConfirmTenantDeletion.vue | 18 +++++++++++-- .../frontend/src/helpers/constants.ts | 2 ++ .../store/innkeeper/innkeeperTenantsStore.ts | 16 +++++++++++ .../frontend/src/store/tenantStore.ts | 20 ++++++++++++++ .../frontend/src/views/tenant/Profile.vue | 27 ++++++++++++++++++- 5 files changed, 80 insertions(+), 3 deletions(-) diff --git a/services/tenant-ui/frontend/src/components/innkeeper/tenants/deleteTenant/ConfirmTenantDeletion.vue b/services/tenant-ui/frontend/src/components/innkeeper/tenants/deleteTenant/ConfirmTenantDeletion.vue index 88a658761..d93766ab7 100644 --- a/services/tenant-ui/frontend/src/components/innkeeper/tenants/deleteTenant/ConfirmTenantDeletion.vue +++ b/services/tenant-ui/frontend/src/components/innkeeper/tenants/deleteTenant/ConfirmTenantDeletion.vue @@ -14,11 +14,19 @@ placeholder="Type the tenant name here" class="w-full mb-4" /> + +
+ + +
+