Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(credentials): added credential sendProblemReport method #906

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ export interface AcceptCredentialOptions {
credentialRecord: CredentialExchangeRecord
}

export interface CreateProblemReportOptions {
message: string
}

export interface CredentialProtocolMsgReturnType<MessageType extends AgentMessage> {
message: MessageType
credentialRecord: CredentialExchangeRecord
Expand Down
26 changes: 26 additions & 0 deletions packages/core/src/modules/credentials/CredentialsModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type {
FindCredentialMessageReturn,
FindProposalMessageReturn,
GetFormatDataReturn,
SendProblemReportOptions,
} from './CredentialsModuleOptions'
import type { CredentialFormat } from './formats'
import type { IndyCredentialFormat } from './formats/indy/IndyCredentialFormat'
Expand Down Expand Up @@ -67,6 +68,7 @@ export interface CredentialsModule<CFs extends CredentialFormat[], CSs extends C

// Credential
acceptCredential(options: AcceptCredentialOptions): Promise<CredentialExchangeRecord>
sendProblemReport(options: SendProblemReportOptions): Promise<CredentialExchangeRecord>

// Record Methods
getAll(): Promise<CredentialExchangeRecord[]>
Expand Down Expand Up @@ -517,6 +519,30 @@ export class CredentialsModule<
}
}

/**
* Send problem report message for a credential record
* @param credentialRecordId The id of the credential record for which to send problem report
* @param message message to send
* @returns credential record associated with the credential problem report message
*/
public async sendProblemReport(options: SendProblemReportOptions) {
const credentialRecord = await this.getById(options.credentialRecordId)
if (!credentialRecord.connectionId) {
throw new AriesFrameworkError(`No connectionId found for credential record '${credentialRecord.id}'.`)
}
const connection = await this.connectionService.getById(credentialRecord.connectionId)

const service = this.getService(credentialRecord.protocolVersion)
const problemReportMessage = service.createProblemReport({ message: options.message })
problemReportMessage.setThread({
threadId: credentialRecord.threadId,
})
const outboundMessage = createOutboundMessage(connection, problemReportMessage)
await this.messageSender.sendMessage(outboundMessage)

return credentialRecord
}

