Skip to content

Commit

Permalink
IMN-657 GET EService descriptor by ID (#712)
Browse files Browse the repository at this point in the history
Co-authored-by: Eric Camellini <eric.camellini@gmail.com>
  • Loading branch information
Viktor-K and ecamellini authored Jul 25, 2024
1 parent 3c2519e commit a9561da
Show file tree
Hide file tree
Showing 10 changed files with 665 additions and 51 deletions.
2 changes: 1 addition & 1 deletion packages/api-clients/src/bffApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { QueryParametersByAlias } from "./utils.js";

type BffApi = typeof bffApi.eservicesApi.api;

export type GetCatalogQueryParam = QueryParametersByAlias<
export type BffGetCatalogQueryParam = QueryParametersByAlias<
BffApi,
"getEServicesCatalog"
>;
Expand Down
2 changes: 1 addition & 1 deletion packages/bff/src/model/api/apiConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function toDescriptorWithOnlyAttributes(
}

export function toEserviceCatalogProcessQueryParams(
queryParams: bffApi.GetCatalogQueryParam
queryParams: bffApi.BffGetCatalogQueryParam
): catalogApi.GetCatalogQueryParam {
return {
...queryParams,
Expand Down
219 changes: 219 additions & 0 deletions packages/bff/src/model/api/converters/catalogClientApiConverter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
/* eslint-disable functional/immutable-data */
/* eslint-disable max-params */
import { DescriptorWithOnlyAttributes } from "pagopa-interop-agreement-lifecycle";
import {
agreementApi,
attributeRegistryApi,
bffApi,
catalogApi,
tenantApi,
} from "pagopa-interop-api-clients";
import { EServiceAttribute, unsafeBrandId } from "pagopa-interop-models";
import { attributeNotExists } from "../../domain/errors.js";
import { getTenantEmail, isUpgradable } from "../../modelMappingUtils.js";
import { catalogApiDescriptorState } from "../apiTypes.js";

export function toEserviceCatalogProcessQueryParams(
queryParams: bffApi.BffGetCatalogQueryParam
): catalogApi.GetCatalogQueryParam {
return {
...queryParams,
eservicesIds: [],
name: queryParams.q,
};
}

export function toBffCatalogApiEService(
eservice: catalogApi.EService,
producerTenant: tenantApi.Tenant,
hasCertifiedAttributes: boolean,
isRequesterEqProducer: boolean,
activeDescriptor?: catalogApi.EServiceDescriptor,
agreement?: agreementApi.Agreement
): bffApi.CatalogEService {
const partialEnhancedEservice = {
id: eservice.id,
name: eservice.name,
description: eservice.description,
producer: {
id: eservice.producerId,
name: producerTenant.name,
},
isMine: isRequesterEqProducer,
hasCertifiedAttributes,
};

return {
...partialEnhancedEservice,
...(activeDescriptor
? {
activeDescriptor: {
id: activeDescriptor.id,
version: activeDescriptor.version,
audience: activeDescriptor.audience,
state: activeDescriptor.state,
},
}
: {}),
...(agreement
? {
agreement: {
id: agreement.id,
state: agreement.state,
canBeUpgraded: isUpgradable(eservice, agreement),
},
}
: {}),
};
}

export function toBffCatalogApiDescriptorAttribute(
attributes: attributeRegistryApi.Attribute[],
descriptorAttributes: catalogApi.Attribute[]
): bffApi.DescriptorAttribute[] {
return descriptorAttributes.map((attribute) => {
const foundAttribute = attributes.find((att) => att.id === attribute.id);
if (!foundAttribute) {
throw attributeNotExists(unsafeBrandId(attribute.id));
}

return {
id: attribute.id,
name: foundAttribute.name,
description: foundAttribute.description,
explicitAttributeVerification: attribute.explicitAttributeVerification,
};
});
}

export function toBffCatalogApiDescriptorDoc(
document: catalogApi.EServiceDoc
): bffApi.EServiceDoc {
return {
id: document.id,
name: document.name,
contentType: document.contentType,
prettyName: document.prettyName,
};
}

export function toBffCatalogApiEserviceRiskAnalysis(
riskAnalysis: catalogApi.EServiceRiskAnalysis
): bffApi.EServiceRiskAnalysis {
const answers: bffApi.RiskAnalysisForm["answers"] =
riskAnalysis.riskAnalysisForm.singleAnswers
.concat(
riskAnalysis.riskAnalysisForm.multiAnswers.flatMap((multiAnswer) =>
multiAnswer.values.map((answerValue) => ({
id: multiAnswer.id,
value: answerValue,
key: multiAnswer.key,
}))
)
)
.reduce((answers: bffApi.RiskAnalysisForm["answers"], answer) => {
const key = answer.key;
if (answers[key] && answer.value) {
answers[key] = [...answers[key], answer.value];
} else {
answers[key] = [];
}

return answers;
}, {});

const riskAnalysisForm: bffApi.RiskAnalysisForm = {
riskAnalysisId: riskAnalysis.id,
version: riskAnalysis.riskAnalysisForm.version,
answers,
};

return {
id: riskAnalysis.id,
name: riskAnalysis.name,
createdAt: riskAnalysis.createdAt,
riskAnalysisForm,
};
}

export function toBffCatalogApiProducerDescriptorEService(
eservice: catalogApi.EService,
producer: tenantApi.Tenant
): bffApi.ProducerDescriptorEService {
const producerMail = getTenantEmail(producer);

const notDraftDecriptors: bffApi.CompactDescriptor[] =
eservice.descriptors.filter(
(d) => d.state !== catalogApiDescriptorState.DRAFT
);

const draftDescriptor: bffApi.CompactDescriptor | undefined =
eservice.descriptors.find(
(d) => d.state === catalogApiDescriptorState.DRAFT
);

return {
id: eservice.id,
name: eservice.name,
description: eservice.description,
technology: eservice.technology,
mode: eservice.mode,
mail: producerMail && {
address: producerMail.address,
description: producerMail.description,
},
draftDescriptor,
riskAnalysis: eservice.riskAnalysis.map(
toBffCatalogApiEserviceRiskAnalysis
),
descriptors: notDraftDecriptors,
};
}

export function toEserviceAttribute(
attributes: catalogApi.Attribute[]
): EServiceAttribute[] {
return attributes.map((attribute) => ({
...attribute,
id: unsafeBrandId(attribute.id),
}));
}

export function toDescriptorWithOnlyAttributes(
descriptor: catalogApi.EServiceDescriptor
): DescriptorWithOnlyAttributes {
return {
...descriptor,
attributes: {
certified: descriptor.attributes.certified.map(toEserviceAttribute),
declared: descriptor.attributes.declared.map(toEserviceAttribute),
verified: descriptor.attributes.verified.map(toEserviceAttribute),
},
};
}

export function toBffCatalogApiDescriptorAttributes(
attributes: attributeRegistryApi.Attribute[],
descriptor: catalogApi.EServiceDescriptor
): bffApi.DescriptorAttributes {
return {
certified: [
toBffCatalogApiDescriptorAttribute(
attributes,
descriptor.attributes.certified.flat()
),
],
declared: [
toBffCatalogApiDescriptorAttribute(
attributes,
descriptor.attributes.declared.flat()
),
],
verified: [
toBffCatalogApiDescriptorAttribute(
attributes,
descriptor.attributes.verified.flat()
),
],
};
}
64 changes: 64 additions & 0 deletions packages/bff/src/model/api/converters/tenantClientApiConverters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { TenantWithOnlyAttributes } from "pagopa-interop-agreement-lifecycle";
import { tenantApi } from "pagopa-interop-api-clients";
import {
CertifiedTenantAttribute,
DeclaredTenantAttribute,
TenantAttribute,
VerifiedTenantAttribute,
tenantAttributeType,
unsafeBrandId,
} from "pagopa-interop-models";

export function toTenantAttribute(
att: tenantApi.TenantAttribute
): TenantAttribute[] {
const certified: CertifiedTenantAttribute | undefined = att.certified && {
id: unsafeBrandId(att.certified.id),
type: tenantAttributeType.CERTIFIED,
revocationTimestamp: att.certified.revocationTimestamp
? new Date(att.certified.revocationTimestamp)
: undefined,
assignmentTimestamp: new Date(att.certified.assignmentTimestamp),
};

const verified: VerifiedTenantAttribute | undefined = att.verified && {
id: unsafeBrandId(att.verified.id),
type: tenantAttributeType.VERIFIED,
assignmentTimestamp: new Date(att.verified.assignmentTimestamp),
verifiedBy: att.verified.verifiedBy.map((v) => ({
id: v.id,
verificationDate: new Date(v.verificationDate),
expirationDate: v.expirationDate ? new Date(v.expirationDate) : undefined,
extensionDate: v.extensionDate ? new Date(v.extensionDate) : undefined,
})),
revokedBy: att.verified.revokedBy.map((r) => ({
id: r.id,
verificationDate: new Date(r.verificationDate),
revocationDate: new Date(r.revocationDate),
expirationDate: r.expirationDate ? new Date(r.expirationDate) : undefined,
extensionDate: r.extensionDate ? new Date(r.extensionDate) : undefined,
})),
};

const declared: DeclaredTenantAttribute | undefined = att.declared && {
id: unsafeBrandId(att.declared.id),
type: tenantAttributeType.DECLARED,
assignmentTimestamp: new Date(att.declared.assignmentTimestamp),
revocationTimestamp: att.declared.revocationTimestamp
? new Date(att.declared.revocationTimestamp)
: undefined,
};

return [certified, verified, declared].filter(
(a): a is TenantAttribute => !!a
);
}

export function toTenantWithOnlyAttributes(
tenant: tenantApi.Tenant
): TenantWithOnlyAttributes {
return {
...tenant,
attributes: tenant.attributes.map(toTenantAttribute).flat(),
};
}
44 changes: 39 additions & 5 deletions packages/bff/src/model/domain/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@ import {
ApiError,
PurposeId,
makeApiProblemBuilder,
AttributeId,
} from "pagopa-interop-models";

export const errorCodes = {
purposeNotFound: "0001",
missingClaim: "0002",
tenantLoginNotAllowed: "0003",
tokenVerificationFailed: "0004",
userNotFound: "0005",
selfcareEntityNotFilled: "0006",
userNotFound: "0002",
selfcareEntityNotFilled: "0003",
descriptorNotFound: "0004",
attributeNotExists: "0005",
invalidEserviceRequester: "0006",
missingClaim: "0007",
tenantLoginNotAllowed: "0008",
tokenVerificationFailed: "0009",
};

export type ErrorCodes = keyof typeof errorCodes;
Expand Down Expand Up @@ -47,6 +51,36 @@ export function purposeNotFound(purposeId: PurposeId): ApiError<ErrorCodes> {
});
}

export function invalidEServiceRequester(
eServiceId: string,
requesterId: string
): ApiError<ErrorCodes> {
return new ApiError({
detail: `EService ${eServiceId} does not belong to producer ${requesterId}`,
code: "invalidEserviceRequester",
title: `Invalid eservice requester`,
});
}

export function eserviceDescriptorNotFound(
eServiceId: string,
descriptorId: string
): ApiError<ErrorCodes> {
return new ApiError({
detail: `Descriptor ${descriptorId} not found in Eservice ${eServiceId}`,
code: "descriptorNotFound",
title: `Descriptor not found`,
});
}

export function attributeNotExists(id: AttributeId): ApiError<ErrorCodes> {
return new ApiError({
detail: `Attribute ${id} does not exist in the attribute registry`,
code: "attributeNotExists",
title: "Attribute not exists",
});
}

export function missingClaim(claimName: string): ApiError<ErrorCodes> {
return new ApiError({
detail: `Claim ${claimName} has not been passed`,
Expand Down
Loading

0 comments on commit a9561da

Please sign in to comment.