Skip to content

Commit

Permalink
feat: delete issuance records (#781)
Browse files Browse the repository at this point in the history
* feat: delete issuance records

Signed-off-by: bhavanakarwade <bhavana.karwade@ayanworks.com>

* reafctor: variables names

Signed-off-by: bhavanakarwade <bhavana.karwade@ayanworks.com>

* feat: delete issuance records by orgid

Signed-off-by: bhavanakarwade <bhavana.karwade@ayanworks.com>

---------

Signed-off-by: bhavanakarwade <bhavana.karwade@ayanworks.com>
Signed-off-by: KulkarniShashank <shashank.kulkarni@ayanworks.com>
  • Loading branch information
bhavanakarwade authored and KulkarniShashank committed Sep 12, 2024
1 parent 0ff0754 commit 7d12efc
Show file tree
Hide file tree
Showing 10 changed files with 167 additions and 26 deletions.
13 changes: 0 additions & 13 deletions apps/api-gateway/src/issuance/enums/Issuance.enum.ts
Original file line number Diff line number Diff line change
@@ -1,13 +0,0 @@
export enum IssueCredential {
proposalSent = 'proposal-sent',
proposalReceived = 'proposal-received',
offerSent = 'offer-sent',
offerReceived = 'offer-received',
declined = 'decliend',
requestSent = 'request-sent',
requestReceived = 'request-received',
credentialIssued = 'credential-issued',
credentialReceived = 'credential-received',
done = 'done',
abandoned = 'abandoned'
}
30 changes: 29 additions & 1 deletion apps/api-gateway/src/issuance/issuance.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import {
Logger,
BadRequestException,
NotFoundException,
ParseUUIDPipe
ParseUUIDPipe,
Delete
} from '@nestjs/common';
import {
ApiTags,
Expand Down Expand Up @@ -757,4 +758,31 @@ issueCredentialDto.type = 'Issuance';
}
return res.status(HttpStatus.CREATED).json(finalResponse);
}

@Delete('/:orgId/issuance-records')
@ApiOperation({ summary: 'Delete issuance record', description: 'Delete issuance records by orgId' })
@ApiResponse({ status: HttpStatus.OK, description: 'Success', type: ApiResponseDto })
@ApiBearerAuth()
@Roles(OrgRoles.OWNER)
@UseGuards(AuthGuard('jwt'), OrgRolesGuard)
async deleteIssuanceRecordsByOrgId(
@Param(
'orgId',
new ParseUUIDPipe({
exceptionFactory: (): Error => {
throw new BadRequestException(ResponseMessages.organisation.error.invalidOrgId);
}
})
)
orgId: string,
@User() user: user,
@Res() res: Response
): Promise<Response> {
await this.issueCredentialService.deleteIssuanceRecords(orgId, user);
const finalResponse: IResponse = {
statusCode: HttpStatus.OK,
message: ResponseMessages.issuance.success.deleteIssuanceRecords
};
return res.status(HttpStatus.OK).json(finalResponse);
}
}
9 changes: 7 additions & 2 deletions apps/api-gateway/src/issuance/issuance.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { BaseService } from 'libs/service/base.service';
import { IUserRequest } from '@credebl/user-request/user-request.interface';
import { ClientDetails, FileParameter, IssuanceDto, OOBCredentialDtoWithEmail, OOBIssueCredentialDto, PreviewFileDetails, TemplateDetails } from './dtos/issuance.dto';
import { FileExportResponse, IIssuedCredentialSearchParams, IReqPayload, ITemplateFormat, IssueCredentialType, UploadedFileDetails } from './interfaces';
import { ICredentialOfferResponse, IIssuedCredential } from '@credebl/common/interfaces/issuance.interface';
import { ICredentialOfferResponse, IDeletedIssuanceRecords, IIssuedCredential } from '@credebl/common/interfaces/issuance.interface';
import { IssueCredentialDto } from './dtos/multi-connection.dto';

import { user } from '@prisma/client';
@Injectable()
export class IssuanceService extends BaseService {

Expand Down Expand Up @@ -155,4 +155,9 @@ export class IssuanceService extends BaseService {
}
}

