abcdefgh
<pre>
Here is my E2E test class.</pre>
<p> </p>
<pre>
import {Test} from '@nestjs/testing';
import {ModuleMocker, MockFunctionMetadata} from 'jest-mock';
import axios from 'axios';
import {ConfigService} from '@nestjs/config';
import {ProcessfulfillmentHelper} from './processfulfillment-helper';
import ProcessService from '../src/process/process.service';
import AxiosUtil from '../src/applib/util/axios.util';
import {HttpException} from "@nestjs/common";
const moduleMocker = new ModuleMocker(global);
jest.setTimeout(10000);
jest.mock('axios', () => ({
default: {
create: jest.fn(() => axios),
post: jest.fn((url, headers) => {
let response;
const experienceApiResponse = ProcessfulfillmentHelper.getExperienceApiResponse(headers.case);
if (url === 'https://sit2www.cvsspecialty.com/apims/client/experience/v1/load' && !headers.isExpired) {
response = experienceApiResponse;
} else if (url === 'https://sit2www.cvsspecialty.com/apims/client/experience/v1/load' && headers.isExpired) {
return Promise.reject({message: "401 unauthorized"});
}
return Promise.resolve(response);
}),
},
// post: jest.fn(() => Promise.resolve({ data: ProcessfulfillmentHelper.cacheSavingsResponseFromAxios() })),
put: () => new Promise(() => {
}),
delete: () => new Promise(() => {
}),
}));
describe('Get process fulfillment', () => {
let processService: ProcessService;
beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
providers: [ProcessService],
})
.useMocker((token) => {
if (token === AxiosUtil) {
return {
getInstance: jest.fn(() => {
return {
post: (url, payload, headers) => {
const experienceApiResponse = ProcessfulfillmentHelper.getExperienceApiResponse(headers.headers.case);
if (url === 'https://sit2www.cvsspecialty.com/apims/client/experience/v1/load' && !headers?.headers?.isExpired) {
return Promise.resolve(experienceApiResponse);
} else if (url === 'https://digital-retail-rx-qa.internal.cvshealth.com/microservices/bff-rest/bff/v1/loadExperience' && !headers?.headers?.isExpired) {
return Promise.resolve(experienceApiResponse);
} else if (url === 'https://sit2www.cvsspecialty.com/apims/client/experience/v1/load' && headers?.headers?.isExpired) {
throw new HttpException("UnAuthorized", 401);
}
else if (url === 'https://digital-retail-rx-qa.internal.cvshealth.com/microservices/bff-rest/bff/v1/loadExperience' && headers?.headers?.isExpired) {
throw new HttpException("UnAuthorized", 401);
}
},
};
}),
}
}
if (token === ConfigService) {
return {
get: (key) => {
let value;
switch (key) {
case 'Agents':
value = ProcessfulfillmentHelper.getAgentConfig();
break;
}
return value;
},
};
}
if (typeof token === 'function') {
const mockMetadata = moduleMocker.getMetadata(token) as MockFunctionMetadata<any, any>;
const Mock = moduleMocker.generateFromMetadata(mockMetadata);
return new Mock();
}
return null;
})
.compile();
processService = moduleRef.get(ProcessService);
});
describe('get process fulfillment service', () => {
it('calling experienceapi method test for refills', async () => {
const intentRequestModel = ProcessfulfillmentHelper.getProcessFulfillmentRequest('refills');
const {agentName} = intentRequestModel;
const {intentName} = intentRequestModel;
const headers = {
'x-grid': '11223344',
'content-type': 'application/json',
authorization:
'Bearer eyJraWQiOiI4ZWEwZWEzYy1lMmU1LTQxNjgtYWRhNC1hMmZiNWZkYmZjNzgiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJyc2FkZHJlc3MxQGdtYWlsLmNvbSIsImF1ZCI6ImFwaS5jdnNoZWFsdGguY29tIiwieC1jbGllbnQtaWQiOiJmQ1I5QTl2ekp5ZnNDS0JZazN4dkduWjNiSzlBN2hEcSIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwiLCJpc3MiOiJhcGkuY3Zzc3BlY2lhbHR5LmNvbSIsIngtbWVtYmVyLXRva2VuIjoiN2I0MDYyYzljMWU1NGNlZWFjZTlhMWIwNDA1YWY1ZTVjOTQ0ZWM3NGE3NjU0ZTIxODdjYzY4NTgzN2ZjMmQ4NCIsIngtbG9iIjoiU3BlY2lhbHR5IiwieC1ncmlkIjoicnJ0LTY1MzgwNjQ2NjI5NjI5NTEwNjMtYS1nd28xLTcyMTUtMTY5NTg2MjA2LTIiLCJ4LWNvbnRleHQtdHlwZSI6ImxvZ2luVG9rZW5DYWNoZSIsImV4cCI6MTY5NTkxNDI4NSwiaWF0IjoxNjk1OTEzNjg1LCJqdGkiOiI5OGZlM2Q1My0xYjI0LTQ0YzItYWYwMy01MTFjYzFmMTZkY2YifQ.VziaVRLD5rsBbZjlPqWfOsu0sNWBl0ujOkSEt4H5CL8hL9DdiNAnT5TK7t1hJKb70r3AxPrXDELhX6ozmX05Gz8n3FIAKFk2ridgZrn9CYz5A2taAFXgOmRY1zdF7urizZr5Mx_Nw10UxxdG-Ae7AZ52u561Y9hUl0d7C8S_Qw09N3v7ogp2eE_EDXSapV82hgZIQkK-AE7Xn0ooC2NS_PlH90ZreiY_wtoJLmor-fqVgMs4RAOpl4CSYh5JUNVP-aTUNtDrKdoTWAFsBfOBBVvKD2jZQN4_tluW27t0pyMd-eYcrnVQhZ6Vw3Hsy8k-szNBjlS4icrHj1_iJVnTvw',
'user-agent': 'PostmanRuntime/7.28.4',
accept: '*/*',
'postman-token': 'd815d09b-853c-49e1-9e5c-053c661fd919',
host: 'localhost:21120',
'accept-encoding': 'gzip, deflate, br',
connection: 'keep-alive',
'content-length': '18893',
isExpired: false,
case: 'refills'
};
const jsonDataResult = ProcessfulfillmentHelper.getJsonDataResult(headers.case);
const experienceApiResponseActual = await processService.callExperienceApi(
agentName,
intentName,
headers,
jsonDataResult,
);
const experienceApiResponse = ProcessfulfillmentHelper.getExperienceApiResponse(headers.case);
expect(JSON.stringify(experienceApiResponseActual)).toStrictEqual(JSON.stringify(experienceApiResponse));
});
it('calling experienceapi method test for questions', async () => {
const intentRequestModel = ProcessfulfillmentHelper.getProcessFulfillmentRequest('questions');
const {agentName} = intentRequestModel;
const {intentName} = intentRequestModel;
const headers = {
'x-grid': '11223344',
'content-type': 'application/json',
authorization:
'Bearer eyJraWQiOiI4ZWEwZWEzYy1lMmU1LTQxNjgtYWRhNC1hMmZiNWZkYmZjNzgiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJyc2FkZHJlc3MxQGdtYWlsLmNvbSIsImF1ZCI6ImFwaS5jdnNoZWFsdGguY29tIiwieC1jbGllbnQtaWQiOiJmQ1I5QTl2ekp5ZnNDS0JZazN4dkduWjNiSzlBN2hEcSIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwiLCJpc3MiOiJhcGkuY3Zzc3BlY2lhbHR5LmNvbSIsIngtbWVtYmVyLXRva2VuIjoiN2I0MDYyYzljMWU1NGNlZWFjZTlhMWIwNDA1YWY1ZTVjOTQ0ZWM3NGE3NjU0ZTIxODdjYzY4NTgzN2ZjMmQ4NCIsIngtbG9iIjoiU3BlY2lhbHR5IiwieC1ncmlkIjoicnJ0LTY1MzgwNjQ2NjI5NjI5NTEwNjMtYS1nd28xLTcyMTUtMTY5NTg2MjA2LTIiLCJ4LWNvbnRleHQtdHlwZSI6ImxvZ2luVG9rZW5DYWNoZSIsImV4cCI6MTY5NTkxNDI4NSwiaWF0IjoxNjk1OTEzNjg1LCJqdGkiOiI5OGZlM2Q1My0xYjI0LTQ0YzItYWYwMy01MTFjYzFmMTZkY2YifQ.VziaVRLD5rsBbZjlPqWfOsu0sNWBl0ujOkSEt4H5CL8hL9DdiNAnT5TK7t1hJKb70r3AxPrXDELhX6ozmX05Gz8n3FIAKFk2ridgZrn9CYz5A2taAFXgOmRY1zdF7urizZr5Mx_Nw10UxxdG-Ae7AZ52u561Y9hUl0d7C8S_Qw09N3v7ogp2eE_EDXSapV82hgZIQkK-AE7Xn0ooC2NS_PlH90ZreiY_wtoJLmor-fqVgMs4RAOpl4CSYh5JUNVP-aTUNtDrKdoTWAFsBfOBBVvKD2jZQN4_tluW27t0pyMd-eYcrnVQhZ6Vw3Hsy8k-szNBjlS4icrHj1_iJVnTvw',
'user-agent': 'PostmanRuntime/7.28.4',
accept: '*/*',
'postman-token': 'd815d09b-853c-49e1-9e5c-053c661fd919',
host: 'localhost:21120',
'accept-encoding': 'gzip, deflate, br',
connection: 'keep-alive',
'content-length': '18893',
isExpired: false,
case: 'questions'
};
const jsonDataResult = ProcessfulfillmentHelper.getJsonDataResult(headers.case);
const experienceApiResponseActual = await processService.callExperienceApi(
agentName,
intentName,
headers,
jsonDataResult,
);
const experienceApiResponse = ProcessfulfillmentHelper.getExperienceApiResponse(headers.case);
expect(JSON.stringify(experienceApiResponseActual)).toStrictEqual(JSON.stringify(experienceApiResponse));
});
it('calling experienceapi refills method test with expired token', async () => {
const intentRequestModel = ProcessfulfillmentHelper.getProcessFulfillmentRequest('refills');
const {agentName} = intentRequestModel;
const {intentName} = intentRequestModel;
const headers = {
'x-grid': '11223344',
'content-type': 'application/json',
authorization:
'Bearer eyJraWQiOiI4ZWEwZWEzYy1lMmU1LTQxNjgtYWRhNC1hMmZiNWZkYmZjNzgiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJyc2FkZHJlc3MxQGdtYWlsLmNvbSIsImF1ZCI6ImFwaS5jdnNoZWFsdGguY29tIiwieC1jbGllbnQtaWQiOiJmQ1I5QTl2ekp5ZnNDS0JZazN4dkduWjNiSzlBN2hEcSIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwiLCJpc3MiOiJhcGkuY3Zzc3BlY2lhbHR5LmNvbSIsIngtbWVtYmVyLXRva2VuIjoiN2I0MDYyYzljMWU1NGNlZWFjZTlhMWIwNDA1YWY1ZTVjOTQ0ZWM3NGE3NjU0ZTIxODdjYzY4NTgzN2ZjMmQ4NCIsIngtbG9iIjoiU3BlY2lhbHR5IiwieC1ncmlkIjoicnJ0LTY1MzgwNjQ2NjI5NjI5NTEwNjMtYS1nd28xLTcyMTUtMTY5NTg2MjA2LTIiLCJ4LWNvbnRleHQtdHlwZSI6ImxvZ2luVG9rZW5DYWNoZSIsImV4cCI6MTY5NTkxNDI4NSwiaWF0IjoxNjk1OTEzNjg1LCJqdGkiOiI5OGZlM2Q1My0xYjI0LTQ0YzItYWYwMy01MTFjYzFmMTZkY2YifQ.VziaVRLD5rsBbZjlPqWfOsu0sNWBl0ujOkSEt4H5CL8hL9DdiNAnT5TK7t1hJKb70r3AxPrXDELhX6ozmX05Gz8n3FIAKFk2ridgZrn9CYz5A2taAFXgOmRY1zdF7urizZr5Mx_Nw10UxxdG-Ae7AZ52u561Y9hUl0d7C8S_Qw09N3v7ogp2eE_EDXSapV82hgZIQkK-AE7Xn0ooC2NS_PlH90ZreiY_wtoJLmor-fqVgMs4RAOpl4CSYh5JUNVP-aTUNtDrKdoTWAFsBfOBBVvKD2jZQN4_tluW27t0pyMd-eYcrnVQhZ6Vw3Hsy8k-szNBjlS4icrHj1_iJVnTvw',
'user-agent': 'PostmanRuntime/7.28.4',
accept: '*/*',
'postman-token': 'd815d09b-853c-49e1-9e5c-053c661fd919',
host: 'localhost:21120',
'accept-encoding': 'gzip, deflate, br',
connection: 'keep-alive',
'content-length': '18893',
isExpired: true,
case: 'refills'
};
const jsonDataResult = ProcessfulfillmentHelper.getJsonDataResult(headers.case);
try {
await processService.callExperienceApi(
agentName,
intentName,
headers,
jsonDataResult,
);
} catch (e) {
expect(e.status).toBe(401);
}
});
it('calling experienceapi questions method test with expired token', async () => {
const intentRequestModel = ProcessfulfillmentHelper.getProcessFulfillmentRequest('questions');
const {agentName} = intentRequestModel;
const {intentName} = intentRequestModel;
const headers = {
'x-grid': '11223344',
'content-type': 'application/json',
authorization:
'Bearer eyJraWQiOiI4ZWEwZWEzYy1lMmU1LTQxNjgtYWRhNC1hMmZiNWZkYmZjNzgiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJyc2FkZHJlc3MxQGdtYWlsLmNvbSIsImF1ZCI6ImFwaS5jdnNoZWFsdGguY29tIiwieC1jbGllbnQtaWQiOiJmQ1I5QTl2ekp5ZnNDS0JZazN4dkduWjNiSzlBN2hEcSIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwiLCJpc3MiOiJhcGkuY3Zzc3BlY2lhbHR5LmNvbSIsIngtbWVtYmVyLXRva2VuIjoiN2I0MDYyYzljMWU1NGNlZWFjZTlhMWIwNDA1YWY1ZTVjOTQ0ZWM3NGE3NjU0ZTIxODdjYzY4NTgzN2ZjMmQ4NCIsIngtbG9iIjoiU3BlY2lhbHR5IiwieC1ncmlkIjoicnJ0LTY1MzgwNjQ2NjI5NjI5NTEwNjMtYS1nd28xLTcyMTUtMTY5NTg2MjA2LTIiLCJ4LWNvbnRleHQtdHlwZSI6ImxvZ2luVG9rZW5DYWNoZSIsImV4cCI6MTY5NTkxNDI4NSwiaWF0IjoxNjk1OTEzNjg1LCJqdGkiOiI5OGZlM2Q1My0xYjI0LTQ0YzItYWYwMy01MTFjYzFmMTZkY2YifQ.VziaVRLD5rsBbZjlPqWfOsu0sNWBl0ujOkSEt4H5CL8hL9DdiNAnT5TK7t1hJKb70r3AxPrXDELhX6ozmX05Gz8n3FIAKFk2ridgZrn9CYz5A2taAFXgOmRY1zdF7urizZr5Mx_Nw10UxxdG-Ae7AZ52u561Y9hUl0d7C8S_Qw09N3v7ogp2eE_EDXSapV82hgZIQkK-AE7Xn0ooC2NS_PlH90ZreiY_wtoJLmor-fqVgMs4RAOpl4CSYh5JUNVP-aTUNtDrKdoTWAFsBfOBBVvKD2jZQN4_tluW27t0pyMd-eYcrnVQhZ6Vw3Hsy8k-szNBjlS4icrHj1_iJVnTvw',
'user-agent': 'PostmanRuntime/7.28.4',
accept: '*/*',
'postman-token': 'd815d09b-853c-49e1-9e5c-053c661fd919',
host: 'localhost:21120',
'accept-encoding': 'gzip, deflate, br',
connection: 'keep-alive',
'content-length': '18893',
isExpired: true,
case: 'questions'
};
const jsonDataResult = ProcessfulfillmentHelper.getJsonDataResult(headers.case);
try {
await processService.callExperienceApi(
agentName,
intentName,
headers,
jsonDataResult,
);
} catch (e) {
expect(e.status).toBe(401);
}
});
});
});</pre>
<p> </p>
<p>Here is my controller</p>
<p> </p>
<pre>
import {Body, Controller, HttpCode,HttpException, Logger, Post, Req} from '@nestjs/common';
import { ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
import { Request } from 'express';
import ProcessService from './process.service';
import { IntentRequestModel } from './model/IntentRequest.model';
import CryptoUtil from '../applib/util/crypto.util';
import {IntentRequestCustomValidator} from "./model/custom-validator/intent-req-validator";
import { ConfigService } from "@nestjs/config";
import {IntentRequestModelV2} from "./model/IntentRequestV2.model";
import {IntentRequestCustomValidatorV2} from "./model/custom-validator/intent-req-validator-v2";
/**
* Fulfillment Process Controller
*/
@Controller('/microservices/chat-fulfillment/process')
@ApiTags('process')
export default class ProcessController {
/**
* Construction
* @param processService - Process Service
*/
private readonly encryptkey: string;
constructor(private readonly processService: ProcessService, private readonly cryptoUtil: CryptoUtil, private readonly configService: ConfigService) {
this.encryptkey = this.configService.get<string>('info.app.encrypt-key');
}
@HttpCode(200)
@Post('/v1/processFulfillment')
@ApiOperation({ summary: 'Process Fulfillment' })
@ApiResponse({
status: 200,
description: 'Process Fulfillment Successfully',
})
async processFulfillment(@Req() request: Request, @IntentRequestCustomValidator() @Body() intentRequestModel: IntentRequestModel) {
const { agentName, intentName } = intentRequestModel;
new Logger().log(`starting process fulfillment request for ${intentName} with payload: `, JSON.stringify(intentRequestModel));
let experienceResult = {};
let jsonDataResult = {};
jsonDataResult = await this.processService.processJsonData(intentRequestModel.jsonData, intentName);
if (this.requiresExpCall(agentName, intentName)) {
experienceResult = await this.processService.callExperienceApi(
agentName,
intentName,
request.headers,
jsonDataResult,
);
if (experienceResult['error']) {
throw new HttpException(experienceResult['error'], experienceResult['error'].status);
}
}
return {
status: 'success',
experienceResult ,
};
}
@HttpCode(200)
@Post('/v2/processFulfillment')
@ApiOperation({ summary: 'Process Fulfillment' })
@ApiResponse({
status: 200,
description: 'Process Fulfillment Successfully',
})
async processV2Fulfillment(@Req() request: Request, @IntentRequestCustomValidatorV2() @Body() intentRequestModel: IntentRequestModelV2) {
const { agentName,intentName,jsonData,conversationId } = intentRequestModel;
new Logger().log(`starting process fulfillment request for ${intentName} with payload: `, JSON.stringify(intentRequestModel));
let experienceResult = {};
let jsonDataResult = {};
await this.processService.handleCacheLogic(agentName,intentName,conversationId,jsonData);
jsonDataResult = await this.processService.processJsonData(intentRequestModel.jsonData, intentName);
if (this.requiresExpCall(agentName, intentName)) {
experienceResult = await this.processService.callExperienceApi(
agentName,
intentName,
request.headers,
jsonDataResult,
);
if (experienceResult['error']) {
throw new HttpException(experienceResult['error'], experienceResult['error'].status);
}
}
return {
status: 'success',
experienceResult ,
};
}
private requiresExpCall(agentName: string, intentName: string): boolean {
const agentConfig = this.processService.getAgentConfig(agentName);
return Boolean(agentConfig.Intents[intentName].serviceUrl);
}
}
</pre>
<p>Here is my service clsaa</p>
<pre>
import { HttpException, HttpStatus, Injectable, Logger, NotFoundException } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import UtilService from 'src/common/utility/common.util';
import { ConfigService } from '@nestjs/config';
import AxiosUtil from '../applib/util/axios.util';
import CryptoUtil from '../applib/util/crypto.util';
@Injectable()
export default class ProcessService {
private agentsConfig: any;
private readonly encryptkey: string;
private readonly getCacheUrl: string;
private readonly setCacheUrl: string;
private readonly purgeCacheUrl: string;
constructor(
private readonly axiosUtil: AxiosUtil,
private readonly cryptoUtil: CryptoUtil,
private http: HttpService,
private utilService: UtilService,
private readonly configService: ConfigService,
) {
this.agentsConfig = this.configService.get<any[]>('Agents');
this.encryptkey = this.configService.get<string>('info.app.encrypt-key');
this.getCacheUrl = this.configService.get<string>('info.app.services.cacheservice.get.url');
this.setCacheUrl = this.configService.get<string>('info.app.services.cacheservice.set.url');
this.purgeCacheUrl = this.configService.get<string>('info.app.services.cacheservice.purge.url');
}
private deepCopy(obj:any)
{
return JSON.parse(JSON.stringify(obj));
}
getAgentConfig(agentName: string): any {
return this.agentsConfig.find((agent) => agent.name === agentName);
}
getStartEndDate(numberofdays: number): any {
let startDate = this.utilService.getFormatedData(new Date().setDate(new Date().getDate() - numberofdays));
let endDate = this.utilService.getFormatedData(new Date());
return {startDate,endDate};
}
getIntentPayload(agentName: string, intentName: string) : any{
const agentConfig = this.getAgentConfig(agentName);
const intentConfig = agentConfig.Intents[intentName];
return this.deepCopy({ ...intentConfig.request });
}
getIntentConfig(agentName: string, intentName: string) : any{
const agentConfig = this.getAgentConfig(agentName);
const intentConfig = agentConfig.Intents[intentName];
return this.deepCopy({ ...intentConfig });
}
async callExperienceApi(agentName: string, intentName: string, headers: any, processedData: any): Promise<any> {
new Logger().log("start calling experience API");
const agentConfig = this.getAgentConfig(agentName);
const intentConfig = agentConfig.Intents[intentName];
const apiUrl = intentConfig.serviceUrl;
const intentHeaders = intentConfig.headers || {};
headers = { ...intentHeaders, ...headers };
const headersToExclude = ['content-length', 'host'];
for (const header of headersToExclude) {
delete headers[header];
}
let payload = this.deepCopy({ ...intentConfig.request });
const replacePlaceholders = (obj: any, parent: any = null, keyInParent: any = null, actionData: any = null) => {
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const value = obj[key];
if (key === 'fillMethod') continue;
if (key === 'items') {
let allItems = [];
// Extract intent from placeholder and get actionDataArray
value.forEach((v)=>{
const intent = extractIntent(v);
const actionDataArray = getActionData(intent, intentName);
// Check the fillMethod of the parent object
const fillMethod = obj.fillMethod || 'latest';
if (fillMethod === 'all') {
const newItems= actionDataArray.map((actionData) => {
let newItem = JSON.parse(JSON.stringify(v));
replacePlaceholders(newItem, null, null, actionData);
return newItem;
});
allItems = allItems.concat(newItems)
} else {
const latestActionData = getLatestActionData(intent, intentName);
const newItem = JSON.parse(JSON.stringify(v));
replacePlaceholders(newItem, null, null, latestActionData);
allItems.push(newItem)
}
});
parent[keyInParent] = allItems;
continue;
}
if (typeof value === 'string' && value.startsWith('$')) {
const [intent, field] = value.substr(1).split('.');
if(actionData && actionData['IntentName'] === intent)
{
const fieldValue = actionData[field];
obj[key] = (fieldValue!== undefined && fieldValue!==null) ? fieldValue : null;
} else {
const latestActionData = getLatestActionData(intent, intentName);
const fieldValue = latestActionData[field];
obj[key] = (fieldValue!== undefined && fieldValue!==null) ? fieldValue : null;
}
} else if (Array.isArray(value) || typeof value === 'object') {
replacePlaceholders(value, obj, key, actionData);
}
if(obj.enableStartEndDate === 'true'){
Object.assign(obj.data,this.getStartEndDate(intentConfig.numberOfDays))
delete obj.enableStartEndDate;
}
}
}
};
const extractIntent = (item: any) => {
for (const key in item) {
if (typeof item[key] === "string" && item[key].startsWith("$")) {
return item[key].substr(1).split(".")[0];
} else if (Array.isArray(item[key]) || typeof item[key] === "object") {
return extractIntent(item[key]);
}
}
};
const getActionData = (intent: string,intentName: string) => {
return processedData[intentName]?.userActions[intent] || processedData[intent]?.userActions[intent] || [];
};
const getLatestActionData = (intent: string, intentName: string) => {
const actionsData = getActionData(intent, intentName);
if (actionsData.length === 0) {
return {};
}
return actionsData.reduce(
(prev, current) => (parseInt(prev.seqNum) > parseInt(current.seqNum) ? prev : current),
{},
);
};
// Replace Placeholders
replacePlaceholders(payload);
new Logger().log(payload);
new Logger().log(headers);
const response = await this.postService(headers, apiUrl, payload);
const processElements = async (elements: any) => {
for (const element of elements) {
if (element.encParams && typeof element.encParams === 'object') {
// Convert the encParams object to a JSON string and encrypt it
const encryptedData = await this.encrypt(element.encParams);
// Replace the encData value in the action URL with the encrypted string
if(element.objectType === 'form')
{
if (element.submitButton && typeof element.submitButton === 'object')
{
element.submitButton.action = element.submitButton.action.replace(/metadata=/, `metadata=${encodeURIComponent(encryptedData)}`);
}
}
if(element.action)
{
element.action = element.action.replace(/metadata=/, `metadata=${encodeURIComponent(encryptedData)}`);
}
// Remove the encParams object
delete element.encParams;
}
if (element.elements && element.elements.length > 0) {
await processElements(element.elements)
}
}
};
// Encrypt the response
if (response && response.contents && response.contents.intent && response.contents.intent.content && response.contents.intent.content.elements) {
const elements = response.contents.intent.content.elements;
await processElements(elements);
}
return response;
}
public async postService(headers: any, URI: string, payload: any): Promise<any> {
console.log('url', URI);
new Logger().log('url', URI);
let response = null;
try {
response = await this.axiosUtil.getInstance().post(URI, payload, { headers });
new Logger().log("executed post service with response: ", JSON.stringify(response));
return response;
} catch (error) {
new Logger().log(error.message);
return {error: {...error, noModifyError: true}};
}
}
async cacheActions(actions, agentName, conversationID) {
const cacheKey = `${agentName}-${conversationID}-actions`;
const cacheValue = JSON.stringify(actions);
// Construct the payload for the cache service
const cachePayload = {
requestMetaData: {
appName: "CVS_APP",
lineOfBusiness: "Retail",
conversationID: conversationID
},
requestPayloadData: {
data: {
context: "chatfulfillment",
data: [{
key: cacheKey,
value: cacheValue
}]
}
}
};
const cacheHeaders = {
'Content-Type': 'application/json',
};
await this.postService(cacheHeaders, this.setCacheUrl, cachePayload);
}
async retrieveCachedActions(agentName, conversationID) {
const cacheKey = `${agentName}-${conversationID}-actions`;
const cachePayload = {
requestMetaData: {
appName: "CVS_APP",
lineOfBusiness: "Retail",
conversationID: conversationID
},
requestPayloadData: {
data: {
context: "chatfulfillment",
data: [{
key: cacheKey
}]
}
}
};
const cacheHeaders = {
'Content-Type': 'application/json',
};
try {
const response = await this.postService(cacheHeaders, this.getCacheUrl, cachePayload)
if (response.responseMetaData && response.responseMetaData.statusCode=='0000') {
return JSON.parse(response.responsePayloadData.data.map(item => item.value).filter(v => v));
}
else {
return [];
}
} catch (error) {
new Logger().error(`Error retrieving cached actions: ${error}`);
return []; // Return an empty array if there's an error
}
}
async purgeCache(agentName, conversationId) {
// Construct the key for cache purging
const cacheKey = `${agentName}-${conversationId}-actions`;
const headers = {
};
const purgeUrl = `${this.purgeCacheUrl}${encodeURIComponent(cacheKey)}`;
try {
await this.axiosUtil.getInstance().get(purgeUrl, { headers });
new Logger().log('Cache successfully purged');
} catch (error) {
new Logger().error(`Error purging cache: ${error}`);
}
}
public async encrypt(data: string): Promise<string> {
const dataToEncryptString = JSON.stringify(data);
const encryptedData = await this.cryptoUtil.encrypt(dataToEncryptString,this.encryptkey);
new Logger().log(encryptedData);
//TODO Revist the decrypt logic
const decryptedData = await this.cryptoUtil.decrypt( encryptedData,this.encryptkey);
new Logger().log(decryptedData);
new Logger().log('Decrypted Data:');
if (typeof decryptedData === 'string') {
const parsedData = JSON.parse(decryptedData);
if (typeof parsedData === 'object') {
new Logger().log('Decrypted Data:');
for (const prop in parsedData) {
if (parsedData.hasOwnProperty(prop)) {
new Logger().log(`${prop}: ${parsedData[prop]}`);
}
}
} else {
new Logger().log('Decrypted Data is not an object.');
}
} else {
new Logger().log('Decrypted Data is not a string.');
}
return encryptedData;
}
public async processJsonData(jsonData: any[], intent: string): Promise<any> {
new Logger().log("start processing jsondata: ", JSON.stringify(jsonData));
const resultMap = {};
for (const data of jsonData) {
const index: number = jsonData.indexOf(data);
const messagesDisplayed: string[] = [];
const optionsDisplayed: string[] = [];
const userActions = data.actions || [];
for (let actionIndex = 0; actionIndex < userActions.length; actionIndex++) {
const action = userActions[actionIndex];
if (action.metadata) {
try {
let decryptedData = await this.cryptoUtil.decrypt(action.metadata, this.encryptkey);
if (typeof decryptedData === 'string') {
const parsedData = JSON.parse(decryptedData);
if (typeof parsedData === 'object') {
// Merge parsedData into the original action object
data.actions[actionIndex] = {...action, ...parsedData};
} else {
new Logger().log('Decrypted Data is not an object.');
}
} else {
new Logger().log('Decrypted Data is not a string.');
}
} catch (error) {
console.error('Decryption error:', error);
}
}
}
// Grouping actions by IntentName
const actionsByIntent = data.actions.reduce((acc: any, action: any) => {
const intentName = action.IntentName;
if (!acc[intentName]) acc[intentName] = [];
acc[intentName].push(action);
return acc;
}, {});
const key = `${intent}`;
resultMap[key] = {
intent,
messagesDisplayed,
optionsDisplayed,
userActions: actionsByIntent,
};
}
return resultMap;
}
async handleCacheLogic(agentName, intentName, conversationId, jsonData) {
const payload = this.getIntentConfig(agentName, intentName);
// Purge the cache if the resetcache is true
if (payload && payload.resetcache) {
await this.purgeCache(agentName, conversationId);
}
// Retrieve and prepend cached actions if resetcache is not true
if (payload && !payload.resetcache && jsonData && jsonData[0] && jsonData[0].actions) {
const cachedActions = await this.retrieveCachedActions(agentName, conversationId);
if (cachedActions.length > 0) {
jsonData[0].actions = [...cachedActions, ...jsonData[0].actions];
}
}
if (jsonData && jsonData[0] && jsonData[0].actions) {
if (jsonData[0].actions.length > 0)
await this.cacheActions(jsonData[0].actions, agentName, conversationId);
}
}
}
</pre>
<p> </p>
<p>What changes needs to be done to fix </p>
<p> ● Chat fulfillment › get process fullfillment for question intent</p>
<p> TypeError: this.processService.processJsonData is not a function</p>
<p> </p>