diff --git a/apps/issuance/src/issuance.repository.ts b/apps/issuance/src/issuance.repository.ts index c825cb96a..d85a9849b 100644 --- a/apps/issuance/src/issuance.repository.ts +++ b/apps/issuance/src/issuance.repository.ts @@ -121,6 +121,9 @@ export class IssuanceRepository { schemaId: string; state: string; orgId: string; + connections: { + theirLabel: string; + }; }[]; }> { try { @@ -144,7 +147,12 @@ export class IssuanceRepository { orgId: true, state: true, schemaId: true, - connectionId: true + connectionId: true, + connections: { + select: { + theirLabel: true + } + } }, orderBy: { [issuedCredentialsSearchCriteria?.sortField]: diff --git a/apps/verification/src/interfaces/verification.interface.ts b/apps/verification/src/interfaces/verification.interface.ts index fb7520a87..0eb86b934 100644 --- a/apps/verification/src/interfaces/verification.interface.ts +++ b/apps/verification/src/interfaces/verification.interface.ts @@ -2,275 +2,279 @@ import { AutoAccept } from '@credebl/enum/enum'; import { IUserRequest } from '@credebl/user-request/user-request.interface'; export interface IProofRequestAttribute { - attributeName?: string; - attributeNames?:string[]; - condition?: string; - value?: string; - credDefId?: string; - schemaId?: string; - credentialName?: string; + attributeName?: string; + attributeNames?: string[]; + condition?: string; + value?: string; + credDefId?: string; + schemaId?: string; + credentialName?: string; } export enum ProofRequestType { - INDY = 'indy', - PRESENTATIONEXCHANGE = 'presentationExchange' + INDY = 'indy', + PRESENTATIONEXCHANGE = 'presentationExchange' } export interface IRequestProof { - orgId: string; - version:string; - connectionId?: string | string[]; - attributes?: IProofRequestAttribute[]; - type: ProofRequestType; - presentationDefinition?:IProofRequestPresentationDefinition; - comment: string; - autoAcceptProof: AutoAccept; - protocolVersion?: string; - emailId?: string[]; - goalCode?: string; - parentThreadId?: string; - willConfirm?: boolean; + orgId: string; + version: string; + connectionId?: string | string[]; + attributes?: IProofRequestAttribute[]; + type: ProofRequestType; + presentationDefinition?: IProofRequestPresentationDefinition; + comment: string; + autoAcceptProof: AutoAccept; + protocolVersion?: string; + emailId?: string[]; + goalCode?: string; + parentThreadId?: string; + willConfirm?: boolean; } export interface IGetAllProofPresentations { - url: string; - apiKey: string; + url: string; + apiKey: string; } export interface IGetProofPresentationById { - url: string; - apiKey?: string; - orgId?: string; + url: string; + apiKey?: string; + orgId?: string; } export interface IVerifyPresentation { - url: string; - apiKey?: string; - orgId?: string; + url: string; + apiKey?: string; + orgId?: string; } export interface IVerifiedProofData { - url: string; - apiKey?: string; - orgId?: string + url: string; + apiKey?: string; + orgId?: string; } export interface IProofPresentationData { - proofId: string; - orgId: string; - user: IUserRequest; + proofId: string; + orgId: string; + user: IUserRequest; } interface IProofFormats { - indy: IndyProof + indy: IndyProof; } interface IndyProof { - name: string; - version: string; - requested_attributes: IRequestedAttributes; - requested_predicates: IRequestedPredicates; + name: string; + version: string; + requested_attributes: IRequestedAttributes; + requested_predicates: IRequestedPredicates; } interface IRequestedAttributes { - [key: string]: IRequestedAttributesName; + [key: string]: IRequestedAttributesName; } interface IRequestedAttributesName { - name?: string; - names?: string; - restrictions: IRequestedRestriction[] + name?: string; + names?: string; + restrictions: IRequestedRestriction[]; } interface IRequestedPredicates { - [key: string]: IRequestedPredicatesName; + [key: string]: IRequestedPredicatesName; } interface IRequestedPredicatesName { - name: string; - restrictions: IRequestedRestriction[] + name: string; + restrictions: IRequestedRestriction[]; } interface IRequestedRestriction { - cred_def_id?: string; - schema_id?: string; - schema_issuer_did?: string; - schema_name?: string; - issuer_did?: string; - schema_version?: string; + cred_def_id?: string; + schema_id?: string; + schema_issuer_did?: string; + schema_name?: string; + issuer_did?: string; + schema_version?: string; } export interface ISchema { - uri:string; + uri: string; } export interface IFields { - path: string[]; - } + path: string[]; +} export interface IConstraints { - fields: IFields[]; - } + fields: IFields[]; +} export interface IInputDescriptors { - - id:string; - name?:string; - purpose?:string; - schema:ISchema[]; - constraints?:IConstraints; - + id: string; + name?: string; + purpose?: string; + schema: ISchema[]; + constraints?: IConstraints; } export interface IProofRequestPresentationDefinition { - id:string; - name: string; - purpose?: string; - input_descriptors:IInputDescriptors[]; + id: string; + name: string; + purpose?: string; + input_descriptors: IInputDescriptors[]; } export interface IPresentationExchange { - presentationDefinition:IProofRequestPresentationDefinition; - + presentationDefinition: IProofRequestPresentationDefinition; } export interface IPresentationExchangeProofFormats { - presentationExchange? : IPresentationExchange; - indy?: IndyProof + presentationExchange?: IPresentationExchange; + indy?: IndyProof; } export interface ISendPresentationExchangeProofRequestPayload { - protocolVersion: string; - comment: string; - parentThreadId?: string; - proofFormats: IPresentationExchangeProofFormats; - autoAcceptProof: string; - label?: string; + protocolVersion: string; + comment: string; + parentThreadId?: string; + proofFormats: IPresentationExchangeProofFormats; + autoAcceptProof: string; + label?: string; } export interface IPresentationExchangeProofRequestPayload { - url: string; - apiKey?: string; - proofRequestPayload: ISendPresentationExchangeProofRequestPayload; - orgId?: string; + url: string; + apiKey?: string; + proofRequestPayload: ISendPresentationExchangeProofRequestPayload; + orgId?: string; } export interface ISendProofRequestPayload { - protocolVersion?: string; - comment?: string; - connectionId?: string; - proofFormats?: IProofFormats; - autoAcceptProof?: AutoAccept; - label?: string; - goalCode?: string; - // TODO: [Credo-ts] Issue with parentThreadId in creating an OOB proof request. - // This causes failures in OOB connection establishment. - // parentThreadId?: string; - willConfirm?: boolean; - imageUrl?: string; - emailId?: string[] - isShortenUrl?: boolean; - type?:string; - orgId?: string; - presentationDefinition?:IProofRequestPresentationDefinition; - reuseConnection?: boolean; - recipientKey?:string; - invitationDid?: string + protocolVersion?: string; + comment?: string; + connectionId?: string; + proofFormats?: IProofFormats; + autoAcceptProof?: AutoAccept; + label?: string; + goalCode?: string; + // TODO: [Credo-ts] Issue with parentThreadId in creating an OOB proof request. + // This causes failures in OOB connection establishment. + // parentThreadId?: string; + willConfirm?: boolean; + imageUrl?: string; + emailId?: string[]; + isShortenUrl?: boolean; + type?: string; + orgId?: string; + presentationDefinition?: IProofRequestPresentationDefinition; + reuseConnection?: boolean; + recipientKey?: string; + invitationDid?: string; } export interface IWSendProofRequestPayload { - protocolVersion?: string; - comment?: string; - connectionId?: string; - proofFormats?: IProofFormats; - autoAcceptProof?: string; - label?: string; - goalCode?: string; - parentThreadId?: string; - willConfirm?: boolean; - imageUrl?: string; - emailId?: string[]; - type?:string; - presentationDefinition?:IProofRequestPresentationDefinition; + protocolVersion?: string; + comment?: string; + connectionId?: string; + proofFormats?: IProofFormats; + autoAcceptProof?: string; + label?: string; + goalCode?: string; + parentThreadId?: string; + willConfirm?: boolean; + imageUrl?: string; + emailId?: string[]; + type?: string; + presentationDefinition?: IProofRequestPresentationDefinition; } export interface IProofRequestPayload { - url: string; - apiKey?: string; - orgId?: string; - proofRequestPayload: ISendProofRequestPayload | ISendPresentationExchangeProofRequestPayload; + url: string; + apiKey?: string; + orgId?: string; + proofRequestPayload: ISendProofRequestPayload | ISendPresentationExchangeProofRequestPayload; } interface IWebhookPresentationProof { - threadId: string; - state: string; - connectionId + threadId: string; + state: string; + connectionId; } export interface IWebhookProofPresentation { - metadata: object; - _tags: IWebhookPresentationProof; - id: string; - createdAt: string; - protocolVersion: string; - state: string; - connectionId: string; - presentationId: string; - threadId: string; - parentThreadId?: string; - autoAcceptProof: string; - updatedAt: string; - isVerified: boolean; - contextCorrelationId: string; - errorMessage?: string; + metadata: object; + _tags: IWebhookPresentationProof; + id: string; + createdAt: string; + protocolVersion: string; + state: string; + connectionId: string; + presentationId: string; + threadId: string; + parentThreadId?: string; + autoAcceptProof: string; + updatedAt: string; + isVerified: boolean; + contextCorrelationId: string; + errorMessage?: string; } export interface IProofPresentation { - proofPresentationPayload: IWebhookProofPresentation; - orgId: string; + proofPresentationPayload: IWebhookProofPresentation; + orgId: string; } export interface IProofRequests { - proofRequestsSearchCriteria: IProofRequestSearchCriteria; - user: IUserRequest; - orgId: string; + proofRequestsSearchCriteria: IProofRequestSearchCriteria; + user: IUserRequest; + orgId: string; } export interface IProofRequestSearchCriteria { - pageNumber: number; - pageSize: number; - sortField: string; - sortBy: string; - search: string; + pageNumber: number; + pageSize: number; + sortField: string; + sortBy: string; + search: string; } -export interface IInvitation{ - invitationUrl?: string; - deepLinkURL?: string; +export interface IInvitation { + invitationUrl?: string; + deepLinkURL?: string; } export interface IProofRequestData { - goalCode?: string; - version:string; - parentThreadId?: string; - willConfirm?: boolean; - protocolVersion?: string; - proofFormats?:IProofFormat; - orgId: string; - connectionId?: string | string[]; - attributes?: IProofRequestAttribute[]; - type: ProofRequestType; - presentationDefinition?:IProofRequestPresentationDefinition; - comment: string; - autoAcceptProof: AutoAccept; + goalCode?: string; + version: string; + parentThreadId?: string; + willConfirm?: boolean; + protocolVersion?: string; + proofFormats?: IProofFormat; + orgId: string; + connectionId?: string | string[]; + attributes?: IProofRequestAttribute[]; + type: ProofRequestType; + presentationDefinition?: IProofRequestPresentationDefinition; + comment: string; + autoAcceptProof: AutoAccept; } export interface IProofFormat { - indy: Indy; + indy: Indy; } export interface Indy { - attributes: IProofAttributesData[]; + attributes: IProofAttributesData[]; } export interface IProofAttributesData { - attributeName: string; - attributeNames?: string[]; - condition: string; - value: string; - credDefId: string; - schemaId: string; -} \ No newline at end of file + attributeName: string; + attributeNames?: string[]; + condition: string; + value: string; + credDefId: string; + schemaId: string; +} + +export interface IEmailResponse { + email: string; + isEmailSent: boolean; + outOfBandRecordId: string; + proofRecordThId: string; +} diff --git a/apps/verification/src/repositories/verification.repository.ts b/apps/verification/src/repositories/verification.repository.ts index 13587c094..256fa951d 100644 --- a/apps/verification/src/repositories/verification.repository.ts +++ b/apps/verification/src/repositories/verification.repository.ts @@ -1,4 +1,4 @@ -import { IProofPresentation, IProofRequestSearchCriteria } from '../interfaces/verification.interface'; +import { IEmailResponse, IProofPresentation, IProofRequestSearchCriteria } from '../interfaces/verification.interface'; import { IProofPresentationsListCount, IVerificationRecords } from '@credebl/common/interfaces/verification.interface'; import { Injectable, Logger, NotFoundException } from '@nestjs/common'; // eslint-disable-next-line camelcase @@ -106,7 +106,12 @@ export class VerificationRepository { presentationId: true, schemaId: true, emailId: true, - errorMessage: true + errorMessage: true, + connections: { + select: { + theirLabel: true + } + } }, orderBy: { [proofRequestsSearchCriteria.sortField]: SortValue.ASC === proofRequestsSearchCriteria.sortBy ? 'asc' : 'desc' @@ -115,6 +120,7 @@ export class VerificationRepository { take: Number(proofRequestsSearchCriteria.pageSize), skip: (proofRequestsSearchCriteria.pageNumber - 1) * proofRequestsSearchCriteria.pageSize }); + const proofRequestsCount = await this.prisma.presentations.count({ where: { orgId, @@ -156,7 +162,6 @@ export class VerificationRepository { let encryptEmailId; let organisationId: string; let schemaId; - const { proofPresentationPayload, orgId } = payload; //For Educreds @@ -182,7 +187,6 @@ export class VerificationRepository { } else { organisationId = orgId; } - const proofPresentationsDetails = await this.prisma.presentations.upsert({ where: { threadId: proofPresentationPayload?.threadId @@ -293,4 +297,18 @@ export class VerificationRepository { throw error; } } + + async saveEmail(emailList: IEmailResponse[]): Promise { + try { + for (const { proofRecordThId, email } of emailList) { + await this.prisma.presentations.updateMany({ + where: { threadId: proofRecordThId }, + data: { emailId: email } + }); + } + } catch (error) { + this.logger.error(`[Verification Save Email] - error: ${JSON.stringify(error)}`); + throw error; + } + } } diff --git a/apps/verification/src/verification.service.ts b/apps/verification/src/verification.service.ts index fe99e8cf8..ed9b8b0c3 100644 --- a/apps/verification/src/verification.service.ts +++ b/apps/verification/src/verification.service.ts @@ -21,7 +21,8 @@ import { IVerifyPresentation, IVerifiedProofData, IInvitation, - IProofRequestData + IProofRequestData, + IEmailResponse } from './interfaces/verification.interface'; import { VerificationRepository } from './repositories/verification.repository'; import { ATTRIBUTE_NAME_REGEX, CommonConstants } from '@credebl/common/common.constant'; @@ -88,7 +89,6 @@ export class VerificationService { orgId, proofRequestsSearchCriteria ); - const schemaIds = getProofRequestsList?.proofRequestsList?.map((schema) => schema?.schemaId).filter(Boolean); const getSchemaDetails = await this._getSchemaAndOrganizationDetails(schemaIds); @@ -243,7 +243,9 @@ export class VerificationService { const getProofPresentationById = await this._getProofPresentationById(payload); return getProofPresentationById?.response; } catch (error) { - this.logger.error(`[getProofPresentationById] - error in get proof presentation by proofId : ${JSON.stringify(error)}`); + this.logger.error( + `[getProofPresentationById] - error in get proof presentation by proofId : ${JSON.stringify(error)}` + ); const errorMessage = error?.response?.error?.reason || error?.message; if (errorMessage?.includes('not found')) { @@ -566,9 +568,9 @@ export class VerificationService { } }; } - if (emailId) { const emailResponse = await this.sendEmailInBatches(payload, emailId, getAgentDetails, getOrganization); + await this.verificationRepository.saveEmail(emailResponse as IEmailResponse[]); return emailResponse; } else { const presentationProof: IInvitation = await this.generateOOBProofReq(payload); diff --git a/libs/common/src/response-messages/index.ts b/libs/common/src/response-messages/index.ts index 44f049c21..0c56ef999 100644 --- a/libs/common/src/response-messages/index.ts +++ b/libs/common/src/response-messages/index.ts @@ -79,7 +79,7 @@ export const ResponseMessages = { updateUserRoles: 'User roles updated successfully', delete: 'Organization deleted successfully', orgInvitationDeleted: 'Organization invitation deleted successfully', - orgCredentials: 'Organization credentials created successfully', + orgCredentials: 'Client credentials created successfully', fetchedOrgCredentials: 'Organization credentials fetched successfully', clientCredentials: 'Client credentials fetched successfully', deleteCredentials: 'Organization client credentials deleted', diff --git a/libs/prisma-service/prisma/migrations/20250721132721_added_relation_for_presentation_with_connection_table/migration.sql b/libs/prisma-service/prisma/migrations/20250721132721_added_relation_for_presentation_with_connection_table/migration.sql new file mode 100644 index 000000000..a28508bea --- /dev/null +++ b/libs/prisma-service/prisma/migrations/20250721132721_added_relation_for_presentation_with_connection_table/migration.sql @@ -0,0 +1,2 @@ +-- AddForeignKey +ALTER TABLE "presentations" ADD CONSTRAINT "presentations_connectionId_fkey" FOREIGN KEY ("connectionId") REFERENCES "connections"("connectionId") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/libs/prisma-service/prisma/migrations/20250724161232_added_connection_for_credentials_with_connection_table/migration.sql b/libs/prisma-service/prisma/migrations/20250724161232_added_connection_for_credentials_with_connection_table/migration.sql new file mode 100644 index 000000000..9f43bd90c --- /dev/null +++ b/libs/prisma-service/prisma/migrations/20250724161232_added_connection_for_credentials_with_connection_table/migration.sql @@ -0,0 +1,2 @@ +-- AddForeignKey +ALTER TABLE "credentials" ADD CONSTRAINT "credentials_connectionId_fkey" FOREIGN KEY ("connectionId") REFERENCES "connections"("connectionId") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/libs/prisma-service/prisma/schema.prisma b/libs/prisma-service/prisma/schema.prisma index 89fee4629..02bcbb91d 100644 --- a/libs/prisma-service/prisma/schema.prisma +++ b/libs/prisma-service/prisma/schema.prisma @@ -325,6 +325,8 @@ model connections { state String orgId String? @db.Uuid organisation organisation? @relation(fields: [orgId], references: [id]) + presentations presentations[] + credentials credentials[] } model credentials { @@ -341,6 +343,7 @@ model credentials { credDefId String @default("") orgId String? @db.Uuid organisation organisation? @relation(fields: [orgId], references: [id]) + connections connections? @relation(fields: [connectionId], references: [connectionId]) } model presentations { @@ -349,7 +352,7 @@ model presentations { createdBy String @db.Uuid lastChangedDateTime DateTime @default(now()) @db.Timestamptz(6) lastChangedBy String @db.Uuid - connectionId String? + connectionId String? state String? threadId String @unique isVerified Boolean? @@ -359,6 +362,8 @@ model presentations { emailId String? orgId String? @db.Uuid organisation organisation? @relation(fields: [orgId], references: [id]) + connections connections? @relation(fields: [connectionId], references: [connectionId]) + } model file_upload { @@ -527,4 +532,4 @@ model client_aliases { lastChangedDateTime DateTime @default(now()) @db.Timestamptz(6) clientAlias String? clientUrl String -} \ No newline at end of file +}