public async getFormatData(credentialRecordId: string): Promise<GetFormatDataReturn<CFs>> {
const credentialRecord = await this.getById(credentialRecordId)
const service = this.getService(credentialRecord.protocolVersion)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,11 @@ export interface AcceptRequestOptions<CFs extends CredentialFormat[] = Credentia
export interface AcceptCredentialOptions {
credentialRecordId: string
}

/**
* Interface for CredentialsModule.sendProblemReport. Will send a problem-report message
*/
export interface SendProblemReportOptions {
credentialRecordId: string
message: string
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import type { AgentMessage } from '../../../../agent/AgentMessage'
import type { HandlerInboundMessage } from '../../../../agent/Handler'
import type { InboundMessageContext } from '../../../../agent/models/InboundMessageContext'
import type { ProblemReportMessage } from '../../../problem-reports'
import type {
AcceptCredentialOptions,
AcceptOfferOptions,
AcceptProposalOptions,
AcceptRequestOptions,
CreateOfferOptions,
CreateProblemReportOptions,
CreateProposalOptions,
CredentialProtocolMsgReturnType,
NegotiateOfferOptions,
Expand All @@ -30,6 +32,7 @@ import { uuid } from '../../../../utils/uuid'
import { AckStatus } from '../../../common'
import { ConnectionService } from '../../../connections/services'
import { MediationRecipientService } from '../../../routing'
import { CredentialProblemReportReason } from '../../errors'
import { IndyCredentialFormatService } from '../../formats/indy/IndyCredentialFormatService'
import { IndyCredPropose } from '../../formats/indy/models'
import { AutoAcceptCredential } from '../../models/CredentialAutoAcceptType'
Expand All @@ -52,6 +55,7 @@ import {
INDY_CREDENTIAL_OFFER_ATTACHMENT_ID,
INDY_CREDENTIAL_REQUEST_ATTACHMENT_ID,
V1CredentialAckMessage,
V1CredentialProblemReportMessage,
V1IssueCredentialMessage,
V1OfferCredentialMessage,
V1ProposeCredentialMessage,
Expand Down Expand Up @@ -909,6 +913,22 @@ export class V1CredentialService extends CredentialService<[IndyCredentialFormat
return credentialRecord
}

/**
* Create a {@link V1CredentialProblemReportMessage} to be sent.
*
* @param message message to send
* @returns a {@link V1CredentialProblemReportMessage}
*
*/
public createProblemReport(options: CreateProblemReportOptions): ProblemReportMessage {
return new V1CredentialProblemReportMessage({
description: {
en: options.message,
code: CredentialProblemReportReason.IssuanceAbandoned,
},
})
}

// AUTO RESPOND METHODS
public async shouldAutoRespondToProposal(options: {
credentialRecord: CredentialExchangeRecord
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,7 @@ describe('V1CredentialService', () => {

describe('createProblemReport', () => {
const threadId = 'fd9c5ddb-ec11-4acd-bc32-540736249746'
const message = 'Indy error'
let credential: CredentialExchangeRecord

beforeEach(() => {
Expand All @@ -702,25 +703,24 @@ describe('V1CredentialService', () => {
})
})

test('returns problem report message base once get error', async () => {
test('returns problem report message base once get error', () => {
// given
mockFunction(credentialRepository.getById).mockReturnValue(Promise.resolve(credential))

// when
const credentialProblemReportMessage = new V1CredentialProblemReportMessage({
description: {
en: 'Indy error',
code: CredentialProblemReportReason.IssuanceAbandoned,
},
})
const credentialProblemReportMessage = credentialService.createProblemReport({ message })

credentialProblemReportMessage.setThread({ threadId })
// then
expect(credentialProblemReportMessage.toJSON()).toMatchObject({
'@id': expect.any(String),
'@type': 'https://didcomm.org/issue-credential/1.0/problem-report',
'~thread': {
thid: 'fd9c5ddb-ec11-4acd-bc32-540736249746',
thid: threadId,
},
description: {
code: CredentialProblemReportReason.IssuanceAbandoned,
en: message,
},
})
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { AgentMessage } from '../../../../agent/AgentMessage'
import type { HandlerInboundMessage } from '../../../../agent/Handler'
import type { InboundMessageContext } from '../../../../agent/models/InboundMessageContext'
import type { ProblemReportMessage } from '../../../problem-reports'
import type {
CreateProposalOptions,
CredentialProtocolMsgReturnType,
Expand All @@ -14,6 +15,7 @@ import type {
AcceptCredentialOptions,
GetFormatDataReturn,
FormatDataMessagePayload,
CreateProblemReportOptions,
} from '../../CredentialServiceOptions'
import type {
CredentialFormat,
Expand All @@ -34,6 +36,7 @@ import { uuid } from '../../../../utils/uuid'
import { AckStatus } from '../../../common'
import { ConnectionService } from '../../../connections'
import { MediationRecipientService } from '../../../routing'
import { CredentialProblemReportReason } from '../../errors'
import { IndyCredentialFormatService } from '../../formats/indy/IndyCredentialFormatService'
import { CredentialState, AutoAcceptCredential } from '../../models'
import { CredentialExchangeRecord, CredentialRepository } from '../../repository'
Expand All @@ -52,6 +55,7 @@ import {
} from './handlers'
import {
V2CredentialAckMessage,
V2CredentialProblemReportMessage,
V2IssueCredentialMessage,
V2OfferCredentialMessage,
V2ProposeCredentialMessage,
Expand Down Expand Up @@ -798,6 +802,22 @@ export class V2CredentialService<CFs extends CredentialFormat[] = CredentialForm
return credentialRecord
}

/**
* Create a {@link V2CredentialProblemReportMessage} to be sent.
*
* @param message message to send
* @returns a {@link V2CredentialProblemReportMessage}
*
*/
public createProblemReport(options: CreateProblemReportOptions): ProblemReportMessage {
return new V2CredentialProblemReportMessage({
description: {
en: options.message,
code: CredentialProblemReportReason.IssuanceAbandoned,
},
})
}

// AUTO ACCEPT METHODS
public async shouldAutoRespondToProposal(options: {
credentialRecord: CredentialExchangeRecord
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -652,22 +652,18 @@ describe('CredentialService', () => {
})

describe('createProblemReport', () => {
test('returns problem report message base once get error', async () => {
test('returns problem report message base once get error', () => {
// given
const credentialRecord = mockCredentialRecord({
state: CredentialState.OfferReceived,
threadId: 'somethreadid',
connectionId: 'b1e2f039-aa39-40be-8643-6ce2797b5190',
})
const message = 'Indy error'
mockFunction(credentialRepository.getById).mockResolvedValue(credentialRecord)

// when
const credentialProblemReportMessage = new V2CredentialProblemReportMessage({
description: {
en: 'Indy error',
code: CredentialProblemReportReason.IssuanceAbandoned,
},
})
const credentialProblemReportMessage = credentialService.createProblemReport({ message })

credentialProblemReportMessage.setThread({ threadId: 'somethreadid' })
// then
Expand All @@ -677,6 +673,10 @@ describe('CredentialService', () => {
'~thread': {
thid: 'somethreadid',
},
description: {
code: CredentialProblemReportReason.IssuanceAbandoned,
en: message,
},
})
})
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type {
AcceptRequestOptions,
AcceptCredentialOptions,
GetFormatDataReturn,
CreateProblemReportOptions,
} from '../CredentialServiceOptions'
import type { CredentialFormat, CredentialFormatService } from '../formats'
import type { CredentialExchangeRecord, CredentialRepository } from './../repository'
Expand Down Expand Up @@ -84,6 +85,9 @@ export abstract class CredentialService<CFs extends CredentialFormat[] = Credent
// methods for ack
abstract processAck(messageContext: InboundMessageContext<AgentMessage>): Promise<CredentialExchangeRecord>

// methods for problem-report
abstract createProblemReport(options: CreateProblemReportOptions): ProblemReportMessage

abstract findProposalMessage(credentialExchangeId: string): Promise<AgentMessage | null>
abstract findOfferMessage(credentialExchangeId: string): Promise<AgentMessage | null>
abstract findRequestMessage(credentialExchangeId: string): Promise<AgentMessage | null>
Expand Down