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

PIN-5776 descriptor state waiting for approval changes and analysis #1325

Open
wants to merge 15 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 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
13 changes: 8 additions & 5 deletions packages/api-gateway/src/api/catalogApiConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import {
} from "pagopa-interop-api-clients";
import { Logger } from "pagopa-interop-commons";
import {
assertNonDraftDescriptor,
assertNotValidDescriptor,
assertRegistryAttributeExists,
} from "../services/validators.js";

export type NonDraftCatalogApiDescriptor = catalogApi.EServiceDescriptor & {
state: Exclude<catalogApi.EServiceDescriptorState, "DRAFT">;
export type validCatalogApiDescriptor = catalogApi.EServiceDescriptor & {
Viktor-K marked this conversation as resolved.
Show resolved Hide resolved
state: Exclude<
catalogApi.EServiceDescriptorState,
"DRAFT" | "WAITING_FOR_APPROVAL"
>;
};

export function toApiGatewayCatalogEservice(
Expand Down Expand Up @@ -94,12 +97,12 @@ export function toApiGatewayDescriptorDocument(
};
}

export function toApiGatewayDescriptorIfNotDraft(
export function toApiGatewayDescriptorIfIsValid(
descriptor: catalogApi.EServiceDescriptor,
eserviceId: catalogApi.EService["id"],
logger: Logger
): apiGatewayApi.EServiceDescriptor {
assertNonDraftDescriptor(descriptor, descriptor.id, eserviceId, logger);
assertNotValidDescriptor(descriptor, eserviceId, logger);

return {
id: descriptor.id,
Expand Down
71 changes: 30 additions & 41 deletions packages/api-gateway/src/services/catalogService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,30 @@ import {
removeDuplicates,
WithLogger,
} from "pagopa-interop-commons";
import {
toApiGatewayCatalogEservice,
toApiGatewayDescriptorIfIsValid,
toApiGatewayEserviceAttributes,
validCatalogApiDescriptor,
} from "../api/catalogApiConverter.js";
import { clientStatusCodeToError } from "../clients/catchClientError.js";
import {
AttributeProcessClient,
CatalogProcessClient,
TenantProcessClient,
} from "../clients/clientsProvider.js";
import { ApiGatewayAppContext } from "../utilities/context.js";
import {
NonDraftCatalogApiDescriptor,
toApiGatewayCatalogEservice,
toApiGatewayDescriptorIfNotDraft,
toApiGatewayEserviceAttributes,
} from "../api/catalogApiConverter.js";
import {
eserviceDescriptorNotFound,
eserviceNotFound,
} from "../models/errors.js";
import { clientStatusCodeToError } from "../clients/catchClientError.js";
import { ApiGatewayAppContext } from "../utilities/context.js";
import { getAllBulkAttributes } from "./attributeService.js";
import { getOrganization } from "./tenantService.js";
import {
assertAvailableDescriptorExists,
assertNonDraftDescriptor,
assertNotValidDescriptor,
validDescriptorStates,
} from "./validators.js";
import { getAllBulkAttributes } from "./attributeService.js";
import { getOrganization } from "./tenantService.js";

export function getAllEservices(
catalogProcessClient: CatalogProcessClient,
Expand Down Expand Up @@ -132,7 +133,7 @@ export function catalogServiceBuilder(

const descriptor = retrieveEserviceDescriptor(eservice, descriptorId);

return toApiGatewayDescriptorIfNotDraft(descriptor, eserviceId, logger);
return toApiGatewayDescriptorIfIsValid(descriptor, eserviceId, logger);
},
getEserviceDescriptors: async (
{ logger, headers }: WithLogger<ApiGatewayAppContext>,
Expand All @@ -147,16 +148,16 @@ export function catalogServiceBuilder(
);

const descriptors = eservice.descriptors
.filter(isNonDraft)
.map((d) => toApiGatewayDescriptorIfNotDraft(d, eserviceId, logger));
.filter(isValidDescriptorState)
.map((d) => toApiGatewayDescriptorIfIsValid(d, eserviceId, logger));

return { descriptors };
},
};
}

const isNonDraft = (d: catalogApi.EServiceDescriptor): boolean =>
d.state !== catalogApi.EServiceDescriptorState.Values.DRAFT;
const isValidDescriptorState = (d: catalogApi.EServiceDescriptor): boolean =>
validDescriptorStates.includes(d.state);
ecamellini marked this conversation as resolved.
Show resolved Hide resolved

function retrieveEserviceDescriptor(
eservice: catalogApi.EService,
Expand All @@ -171,34 +172,25 @@ function retrieveEserviceDescriptor(
return descriptor;
}

function getLatestNonDraftDescriptor(
function getLatestValidDescriptor(
eservice: catalogApi.EService,
logger: Logger
): NonDraftCatalogApiDescriptor {
const latestNonDraftDescriptor = eservice.descriptors
.filter(isNonDraft)
): validCatalogApiDescriptor {
const latestValidDescriptor = eservice.descriptors
.filter(isValidDescriptorState)
.sort((a, b) => Number(a.version) - Number(b.version))
.at(-1);

assertAvailableDescriptorExists(
latestNonDraftDescriptor,
eservice.id,
logger
);
assertNonDraftDescriptor(
latestNonDraftDescriptor,
latestNonDraftDescriptor.id,
eservice.id,
logger
);
assertAvailableDescriptorExists(latestValidDescriptor, eservice.id, logger);
assertNotValidDescriptor(latestValidDescriptor, eservice.id, logger);

return latestNonDraftDescriptor;
return latestValidDescriptor;
}

async function getDescriptorAttributes(
attributeProcessClient: AttributeProcessClient,
headers: ApiGatewayAppContext["headers"],
descriptor: NonDraftCatalogApiDescriptor
descriptor: validCatalogApiDescriptor
): Promise<apiGatewayApi.EServiceAttributes> {
const allDescriptorAttributesIds = removeDuplicates(
[
Expand Down Expand Up @@ -227,14 +219,11 @@ export async function enhanceEservice(
eservice: catalogApi.EService,
logger: Logger
): Promise<apiGatewayApi.EService> {
const latestNonDraftDescriptor = getLatestNonDraftDescriptor(
eservice,
logger
);
const latestValidDescriptor = getLatestValidDescriptor(eservice, logger);
const descriptorAttributes = await getDescriptorAttributes(
attributeProcessClient,
headers,
latestNonDraftDescriptor
latestValidDescriptor
);

const producerOrganization = await getOrganization(
Expand All @@ -249,10 +238,10 @@ export async function enhanceEservice(
name: eservice.name,
description: eservice.description,
technology: eservice.technology,
version: latestNonDraftDescriptor.version,
version: latestValidDescriptor.version,
attributes: descriptorAttributes,
state: latestNonDraftDescriptor.state,
serverUrls: latestNonDraftDescriptor.serverUrls,
state: latestValidDescriptor.state,
serverUrls: latestValidDescriptor.serverUrls,
producer: producerOrganization,
isSignalHubEnabled: eservice.isSignalHubEnabled,
};
Expand Down
27 changes: 19 additions & 8 deletions packages/api-gateway/src/services/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,31 @@ import {
delegationApi,
purposeApi,
} from "pagopa-interop-api-clients";
import { operationForbidden, TenantId } from "pagopa-interop-models";
import { Logger } from "pagopa-interop-commons";
import { operationForbidden, TenantId } from "pagopa-interop-models";
import { validCatalogApiDescriptor } from "../api/catalogApiConverter.js";
import {
activeAgreementByEserviceAndConsumerNotFound,
attributeNotFoundInRegistry,
invalidAgreementState,
missingActivePurposeVersion,
missingAvailableDescriptor,
multipleActiveProducerDelegationsForEservice,
multipleAgreementForEserviceAndConsumer,
unexpectedDescriptorState,
multipleActiveProducerDelegationsForEservice,
} from "../models/errors.js";
import { NonDraftCatalogApiDescriptor } from "../api/catalogApiConverter.js";

export const invalidDescriptorStates: catalogApi.EServiceDescriptorState[] = [
catalogApi.EServiceDescriptorState.Values.DRAFT,
catalogApi.EServiceDescriptorState.Values.WAITING_FOR_APPROVAL,
];

export const validDescriptorStates: catalogApi.EServiceDescriptorState[] = [
catalogApi.EServiceDescriptorState.Values.ARCHIVED,
catalogApi.EServiceDescriptorState.Values.DEPRECATED,
catalogApi.EServiceDescriptorState.Values.PUBLISHED,
catalogApi.EServiceDescriptorState.Values.SUSPENDED,
];

export function assertAgreementStateNotDraft(
agreementState: agreementApi.AgreementState,
Expand Down Expand Up @@ -71,17 +83,16 @@ export function assertAvailableDescriptorExists(
}
}

export function assertNonDraftDescriptor(
export function assertNotValidDescriptor(
Viktor-K marked this conversation as resolved.
Show resolved Hide resolved
descriptor: catalogApi.EServiceDescriptor,
descriptorId: catalogApi.EServiceDescriptor["id"],
eserviceId: catalogApi.EService["id"],
logger: Logger
): asserts descriptor is NonDraftCatalogApiDescriptor {
if (descriptor.state === catalogApi.EServiceDescriptorState.Values.DRAFT) {
): asserts descriptor is validCatalogApiDescriptor {
if (invalidDescriptorStates.includes(descriptor.state)) {
ecamellini marked this conversation as resolved.
Show resolved Hide resolved
throw unexpectedDescriptorState(
descriptor.state,
eserviceId,
descriptorId,
descriptor.id,
logger
);
}
Expand Down
25 changes: 11 additions & 14 deletions packages/backend-for-frontend/src/api/catalogApiConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,18 @@ import {
import { attributeNotExists } from "../model/errors.js";
import {
getLatestActiveDescriptor,
getNotDraftDescriptor,
getLatestTenantContactEmail,
getValidDescriptor,
} from "../model/modelMappingUtils.js";
import { ConfigurationRiskAnalysis } from "../model/types.js";
import {
isRequesterEserviceProducer,
hasCertifiedAttributes,
isAgreementSubscribed,
isAgreementUpgradable,
hasCertifiedAttributes,
isInvalidDescriptor,
isRequesterEserviceProducer,
isValidDescriptor,
} from "../services/validators.js";
import {
ConfigurationRiskAnalysis,
catalogApiDescriptorState,
} from "../model/types.js";
import { toBffCompactAgreement } from "./agreementApiConverter.js";

export function toEserviceCatalogProcessQueryParams(
Expand Down Expand Up @@ -105,7 +104,7 @@ export function toBffCatalogDescriptorEService(
},
description: eservice.description,
technology: eservice.technology,
descriptors: getNotDraftDescriptor(eservice).map(toCompactDescriptor),
descriptors: getValidDescriptor(eservice).map(toCompactDescriptor),
agreement: agreement && toBffCompactAgreement(agreement, eservice),
isMine: isRequesterEserviceProducer(requesterTenant.id, eservice),
hasCertifiedAttributes: hasCertifiedAttributes(descriptor, requesterTenant),
Expand Down Expand Up @@ -240,14 +239,10 @@ export function toBffCatalogApiProducerDescriptorEService(
const producerMail = getLatestTenantContactEmail(producer);

const notDraftDecriptors = eservice.descriptors
.filter((d) => d.state !== catalogApiDescriptorState.DRAFT)
.filter(isValidDescriptor)
.map(toCompactDescriptor);

const draftDescriptor = eservice.descriptors.find(
(d) =>
d.state === catalogApiDescriptorState.DRAFT ||
d.state === catalogApiDescriptorState.WAITING_FOR_APPROVAL
);
const draftDescriptor = eservice.descriptors.find(isInvalidDescriptor);

return {
id: eservice.id,
Expand Down Expand Up @@ -378,6 +373,8 @@ export function toCompactProducerDescriptor(
version: descriptor.version,
requireCorrections:
isRequesterProducerDelegate &&
// The WAITING_FOR_APPROVAL state is not relevant for the producer descriptor's requireCorrections field,
// so we don't consider it when determining whether corrections are required.
descriptor.state === catalogApi.EServiceDescriptorState.Values.DRAFT &&
descriptor.rejectionReasons &&
descriptor.rejectionReasons.length > 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ const activeDescriptorStatesFilter: catalogApi.EServiceDescriptorState[] = [
catalogApiDescriptorState.DEPRECATED,
];

const invalidDescriptorState: catalogApi.EServiceDescriptorState[] = [
catalogApiDescriptorState.DRAFT,
catalogApiDescriptorState.WAITING_FOR_APPROVAL,
];

export function getLatestActiveDescriptor(
eservice: catalogApi.EService
): catalogApi.EServiceDescriptor | undefined {
Expand All @@ -26,11 +31,11 @@ export function getLatestActiveDescriptor(
.at(-1);
}

export function getNotDraftDescriptor(
export function getValidDescriptor(
eservice: catalogApi.EService
): catalogApi.EServiceDescriptor[] {
return eservice.descriptors.filter(
(d) => d.state !== catalogApiDescriptorState.DRAFT
(d) => !invalidDescriptorState.includes(d.state)
);
}

Expand Down
12 changes: 3 additions & 9 deletions packages/backend-for-frontend/src/services/catalogService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,14 @@ import {
toBffCatalogApiEserviceRiskAnalysisSeed,
toCompactProducerDescriptor,
} from "../api/catalogApiConverter.js";
import {
catalogApiDescriptorState,
ConfigurationEservice,
} from "../model/types.js";
import { ConfigurationEservice } from "../model/types.js";
import { getAllAgreements, getLatestAgreement } from "./agreementService.js";
import { getAllBulkAttributes } from "./attributeService.js";
import {
assertNotDelegatedEservice,
assertRequesterIsProducer,
assertRequesterCanActAsProducer,
isInvalidDescriptor,
} from "./validators.js";

export type CatalogService = ReturnType<typeof catalogServiceBuilder>;
Expand Down Expand Up @@ -117,11 +115,7 @@ const enhanceProducerEService = (
requesterId: TenantId
): bffApi.ProducerEService => {
const activeDescriptor = getLatestActiveDescriptor(eservice);
const draftDescriptor = eservice.descriptors.find(
(d) =>
d.state === catalogApiDescriptorState.DRAFT ||
d.state === catalogApiDescriptorState.WAITING_FOR_APPROVAL
);
const draftDescriptor = eservice.descriptors.find(isInvalidDescriptor);

const isRequesterDelegateProducer = requesterId !== eservice.producerId;

Expand Down
26 changes: 25 additions & 1 deletion packages/backend-for-frontend/src/services/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,30 @@ import {
import { BffAppContext } from "../utilities/context.js";
import { getAllDelegations } from "./delegationService.js";

export const invalidDescriptorStates: catalogApi.EServiceDescriptorState[] = [
catalogApi.EServiceDescriptorState.Values.DRAFT,
catalogApi.EServiceDescriptorState.Values.WAITING_FOR_APPROVAL,
];

export const validDescriptorStates: catalogApi.EServiceDescriptorState[] = [
catalogApi.EServiceDescriptorState.Values.PUBLISHED,
catalogApi.EServiceDescriptorState.Values.DEPRECATED,
catalogApi.EServiceDescriptorState.Values.SUSPENDED,
catalogApi.EServiceDescriptorState.Values.ARCHIVED,
];

export function isValidDescriptor(
descriptor: catalogApi.EServiceDescriptor
): boolean {
return validDescriptorStates.includes(descriptor.state);
}

export function isInvalidDescriptor(
descriptor: catalogApi.EServiceDescriptor
): boolean {
return invalidDescriptorStates.includes(descriptor.state);
}
ecamellini marked this conversation as resolved.
Show resolved Hide resolved

export function isRequesterEserviceProducer(
requesterId: string,
eservice: catalogApi.EService
Expand Down Expand Up @@ -145,7 +169,7 @@ export function hasCertifiedAttributes(
export function verifyExportEligibility(
descriptor: catalogApi.EServiceDescriptor
): void {
if (descriptor.state === catalogApiDescriptorState.DRAFT) {
if (isValidDescriptor(descriptor)) {
throw notValidDescriptor(descriptor.id, descriptor.state);
}
}
Loading
Loading