async deleteIssuanceRecords(orgId: string, userDetails: user): Promise<IDeletedIssuanceRecords> {
const payload = { orgId, userDetails };
return this.sendNatsMessage(this.issuanceProxy, 'delete-issuance-records', payload);
}

}
9 changes: 8 additions & 1 deletion apps/issuance/src/issuance.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { Controller } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';
import { IClientDetails, IIssuance, IIssueCredentials, IIssueCredentialsDefinitions, ImportFileDetails, IssueCredentialWebhookPayload, OutOfBandCredentialOffer, PreviewRequest, TemplateDetailsInterface } from '../interfaces/issuance.interfaces';
import { IssuanceService } from './issuance.service';
import { ICredentialOfferResponse, IIssuedCredential } from '@credebl/common/interfaces/issuance.interface';
import { ICredentialOfferResponse, IDeletedIssuanceRecords, IIssuedCredential } from '@credebl/common/interfaces/issuance.interface';
import { OOBIssueCredentialDto } from 'apps/api-gateway/src/issuance/dtos/issuance.dto';
import { user } from '@prisma/client';

@Controller()
export class IssuanceController {
Expand Down Expand Up @@ -97,4 +98,10 @@ export class IssuanceController {
async retryeBulkCredentials(payload: { fileId: string, orgId: string, clientId: string }): Promise<string> {
return this.issuanceService.retryBulkCredential(payload.fileId, payload.orgId, payload.clientId);
}

@MessagePattern({ cmd: 'delete-issuance-records' })
async deleteIssuanceRecords(payload: {orgId: string, userDetails: user}): Promise<IDeletedIssuanceRecords> {
const { orgId, userDetails } = payload;
return this.issuanceService.deleteIssuanceRecords(orgId, userDetails);
}
}
3 changes: 2 additions & 1 deletion apps/issuance/src/issuance.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { CacheModule } from '@nestjs/cache-manager';
import * as redisStore from 'cache-manager-redis-store';
import { BulkIssuanceProcessor } from './issuance.processor';
import { AwsService } from '@credebl/aws';
import { UserActivityRepository } from 'libs/user-activity/repositories';

@Module({
imports: [
Expand All @@ -37,6 +38,6 @@ import { AwsService } from '@credebl/aws';
})
],
controllers: [IssuanceController],
providers: [IssuanceService, IssuanceRepository, PrismaService, Logger, OutOfBandIssuance, EmailDto]
providers: [IssuanceService, IssuanceRepository, UserActivityRepository, PrismaService, Logger, OutOfBandIssuance, EmailDto, BulkIssuanceProcessor, AwsService]
})
export class IssuanceModule { }
47 changes: 45 additions & 2 deletions apps/issuance/src/issuance.repository.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable camelcase */
import { Injectable, InternalServerErrorException, Logger, NotFoundException } from '@nestjs/common';
import { ConflictException, Injectable, InternalServerErrorException, Logger, NotFoundException } from '@nestjs/common';
import { PrismaService } from '@credebl/prisma-service';
// eslint-disable-next-line camelcase
import {
Expand All @@ -24,7 +24,8 @@ import {
import { FileUploadStatus } from 'apps/api-gateway/src/enum';
import { IUserRequest } from '@credebl/user-request/user-request.interface';
import { IIssuedCredentialSearchParams } from 'apps/api-gateway/src/issuance/interfaces';
import { SortValue } from '@credebl/enum/enum';
import { PrismaTables, SortValue } from '@credebl/enum/enum';
import { IDeletedIssuanceRecords } from '@credebl/common/interfaces/issuance.interface';
@Injectable()
export class IssuanceRepository {
constructor(
Expand Down Expand Up @@ -542,4 +543,46 @@ export class IssuanceRepository {
throw error;
}
}

async deleteIssuanceRecordsByOrgId(orgId: string): Promise<IDeletedIssuanceRecords> {
try {
const tablesToCheck = [`${PrismaTables.PRESENTATIONS}`];

const referenceCounts = await Promise.all(
tablesToCheck.map((table) => this.prisma[table].count({ where: { orgId } }))
);

const referencedTables = referenceCounts
.map((count, index) => (0 < count ? tablesToCheck[index] : null))
.filter(Boolean);

if (0 < referencedTables.length) {
throw new ConflictException(`Organization ID ${orgId} is referenced in the following table(s): ${referencedTables.join(', ')}`);
}

return await this.prisma.$transaction(async (prisma) => {

const recordsToDelete = await this.prisma.credentials.findMany({
where: { orgId },
select: {
createDateTime: true,
createdBy: true,
connectionId: true,
schemaId: true,
state: true,
orgId: true
}
});

const deleteResult = await prisma.credentials.deleteMany({
where: { orgId }
});

return { deleteResult, recordsToDelete};
});
} catch (error) {
this.logger.error(`Error in deleting issuance records: ${error.message}`);
throw error;
}
}
}
52 changes: 49 additions & 3 deletions apps/issuance/src/issuance.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ResponseMessages } from '@credebl/common/response-messages';
import { ClientProxy, RpcException } from '@nestjs/microservices';
import { map } from 'rxjs';
import { CredentialOffer, FileUpload, FileUploadData, IAttributes, IClientDetails, ICreateOfferResponse, ICredentialPayload, IIssuance, IIssueData, IPattern, IQueuePayload, ISendOfferNatsPayload, ImportFileDetails, IssueCredentialWebhookPayload, OutOfBandCredentialOfferPayload, PreviewRequest, SchemaDetails, SendEmailCredentialOffer, TemplateDetailsInterface } from '../interfaces/issuance.interfaces';
import { OrgAgentType, PromiseResult, SchemaType, TemplateIdentifier } from '@credebl/enum/enum';
import { IssuanceProcessState, OrgAgentType, PromiseResult, SchemaType, TemplateIdentifier } from '@credebl/enum/enum';
import * as QRCode from 'qrcode';
import { OutOfBandIssuance } from '../templates/out-of-band-issuance.template';
import { EmailDto } from '@credebl/common/dtos/email.dto';
Expand All @@ -27,11 +27,12 @@ import { FileUploadStatus, FileUploadType } from 'apps/api-gateway/src/enum';
import { AwsService } from '@credebl/aws';
import { io } from 'socket.io-client';
import { IIssuedCredentialSearchParams, IssueCredentialType } from 'apps/api-gateway/src/issuance/interfaces';
import { ICredentialOfferResponse, IIssuedCredential, IJsonldCredential } from '@credebl/common/interfaces/issuance.interface';
import { ICredentialOfferResponse, IDeletedIssuanceRecords, IIssuedCredential, IJsonldCredential } from '@credebl/common/interfaces/issuance.interface';
import { OOBIssueCredentialDto } from 'apps/api-gateway/src/issuance/dtos/issuance.dto';
import { agent_invitations, organisation } from '@prisma/client';
import { RecordType, agent_invitations, organisation, user } from '@prisma/client';
import { createOobJsonldIssuancePayload, validateEmail } from '@credebl/common/cast.helper';
import { sendEmail } from '@credebl/common/send-grid-helper-file';
import { UserActivityRepository } from 'libs/user-activity/repositories';

@Injectable()
export class IssuanceService {
Expand All @@ -42,6 +43,8 @@ export class IssuanceService {
@Inject('NATS_CLIENT') private readonly issuanceServiceProxy: ClientProxy,
private readonly commonService: CommonService,
private readonly issuanceRepository: IssuanceRepository,
private readonly userActivityRepository: UserActivityRepository,
@Inject(CACHE_MANAGER) private cacheManager: Cache,
private readonly outOfBandIssuance: OutOfBandIssuance,
private readonly emailData: EmailDto,
private readonly awsService: AwsService,
Expand Down Expand Up @@ -1449,4 +1452,47 @@ async sendEmailForCredentialOffer(sendEmailCredentialOffer: SendEmailCredentialO
}
}

async deleteIssuanceRecords(orgId: string, userDetails: user): Promise<IDeletedIssuanceRecords> {
try {
const deletedCredentialsRecords = await this.issuanceRepository.deleteIssuanceRecordsByOrgId(orgId);

if (0 === deletedCredentialsRecords?.deleteResult?.count) {
throw new NotFoundException(ResponseMessages.issuance.error.issuanceRecordsNotFound);
}

const statusCounts = {
[IssuanceProcessState.REQUEST_SENT]: 0,
[IssuanceProcessState.REQUEST_RECEIVED]: 0,
[IssuanceProcessState.PROPOSAL_SENT]: 0,
[IssuanceProcessState.PROPOSAL_RECEIVED]: 0,
[IssuanceProcessState.OFFER_SENT]: 0,
[IssuanceProcessState.OFFER_RECEIVED]: 0,
[IssuanceProcessState.DONE]: 0,
[IssuanceProcessState.DECLIEND]: 0,
[IssuanceProcessState.CREDENTIAL_RECEIVED]: 0,
[IssuanceProcessState.CREDENTIAL_ISSUED]: 0,
[IssuanceProcessState.ABANDONED]: 0
};

await Promise.all(deletedCredentialsRecords?.recordsToDelete?.map(async (record) => {
statusCounts[record.state]++;
}));

const filteredStatusCounts = Object.fromEntries(
Object.entries(statusCounts).filter(entry => 0 < entry[1])
);

const deletedIssuanceData = {
deletedCredentialsRecordsCount : deletedCredentialsRecords?.deleteResult?.count,
deletedRecordsStatusCount: filteredStatusCounts
};

await this.userActivityRepository._orgDeletedActivity(orgId, userDetails, deletedIssuanceData, RecordType.ISSUANCE_RECORD);

return deletedCredentialsRecords;
} catch (error) {
this.logger.error(`[deleteIssuanceRecords] - error in deleting issuance records: ${JSON.stringify(error)}`);
throw new RpcException(error.response ? error.response : error);
}
}
}
10 changes: 9 additions & 1 deletion libs/common/src/interfaces/issuance.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,12 @@ export interface IIssuedCredential {
autoAcceptCredential?: string;
contextCorrelationId?: string;
}


interface IDeletedIssuanceRecordsCount {
count: number;
}

export interface IDeletedIssuanceRecords {
deleteResult: IDeletedIssuanceRecordsCount;
recordsToDelete: IIssuedCredentialResponse[];
}
6 changes: 4 additions & 2 deletions libs/common/src/response-messages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,8 @@ export const ResponseMessages = {
previewCSV: 'File details fetched sucessfully',
bulkIssuance: 'Issuance process started. It will take some time',
notFound: 'Schema records not found',
bulkProcess: 'Process initiated for bulk issuance'
bulkProcess: 'Process initiated for bulk issuance',
deleteIssuanceRecords: 'Issuance records deleted'
},
error: {
exists: 'Credentials is already exist',
Expand Down Expand Up @@ -316,7 +317,8 @@ export const ResponseMessages = {
invalidCredentialType:'invalid credential type',
missingRequestId: 'Param requestId is missing from the request.',
cachedData: 'Cached data does not exist',
cachedfileData: 'Cached file data does not exist'
cachedfileData: 'Cached file data does not exist',
issuanceRecordsNotFound: 'Issuance records not found'
}
},
verification: {
Expand Down
14 changes: 14 additions & 0 deletions libs/enum/src/enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,20 @@ export enum PrismaTables {
CREDENTIALS = 'credentials',
}

export enum IssuanceProcessState {
PROPOSAL_SENT = 'proposal-sent',
PROPOSAL_RECEIVED = 'proposal-received',
OFFER_SENT = 'offer-sent',
OFFER_RECEIVED = 'offer-received',
DECLIEND = 'decliend',
REQUEST_SENT = 'request-sent',
REQUEST_RECEIVED = 'request-received',
CREDENTIAL_ISSUED = 'credential-issued',
CREDENTIAL_RECEIVED = 'credential-received',
DONE = 'done',
ABANDONED = 'abandoned'
}

export enum VerificationProcessState {
PROPOSAL_SENT = 'proposal-sent',
PROPOSAL_RECEIVED = 'proposal-received',
Expand Down

0 comments on commit 7d12efc

Please sign in to comment.