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

Feature: Capofila #1175

Open
wants to merge 21 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
bdd832b
PIN-5442 - Update e-service request caller assertions to accept deleg…
Carminepo2 Nov 5, 2024
ae502ae
PIN-5481 agreement documents (#1157)
sandrotaje Nov 5, 2024
a6ec8c2
PIN-5484 activate agreement with delegation (#1162)
sandrotaje Nov 6, 2024
4e0b31b
IMN-5483 suspend agreement (#1169)
sandrotaje Nov 7, 2024
81173c5
Fix merge problems
Carminepo2 Nov 7, 2024
ab8c08c
Renamed processPublishDescriptorUpdate
Carminepo2 Nov 11, 2024
af285de
PIN-5483 PIN-5487 reject agreement (#1171)
sandrotaje Nov 11, 2024
420c34c
Merge branch 'main' into feature/pin-5126-capofila
Carminepo2 Nov 12, 2024
7e74a11
Bump interop outbound models
Carminepo2 Nov 13, 2024
96f429c
Merge branch 'main' into feature/pin-5126-capofila
Carminepo2 Nov 13, 2024
3e62bc6
PIN-5641 - Add features filter in get tenants (#1182)
Carminepo2 Nov 14, 2024
a61b641
PIN-5640 - Add `delegated` filter in `GET /eservices` (#1179)
Carminepo2 Nov 14, 2024
e8b6d33
PIN-5203 - Updated purpose process for producer delegations (#1151)
Carminepo2 Nov 14, 2024
30d54ea
PIN-5656 fix suspend agreement (#1183)
sandrotaje Nov 14, 2024
fc8770c
Merge branch 'main' into feature/pin-5126-capofila
Carminepo2 Nov 14, 2024
0428c28
PIN-5605 - Allow delegate to retrieve purpose in api-gateway (#1168)
Carminepo2 Nov 14, 2024
1720855
PIN-5488 agreement listing (#1154)
sandrotaje Nov 15, 2024
7d65bda
Merge branch 'develop' into feature/pin-5126-capofila
sandrotaje Nov 20, 2024
3b5542e
Merge branch 'develop' into feature/pin-5126-capofila
Carminepo2 Nov 22, 2024
3223eeb
Merge branch 'develop' into feature/pin-5126-capofila
Carminepo2 Nov 22, 2024
6846e45
Fix merge problems
Carminepo2 Nov 22, 2024
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
4 changes: 2 additions & 2 deletions packages/agreement-outbound-writer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"vitest": "1.6.0"
},
"dependencies": {
"@pagopa/interop-outbound-models": "1.0.10",
"@pagopa/interop-outbound-models": "1.0.11a",
"@protobuf-ts/runtime": "2.9.4",
"connection-string": "4.4.0",
"dotenv-flow": "4.1.0",
Expand All @@ -40,4 +40,4 @@
"ts-pattern": "5.2.0",
"zod": "3.23.8"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,64 @@ export const assertRequesterIsConsumerOrProducer = (
}
};

export const assertRequesterIsConsumerOrProducerOrDelegate = async (
agreement: Agreement,
authData: AuthData,
readModelService: ReadModelService
): Promise<void> => {
try {
assertRequesterIsConsumer(agreement, authData);
} catch (error) {
try {
assertRequesterIsProducer(agreement, authData);
} catch (error) {
const delegation = await readModelService.getDelegationByDelegateId(
authData.organizationId
);
assertRequesterIsDelegate(delegation?.data.delegateId, authData);
}
}
};

export const assertRequesterIsProducerOrDelegate = (
agreement: Agreement,
delegateIdActiveDelegation: TenantId | undefined,
authData: AuthData
): void => {
if (delegateIdActiveDelegation) {
assertRequesterIsDelegate(delegateIdActiveDelegation, authData);
} else {
assertRequesterIsProducer(agreement, authData);
}
};

export const assertRequesterIsDelegate = (
delegateId: TenantId | undefined,
authData: AuthData
): void => {
if (authData.organizationId !== delegateId) {
throw operationNotAllowed(authData.organizationId);
}
};

export const assertRequesterCanActivate = (
agreement: Agreement,
delegateIdActiveDelegation: TenantId | undefined,
authData: AuthData
): void => {
try {
assertRequesterIsConsumer(agreement, authData);
} catch (e) {
if (delegateIdActiveDelegation) {
assertRequesterIsDelegate(delegateIdActiveDelegation, authData);
} else {
assertRequesterIsProducer(agreement, authData);
}
}
};

export const assertRequesterCanSuspend = assertRequesterCanActivate;

export const assertSubmittableState = (
state: AgreementState,
agreementId: AgreementId
Expand Down Expand Up @@ -207,8 +265,15 @@ const validateLatestDescriptor = (
descriptorId: DescriptorId,
allowedStates: DescriptorState[]
): Descriptor => {
const activeDescriptorStates: DescriptorState[] = [
descriptorState.archived,
descriptorState.deprecated,
descriptorState.published,
descriptorState.suspended,
];

const recentActiveDescriptors = eservice.descriptors
.filter((d) => d.state !== descriptorState.draft)
.filter((d) => activeDescriptorStates.includes(d.state))
.sort((a, b) => Number(b.version) - Number(a.version));

if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
Descriptor,
EService,
Tenant,
TenantId,
UserId,
agreementState,
genericError,
Expand Down Expand Up @@ -47,6 +48,7 @@ export function createActivationUpdateAgreementSeed({
suspendedByConsumer,
suspendedByProducer,
suspendedByPlatform,
delegateId,
}: {
isFirstActivation: boolean;
newState: AgreementState;
Expand All @@ -58,8 +60,9 @@ export function createActivationUpdateAgreementSeed({
suspendedByConsumer: boolean | undefined;
suspendedByProducer: boolean | undefined;
suspendedByPlatform: boolean | undefined;
delegateId?: TenantId | undefined;
}): UpdateAgreementSeed {
const stamp = createStamp(authData.userId);
const stamp = createStamp(authData.userId, delegateId);

return isFirstActivation
? {
Expand Down Expand Up @@ -113,7 +116,8 @@ export async function createActivationEvent(
suspendedByPlatformChanged: boolean,
agreementEventStoreVersion: number,
authData: AuthData,
correlationId: CorrelationId
correlationId: CorrelationId,
delegateId?: TenantId
): Promise<Array<CreateEvent<AgreementEventV2>>> {
if (isFirstActivation) {
// Pending >>> Active
Expand Down Expand Up @@ -150,30 +154,41 @@ export async function createActivationEvent(
we also create the corresponding suspension/unsuspension by platform event.
*/

return match([authData.organizationId, updatedAgreement.state])
.with([updatedAgreement.producerId, agreementState.active], () => [
toCreateEventAgreementUnsuspendedByProducer(
updatedAgreement,
agreementEventStoreVersion,
correlationId
),
])
.with([updatedAgreement.producerId, agreementState.suspended], () => [
toCreateEventAgreementUnsuspendedByProducer(
{
...updatedAgreement,
suspendedByPlatform: originalSuspendedByPlatform,
},
agreementEventStoreVersion,
correlationId
),
...maybeCreateSuspensionByPlatformEvents(
updatedAgreement,
suspendedByPlatformChanged,
agreementEventStoreVersion + 1,
correlationId
),
])
return match<[TenantId | undefined, AgreementState]>([
authData.organizationId,
updatedAgreement.state,
])
.with(
[updatedAgreement.producerId, agreementState.active],
[delegateId, agreementState.active],
() => [
toCreateEventAgreementUnsuspendedByProducer(
updatedAgreement,
agreementEventStoreVersion,
correlationId
),
]
)
.with(
[updatedAgreement.producerId, agreementState.suspended],
[delegateId, agreementState.suspended],
() => [
toCreateEventAgreementUnsuspendedByProducer(
{
...updatedAgreement,
suspendedByPlatform: originalSuspendedByPlatform,
},
agreementEventStoreVersion,
correlationId
),
...maybeCreateSuspensionByPlatformEvents(
updatedAgreement,
suspendedByPlatformChanged,
agreementEventStoreVersion + 1,
correlationId
),
]
)
.with([updatedAgreement.consumerId, agreementState.active], () => [
toCreateEventAgreementUnsuspendedByConsumer(
updatedAgreement,
Expand Down
73 changes: 63 additions & 10 deletions packages/agreement-process/src/services/agreementService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
unsafeBrandId,
CompactTenant,
CorrelationId,
Delegation,
} from "pagopa-interop-models";
import {
declaredAttributesSatisfied,
Expand Down Expand Up @@ -87,9 +88,11 @@ import {
assertActivableState,
assertCanWorkOnConsumerDocuments,
assertExpectedState,
assertRequesterCanActivate,
assertRequesterCanSuspend,
assertRequesterIsConsumer,
assertRequesterIsConsumerOrProducer,
assertRequesterIsProducer,
assertRequesterIsConsumerOrProducerOrDelegate,
assertRequesterIsProducerOrDelegate,
assertSubmittableState,
failOnActivationFailure,
matchingCertifiedAttributes,
Expand Down Expand Up @@ -172,6 +175,18 @@ export const retrieveTenant = async (
return tenant;
};

export const retrieveDelegationByDelegateId = async (
delegateId: TenantId,
readModelService: ReadModelService
): Promise<WithMetadata<Delegation> | undefined> =>
await readModelService.getDelegationByDelegateId(delegateId);

export const retrieveActiveDelegationByEserviceId = async (
eserviceId: EServiceId,
readModelService: ReadModelService
): Promise<WithMetadata<Delegation> | undefined> =>
await readModelService.getActiveDelegationByEserviceId(eserviceId);

const retrieveDescriptor = (
descriptorId: DescriptorId,
eservice: EService
Expand Down Expand Up @@ -401,10 +416,17 @@ export function agreementServiceBuilder(
readModelService
);

const activeDelegation = await retrieveActiveDelegationByEserviceId(
agreement.data.eserviceId,
readModelService
);
const delegateId = activeDelegation?.data.delegateId;

const nextStateByAttributes = nextStateByAttributesFSM(
agreement.data,
descriptor,
consumer
consumer,
delegateId
);

const suspendedByPlatform = suspendedByPlatformFlag(
Expand Down Expand Up @@ -757,7 +779,12 @@ export function agreementServiceBuilder(
`Retrieving consumer document ${documentId} from agreement ${agreementId}`
);
const agreement = await retrieveAgreement(agreementId, readModelService);
assertRequesterIsConsumerOrProducer(agreement.data, authData);

await assertRequesterIsConsumerOrProducerOrDelegate(
agreement.data,
authData,
readModelService
);

return retrieveAgreementDocument(agreement.data, documentId);
},
Expand All @@ -768,8 +795,14 @@ export function agreementServiceBuilder(
logger.info(`Suspending agreement ${agreementId}`);

const agreement = await retrieveAgreement(agreementId, readModelService);
const activeDelegation = await retrieveActiveDelegationByEserviceId(
agreement.data.eserviceId,
readModelService
);

const delegateId = activeDelegation?.data.delegateId;

assertRequesterIsConsumerOrProducer(agreement.data, authData);
assertRequesterCanSuspend(agreement.data, delegateId, authData);

assertExpectedState(
agreementId,
Expand Down Expand Up @@ -797,14 +830,16 @@ export function agreementServiceBuilder(
authData,
descriptor,
consumer,
delegateId,
});

await repository.createEvent(
createAgreementSuspendedEvent(
authData.organizationId,
correlationId,
updatedAgreement,
agreement
agreement,
delegateId
)
);

Expand Down Expand Up @@ -873,8 +908,17 @@ export function agreementServiceBuilder(
agreementId,
readModelService
);
const activeDelegation = await retrieveActiveDelegationByEserviceId(
agreementToBeRejected.data.eserviceId,
readModelService
);
const delegateId = activeDelegation?.data.delegateId;

assertRequesterIsProducer(agreementToBeRejected.data, authData);
assertRequesterIsProducerOrDelegate(
agreementToBeRejected.data,
delegateId,
authData
);

assertExpectedState(
agreementId,
Expand Down Expand Up @@ -913,7 +957,7 @@ export function agreementServiceBuilder(
suspendedByPlatform: undefined,
stamps: {
...agreementToBeRejected.data.stamps,
rejection: createStamp(authData.userId),
rejection: createStamp(authData.userId, delegateId),
},
};

Expand Down Expand Up @@ -943,8 +987,15 @@ export function agreementServiceBuilder(
);

const agreement = await retrieveAgreement(agreementId, readModelService);
const activeDelegation = await retrieveActiveDelegationByEserviceId(
agreement.data.eserviceId,
readModelService
);

const delegateId = activeDelegation?.data.delegateId;

assertRequesterCanActivate(agreement.data, delegateId, authData);

assertRequesterIsConsumerOrProducer(agreement.data, authData);
verifyConsumerDoesNotActivatePending(agreement.data, authData);
assertActivableState(agreement.data);

Expand Down Expand Up @@ -1036,6 +1087,7 @@ export function agreementServiceBuilder(
suspendedByConsumer,
suspendedByProducer,
suspendedByPlatform,
delegateId,
});

const updatedAgreementWithoutContract: Agreement = {
Expand Down Expand Up @@ -1063,7 +1115,8 @@ export function agreementServiceBuilder(
suspendedByPlatformChanged,
agreement.metadata.version,
authData,
correlationId
correlationId,
delegateId
);

const archiveEvents = await archiveRelatedToAgreements(
Expand Down
Loading