From 5ce5b3cc2cd2735a2d3073bde287a07a1342db65 Mon Sep 17 00:00:00 2001 From: Gurjeet Matharu Date: Mon, 30 Oct 2023 15:36:45 -0700 Subject: [PATCH 1/6] ui work for deletion of a tenant Signed-off-by: Gurjeet Matharu --- .../components/innkeeper/tenants/Tenants.vue | 11 ++- .../deleteTenant/ConfirmTenantDeletion.vue | 74 +++++++++++++++++++ .../tenants/deleteTenant/DeleteTenant.vue | 53 +++++++++++++ .../frontend/src/plugins/i18n/locales/en.json | 3 +- .../frontend/src/plugins/i18n/locales/fr.json | 3 +- .../frontend/src/plugins/i18n/locales/ja.json | 3 +- .../store/innkeeper/innkeeperTenantsStore.ts | 22 ++++++ 7 files changed, 165 insertions(+), 4 deletions(-) create mode 100644 services/tenant-ui/frontend/src/components/innkeeper/tenants/deleteTenant/ConfirmTenantDeletion.vue create mode 100644 services/tenant-ui/frontend/src/components/innkeeper/tenants/deleteTenant/DeleteTenant.vue diff --git a/services/tenant-ui/frontend/src/components/innkeeper/tenants/Tenants.vue b/services/tenant-ui/frontend/src/components/innkeeper/tenants/Tenants.vue index 80cbe3ab9..a390f3978 100644 --- a/services/tenant-ui/frontend/src/components/innkeeper/tenants/Tenants.vue +++ b/services/tenant-ui/frontend/src/components/innkeeper/tenants/Tenants.vue @@ -33,7 +33,10 @@ + 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 new file mode 100644 index 000000000..805119deb --- /dev/null +++ b/services/tenant-ui/frontend/src/components/innkeeper/tenants/deleteTenant/ConfirmTenantDeletion.vue @@ -0,0 +1,74 @@ + + + diff --git a/services/tenant-ui/frontend/src/components/innkeeper/tenants/deleteTenant/DeleteTenant.vue b/services/tenant-ui/frontend/src/components/innkeeper/tenants/deleteTenant/DeleteTenant.vue new file mode 100644 index 000000000..809a44ac9 --- /dev/null +++ b/services/tenant-ui/frontend/src/components/innkeeper/tenants/deleteTenant/DeleteTenant.vue @@ -0,0 +1,53 @@ + + + diff --git a/services/tenant-ui/frontend/src/plugins/i18n/locales/en.json b/services/tenant-ui/frontend/src/plugins/i18n/locales/en.json index 80363f980..78ee7b877 100644 --- a/services/tenant-ui/frontend/src/plugins/i18n/locales/en.json +++ b/services/tenant-ui/frontend/src/plugins/i18n/locales/en.json @@ -468,7 +468,8 @@ "enableLedgerSwitch": "Tenant can switch endorser/ledger", "endorserAlias": "Endorser Alias:", "ledgerName": "Ledger Name:", - "success": "Tenant Config Updated" + "success": "Tenant Config Updated", + "confirmDeletion": "To confirm, type \"{tenantName}\" in the box below" }, "tenants": "Tenants" }, diff --git a/services/tenant-ui/frontend/src/plugins/i18n/locales/fr.json b/services/tenant-ui/frontend/src/plugins/i18n/locales/fr.json index f849db4c8..9ce60e17a 100644 --- a/services/tenant-ui/frontend/src/plugins/i18n/locales/fr.json +++ b/services/tenant-ui/frontend/src/plugins/i18n/locales/fr.json @@ -471,7 +471,8 @@ "enableLedgerSwitch": "Tenant can switch endorser/ledger ", "endorserAlias": "Endorser Alias ", "ledgerName": "Ledger Name ", - "success": "Tenant Config Updated " + "success": "Tenant Config Updated ", + "confirmDeletion": "To confirm, type \"{tenantName}\" in the box below " }, "tenants": "Tenants " }, diff --git a/services/tenant-ui/frontend/src/plugins/i18n/locales/ja.json b/services/tenant-ui/frontend/src/plugins/i18n/locales/ja.json index 27cffc01d..9ea80796d 100644 --- a/services/tenant-ui/frontend/src/plugins/i18n/locales/ja.json +++ b/services/tenant-ui/frontend/src/plugins/i18n/locales/ja.json @@ -472,7 +472,8 @@ "enableLedgerSwitch": "Tenant can switch endorser/ledger ", "endorserAlias": "Endorser Alias ", "ledgerName": "Ledger Name ", - "success": "Tenant Config Updated " + "success": "Tenant Config Updated ", + "confirmDeletion": "To confirm, type \"{tenantName}\" in the box below " }, "tenants": "Tenants " }, diff --git a/services/tenant-ui/frontend/src/store/innkeeper/innkeeperTenantsStore.ts b/services/tenant-ui/frontend/src/store/innkeeper/innkeeperTenantsStore.ts index 6d9544bcc..4b1e0414f 100644 --- a/services/tenant-ui/frontend/src/store/innkeeper/innkeeperTenantsStore.ts +++ b/services/tenant-ui/frontend/src/store/innkeeper/innkeeperTenantsStore.ts @@ -355,6 +355,27 @@ export const useInnkeeperTenantsStore = defineStore('innkeeperTenants', () => { return result; }; + // Delete a Tenant + async function deleteTenant(id: string) { + loading.value = true; + try { + console.log(`Deleting tenant: ${id}`); + + // await acapyApi.deleteHttp( + // API_PATH.INNKEEPER_AUTHENTICATIONS_API_RECORD(id) + // ); + // listApiKeys(); + } catch (err: any) { + error.value = err; + } finally { + loading.value = false; + } + if (error.value != null) { + // throw error so $onAction.onError listeners can add their own handler + throw error.value; + } + } + return { loading, error, @@ -376,6 +397,7 @@ export const useInnkeeperTenantsStore = defineStore('innkeeperTenants', () => { listReservations, updateTenantConfig, getDefaultConfigValues, + deleteTenant, }; }); From 286534c674b7facbe51d34a738c35f270aab5240 Mon Sep 17 00:00:00 2001 From: Gurjeet Matharu Date: Mon, 30 Oct 2023 17:10:25 -0700 Subject: [PATCH 2/6] inkeeper api deletion - added soft delete to model - added query params to get tenants - added delete endpoint Signed-off-by: Gurjeet Matharu --- .../v1_0/innkeeper/models.py | 11 +++- .../v1_0/innkeeper/routes.py | 56 ++++++++++++++++++- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/plugins/traction_innkeeper/traction_innkeeper/v1_0/innkeeper/models.py b/plugins/traction_innkeeper/traction_innkeeper/v1_0/innkeeper/models.py index 006499689..e7fec8242 100644 --- a/plugins/traction_innkeeper/traction_innkeeper/v1_0/innkeeper/models.py +++ b/plugins/traction_innkeeper/traction_innkeeper/v1_0/innkeeper/models.py @@ -238,7 +238,7 @@ class Meta: fields.Dict(description="Endorser and ledger config", required=False), example=json.dumps(ENDORSER_LEDGER_CONFIG_EXAMPLE), required=False, - attribute="connect_to_endorsers" + attribute="connect_to_endorsers", ) create_public_did = fields.List( @@ -345,6 +345,15 @@ async def query_by_wallet_id( raise StorageNotFoundError("No TenantRecord found for the given wallet_id") return result[0] + async def soft_delete(self, session: ProfileSession): + """ + Soft delete the tenant record by setting its state to 'deleted'. + Note: This method should be called on an instance of the TenantRecord. + """ + if self.state != self.STATE_DELETED: + self.state = self.STATE_DELETED + await self.save(session, reason="Soft delete") + class TenantRecordSchema(BaseRecordSchema): """Innkeeper Tenant Record Schema.""" 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 f0724f0ad..16bca1080 100644 --- a/plugins/traction_innkeeper/traction_innkeeper/v1_0/innkeeper/routes.py +++ b/plugins/traction_innkeeper/traction_innkeeper/v1_0/innkeeper/routes.py @@ -3,7 +3,13 @@ import uuid from aiohttp import ClientSession, web -from aiohttp_apispec import docs, match_info_schema, request_schema, response_schema +from aiohttp_apispec import ( + docs, + match_info_schema, + request_schema, + response_schema, + use_kwargs, +) from aries_cloudagent.admin.request_context import AdminRequestContext from aries_cloudagent.messaging.models.base import BaseModelError from aries_cloudagent.messaging.models.openapi import OpenAPISchema @@ -17,7 +23,7 @@ from aries_cloudagent.storage.error import StorageError, StorageNotFoundError from aries_cloudagent.wallet.error import WalletSettingsError from aries_cloudagent.wallet.models.wallet_record import WalletRecord -from marshmallow import fields +from marshmallow import fields, validate from . import TenantManager from .config import InnkeeperWalletConfig @@ -275,6 +281,19 @@ class TenantListSchema(OpenAPISchema): ) +class TenantListQuerySchema(OpenAPISchema): + """Query parameters schema for tenants list.""" + + state = fields.Str( + required=False, + description="The state of the tenants to filter by.", + example=TenantRecord.STATE_ACTIVE, + validate=validate.OneOf( + [TenantRecord.STATE_ACTIVE, TenantRecord.STATE_DELETED, "all"] + ), + ) + + class TenantAuthenticationApiListSchema(OpenAPISchema): """Response schema for authentications - users list.""" @@ -709,6 +728,7 @@ async def innkeeper_reservations_deny(request: web.BaseRequest): tags=[SWAGGER_CATEGORY], ) @response_schema(TenantListSchema(), 200, description="") +@use_kwargs(TenantListQuerySchema(), location="query") @innkeeper_only @error_handler async def innkeeper_tenants_list(request: web.BaseRequest): @@ -718,7 +738,14 @@ async def innkeeper_tenants_list(request: web.BaseRequest): mgr = context.inject(TenantManager) profile = mgr.profile + # Get the state from query parameters, default to 'active' + state = request.query.get("state", TenantRecord.STATE_ACTIVE) tag_filter = {} + + # If the state is not 'all', apply the filter + if state != "all": + tag_filter["state"] = state + post_filter = {} async with profile.session() as session: @@ -757,6 +784,30 @@ async def innkeeper_tenant_get(request: web.BaseRequest): return web.json_response(rec.serialize()) +@docs( + tags=[SWAGGER_CATEGORY], +) +@match_info_schema(TenantIdMatchInfoSchema()) +@response_schema(TenantRecordSchema(), 200, description="") +@innkeeper_only +@error_handler +async def innkeeper_tenant_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: + await rec.soft_delete(session) + LOGGER.info("Tenant %s soft deleted.", tenant_id) + 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], summary="Create API Key Record") @request_schema(TenantAuthenticationsApiRequestSchema()) @response_schema(TenantAuthenticationsApiResponseSchema(), 200, description="") @@ -915,6 +966,7 @@ async def register(app: web.Application): "/innkeeper/tenants/{tenant_id}", innkeeper_tenant_get, allow_head=False ), web.put("/innkeeper/tenants/{tenant_id}/config", tenant_config_update), + web.delete("/innkeeper/tenants/{tenant_id}", innkeeper_tenant_delete), web.get( "/innkeeper/default-config", tenant_default_config_settings, From c275f59a3384e736629f65729f70f4f25229f0f8 Mon Sep 17 00:00:00 2001 From: Gurjeet Matharu Date: Mon, 30 Oct 2023 17:11:11 -0700 Subject: [PATCH 3/6] tenant ui - added delete button - webcopy fixes Signed-off-by: Gurjeet Matharu --- .../deleteTenant/ConfirmTenantDeletion.vue | 1 - .../tenants/deleteTenant/DeleteTenant.vue | 2 +- .../frontend/src/plugins/i18n/locales/en.json | 3 +- .../frontend/src/plugins/i18n/locales/fr.json | 3 +- .../frontend/src/plugins/i18n/locales/ja.json | 3 +- .../store/innkeeper/innkeeperTenantsStore.ts | 37 ++++++++----------- 6 files changed, 23 insertions(+), 26 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 805119deb..fd6c1a6e8 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 @@ -68,7 +68,6 @@ async function handleDelete() { }); emit('success'); - emit('closed'); } diff --git a/services/tenant-ui/frontend/src/components/innkeeper/tenants/deleteTenant/DeleteTenant.vue b/services/tenant-ui/frontend/src/components/innkeeper/tenants/deleteTenant/DeleteTenant.vue index 809a44ac9..e125dd9b8 100644 --- a/services/tenant-ui/frontend/src/components/innkeeper/tenants/deleteTenant/DeleteTenant.vue +++ b/services/tenant-ui/frontend/src/components/innkeeper/tenants/deleteTenant/DeleteTenant.vue @@ -1,7 +1,7 @@ From c56f2f53f0adc48b230660385edd049dccd17539 Mon Sep 17 00:00:00 2001 From: Gurjeet Matharu Date: Tue, 31 Oct 2023 14:47:32 -0700 Subject: [PATCH 5/6] added deleted_at Signed-off-by: Gurjeet Matharu --- .../traction_innkeeper/v1_0/innkeeper/models.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/traction_innkeeper/traction_innkeeper/v1_0/innkeeper/models.py b/plugins/traction_innkeeper/traction_innkeeper/v1_0/innkeeper/models.py index e7fec8242..0ff157622 100644 --- a/plugins/traction_innkeeper/traction_innkeeper/v1_0/innkeeper/models.py +++ b/plugins/traction_innkeeper/traction_innkeeper/v1_0/innkeeper/models.py @@ -278,6 +278,7 @@ def __init__( created_public_did: List = [], auto_issuer: bool = False, enable_ledger_switch=False, + deleted_at: str = None, **kwargs, ): """Construct record.""" @@ -293,6 +294,7 @@ def __init__( self.auto_issuer = auto_issuer self.enable_ledger_switch = enable_ledger_switch self.curr_ledger_id = curr_ledger_id + self.deleted_at = deleted_at @property def tenant_id(self) -> Optional[str]: @@ -312,6 +314,7 @@ def record_value(self) -> dict: "auto_issuer", "enable_ledger_switch", "curr_ledger_id", + "deleted_at", ) } @@ -352,6 +355,7 @@ async def soft_delete(self, session: ProfileSession): """ if self.state != self.STATE_DELETED: self.state = self.STATE_DELETED + self.deleted_at = datetime_to_str(datetime.utcnow()) await self.save(session, reason="Soft delete") @@ -422,6 +426,11 @@ class Meta: required=False, description="Current ledger identifier", ) + deleted_at = fields.Str( + required=False, + description="Timestamp of the deletion", + example="2023-10-30T01:01:01Z", + ) class TenantAuthenticationApiRecord(BaseRecord): From 6fc1ab8bb214b303317bdac93cbb4bba94e4d339 Mon Sep 17 00:00:00 2001 From: Gurjeet Matharu Date: Tue, 31 Oct 2023 14:47:47 -0700 Subject: [PATCH 6/6] disabled buttons for innkeeper Signed-off-by: Gurjeet Matharu --- .../components/innkeeper/tenants/deleteTenant/DeleteTenant.vue | 1 + .../src/components/innkeeper/tenants/editConfig/editConfig.vue | 1 + 2 files changed, 2 insertions(+) diff --git a/services/tenant-ui/frontend/src/components/innkeeper/tenants/deleteTenant/DeleteTenant.vue b/services/tenant-ui/frontend/src/components/innkeeper/tenants/deleteTenant/DeleteTenant.vue index bcb31007c..3cc2d1965 100644 --- a/services/tenant-ui/frontend/src/components/innkeeper/tenants/deleteTenant/DeleteTenant.vue +++ b/services/tenant-ui/frontend/src/components/innkeeper/tenants/deleteTenant/DeleteTenant.vue @@ -4,6 +4,7 @@ :title="$t('tenants.settings.deleteTenant')" icon="pi pi-trash" class="p-button-rounded p-button-icon-only p-button-text" + :disabled="props.tenant.tenant_name === 'traction_innkeeper'" @click="openModal" />