diff --git a/CHANGELOG.md b/CHANGELOG.md index 83e82f0fe..ea2dfe10f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,10 @@ the detailed section referring to by linking pull requests or issues. #### Patch +- Used createDataOffer endpoint to create an asset, policies and a contract + definition in a single call + ([#841](https://github.com/sovity/edc-ui/issues/841)) + ### Deployment Migration Notes _No special deployment migration steps required_ @@ -36,10 +40,14 @@ Various bugfixes. #### Patch -- Changed wording on the data offer creation page ([#817](https://github.com/sovity/edc-ui/issues/795)) -- Data Offer details now display the contract ID for each contract offer ([#795](https://github.com/sovity/edc-ui/issues/795)) -- Warn the user when using an invalid Policy Id ([#746](https://github.com/sovity/edc-ui/issues/746)) -- Warn the user when using an invalid Data Offer Id ([#745](https://github.com/sovity/edc-ui/issues/745)) +- Changed wording on the data offer creation page + ([#817](https://github.com/sovity/edc-ui/issues/795)) +- Data Offer details now display the contract ID for each contract offer + ([#795](https://github.com/sovity/edc-ui/issues/795)) +- Warn the user when using an invalid Policy Id + ([#746](https://github.com/sovity/edc-ui/issues/746)) +- Warn the user when using an invalid Data Offer Id + ([#745](https://github.com/sovity/edc-ui/issues/745)) - Fixed time restriction upper bound "local day to datetime" conversion issues ([#815](https://github.com/sovity/edc-ui/issues/815)) diff --git a/package-lock.json b/package-lock.json index 055d5becb..7536bfc4f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "@angular/router": "^14.3.0", "@ng-apimock/core": "^3.11.0", "@ngxs/store": "^3.8.1", - "@sovity.de/edc-client": "0.20240805.72446-main-4f0ae71b", + "@sovity.de/edc-client": "10.4.0", "clean-deep": "^3.4.0", "date-fns": "^2.30.0", "date-fns-tz": "^2.0.1", @@ -3574,9 +3574,9 @@ "dev": true }, "node_modules/@sovity.de/edc-client": { - "version": "0.20240805.72446-main-4f0ae71b", - "resolved": "https://registry.npmjs.org/@sovity.de/edc-client/-/edc-client-0.20240805.72446-main-4f0ae71b.tgz", - "integrity": "sha512-TLwikNivrsUmiVNFDqHvjVsojuNXVWxMogtFfaujLURflAL9+s/XGJ1eBZPaAMhmeRFfeqEGhrtI8RD4xtc1jg==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@sovity.de/edc-client/-/edc-client-10.4.0.tgz", + "integrity": "sha512-CBC7bHdIWD1K5plc+tgdJOb5YT82YyyaZ1xMKCy5Ox77KgQEOKG5W/95VzzZkap91xV5zNO5j7I5KJXj18jz8g==", "dependencies": { "zod": "^3.22.4" } @@ -16640,9 +16640,9 @@ "dev": true }, "@sovity.de/edc-client": { - "version": "0.20240805.72446-main-4f0ae71b", - "resolved": "https://registry.npmjs.org/@sovity.de/edc-client/-/edc-client-0.20240805.72446-main-4f0ae71b.tgz", - "integrity": "sha512-TLwikNivrsUmiVNFDqHvjVsojuNXVWxMogtFfaujLURflAL9+s/XGJ1eBZPaAMhmeRFfeqEGhrtI8RD4xtc1jg==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@sovity.de/edc-client/-/edc-client-10.4.0.tgz", + "integrity": "sha512-CBC7bHdIWD1K5plc+tgdJOb5YT82YyyaZ1xMKCy5Ox77KgQEOKG5W/95VzzZkap91xV5zNO5j7I5KJXj18jz8g==", "requires": { "zod": "^3.22.4" } diff --git a/package.json b/package.json index bd158ae1e..d89783691 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "@angular/router": "^14.3.0", "@ng-apimock/core": "^3.11.0", "@ngxs/store": "^3.8.1", - "@sovity.de/edc-client": "0.20240805.72446-main-4f0ae71b", + "@sovity.de/edc-client": "10.4.0", "clean-deep": "^3.4.0", "date-fns": "^2.30.0", "date-fns-tz": "^2.0.1", diff --git a/src/app/core/services/api/edc-api.service.ts b/src/app/core/services/api/edc-api.service.ts index 122f9ff88..2575fb157 100644 --- a/src/app/core/services/api/edc-api.service.ts +++ b/src/app/core/services/api/edc-api.service.ts @@ -8,6 +8,7 @@ import { ContractDefinitionPage, ContractDefinitionRequest, ContractNegotiationRequest, + CreateDataOfferRequest, DashboardPage, EdcClient, GetContractAgreementPageRequest, @@ -129,6 +130,14 @@ export class EdcApiService { ); } + createDataOffer( + dataOfferCreationRequest: CreateDataOfferRequest, + ): Observable { + return toObservable(() => + this.edcClient.uiApi.createDataOffer(dataOfferCreationRequest), + ); + } + getCatalogPageDataOffers( connectorEndpoint: string, ): Observable { diff --git a/src/app/core/services/api/fake-backend/connector-fake-impl/data-offer-fake-service.ts b/src/app/core/services/api/fake-backend/connector-fake-impl/data-offer-fake-service.ts new file mode 100644 index 000000000..471a2a2cf --- /dev/null +++ b/src/app/core/services/api/fake-backend/connector-fake-impl/data-offer-fake-service.ts @@ -0,0 +1,72 @@ +import { + DataOfferCreationRequest, + DataOfferCreationRequestPolicyEnum, + IdResponseDto, + UiCriterionLiteralType, +} from '@sovity.de/edc-client'; +import {ALWAYS_TRUE_POLICY_ID} from 'src/app/component-library/edit-asset-form/edit-asset-form/form/model/always-true-policy-id'; +import {assetIdAvailable, createAsset} from './asset-fake-service'; +import { + contractDefinitionIdAvailable, + createContractDefinition, +} from './contract-definition-fake-service'; +import { + createPolicyDefinitionV2, + policyDefinitionIdAvailable, +} from './policy-definition-fake-service'; + +const checkIdAvailability = (id: string): void => { + if ( + !policyDefinitionIdAvailable(id).available || + !assetIdAvailable(id).available || + !contractDefinitionIdAvailable(id).available + ) { + throw new Error('Id already exists'); + } +}; + +export const createDataOffer = ( + request: DataOfferCreationRequest, +): IdResponseDto => { + const commonId = request.uiAssetCreateRequest.id; + let accessPolicyId = null; + let contractPolicyId = null; + + checkIdAvailability(commonId); + createAsset(request.uiAssetCreateRequest); + + switch (request.policy) { + case DataOfferCreationRequestPolicyEnum.DontPublish: + return {id: commonId, lastUpdatedDate: new Date()}; + case DataOfferCreationRequestPolicyEnum.PublishRestricted: + createPolicyDefinitionV2({ + policyDefinitionId: commonId, + expression: request.uiPolicyExpression!, + }); + accessPolicyId = commonId; + contractPolicyId = commonId; + break; + case DataOfferCreationRequestPolicyEnum.PublishUnrestricted: + accessPolicyId = ALWAYS_TRUE_POLICY_ID; + contractPolicyId = ALWAYS_TRUE_POLICY_ID; + break; + } + + createContractDefinition({ + contractDefinitionId: commonId, + accessPolicyId, + contractPolicyId, + assetSelector: [ + { + operandLeft: commonId, + operator: 'EQ', + operandRight: { + type: UiCriterionLiteralType.Value, + value: commonId, + }, + }, + ], + }); + + return {id: commonId, lastUpdatedDate: new Date()}; +}; diff --git a/src/app/core/services/api/fake-backend/edc-fake-backend.ts b/src/app/core/services/api/fake-backend/edc-fake-backend.ts index 305ab99fe..57a129c7c 100644 --- a/src/app/core/services/api/fake-backend/edc-fake-backend.ts +++ b/src/app/core/services/api/fake-backend/edc-fake-backend.ts @@ -8,6 +8,7 @@ import { ContractNegotiationRequestFromJSON, ContractTerminationRequestFromJSON, DashboardPageToJSON, + DataOfferCreationRequestFromJSON, FetchAPI, IdAvailabilityResponseToJSON, IdResponseDtoToJSON, @@ -46,6 +47,7 @@ import { } from './connector-fake-impl/contract-negotiation-fake-service'; import {initiateContractTermination} from './connector-fake-impl/contract-termination-fake-service'; import {dashboardPage} from './connector-fake-impl/dashboard-fake-service'; +import {createDataOffer} from './connector-fake-impl/data-offer-fake-service'; import {connectorLimits} from './connector-fake-impl/ee-fake-service'; import { createPolicyDefinition, @@ -194,8 +196,10 @@ export const EDC_FAKE_BACKEND: FetchAPI = async ( .url('ui/pages/contract-agreement-page/*') .on('GET', (contractAgreementId: String) => { return ok( - contractAgreementPage().contractAgreements - .find( (contractAgreement) => contractAgreement.contractAgreementId === contractAgreementId) + contractAgreementPage().contractAgreements.find( + (contractAgreement) => + contractAgreement.contractAgreementId === contractAgreementId, + ), ); }) @@ -234,6 +238,12 @@ export const EDC_FAKE_BACKEND: FetchAPI = async ( return ok(ConnectorLimitsToJSON(limits)); }) + .url('ui/pages/create-data-offer') + .on('POST', () => { + const response = createDataOffer(DataOfferCreationRequestFromJSON(body)); + return ok(IdResponseDtoToJSON(response)); + }) + .url('ui/pages/data-offer-page/validate-asset-id/*') .on('GET', (assetId) => { const response = assetIdAvailable(assetId); diff --git a/src/app/routes/connector-ui/asset-edit-page/asset-edit-page/asset-edit-page.component.ts b/src/app/routes/connector-ui/asset-edit-page/asset-edit-page/asset-edit-page.component.ts index f5896dff2..bd4b5c2a0 100644 --- a/src/app/routes/connector-ui/asset-edit-page/asset-edit-page/asset-edit-page.component.ts +++ b/src/app/routes/connector-ui/asset-edit-page/asset-edit-page/asset-edit-page.component.ts @@ -1,24 +1,22 @@ import {Component, OnInit} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; -import {EMPTY, Observable, catchError, concat, finalize, tap} from 'rxjs'; +import {EMPTY, Observable, catchError, finalize, tap} from 'rxjs'; import { + DataOfferCreationRequestPolicyEnum, IdResponseDto, UiAssetEditRequest, - UiCriterionLiteralType, } from '@sovity.de/edc-client'; import {AssetAdvancedFormBuilder} from 'src/app/component-library/edit-asset-form/edit-asset-form/form/asset-advanced-form-builder'; import {AssetDatasourceFormBuilder} from 'src/app/component-library/edit-asset-form/edit-asset-form/form/asset-datasource-form-builder'; import {AssetGeneralFormBuilder} from 'src/app/component-library/edit-asset-form/edit-asset-form/form/asset-general-form-builder'; import {EditAssetForm} from 'src/app/component-library/edit-asset-form/edit-asset-form/form/edit-asset-form'; import {EditAssetFormInitializer} from 'src/app/component-library/edit-asset-form/edit-asset-form/form/edit-asset-form-initializer'; -import {ALWAYS_TRUE_POLICY_ID} from 'src/app/component-library/edit-asset-form/edit-asset-form/form/model/always-true-policy-id'; import {EditAssetFormValue} from 'src/app/component-library/edit-asset-form/edit-asset-form/form/model/edit-asset-form-model'; import {ExpressionFormControls} from 'src/app/component-library/policy-editor/editor/expression-form-controls'; import {ExpressionFormHandler} from 'src/app/component-library/policy-editor/editor/expression-form-handler'; import {EdcApiService} from 'src/app/core/services/api/edc-api.service'; import {AssetRequestBuilder} from 'src/app/core/services/asset-request-builder'; import {AssetService} from 'src/app/core/services/asset.service'; -import {AssetProperty} from 'src/app/core/services/models/asset-properties'; import {Fetched} from 'src/app/core/services/models/fetched'; import {UiAssetMapped} from 'src/app/core/services/models/ui-asset-mapped'; import {NotificationService} from 'src/app/core/services/notification.service'; @@ -130,21 +128,30 @@ export class AssetEditPageComponent implements OnInit { this.assetRequestBuilder.buildAssetCreateRequest(formValue); if (publishMode === 'PUBLISH_UNRESTRICTED') { - return concat( - this.edcApiService.createAsset(assetCreateRequest), - this.createContractDefinition(assetId, ALWAYS_TRUE_POLICY_ID), - ); + return this.edcApiService.createDataOffer({ + dataOfferCreationRequest: { + uiAssetCreateRequest: assetCreateRequest, + policy: DataOfferCreationRequestPolicyEnum.PublishUnrestricted, + uiPolicyExpression: + this.expressionFormHandler.toUiPolicyExpression(), + }, + }); } else if (publishMode === 'PUBLISH_RESTRICTED') { - return concat( - this.edcApiService.createAsset(assetCreateRequest), - this.edcApiService.createPolicyDefinitionV2({ - policyDefinitionId: assetId, - expression: this.expressionFormHandler.toUiPolicyExpression(), - }), - this.createContractDefinition(assetId, assetId), - ); + return this.edcApiService.createDataOffer({ + dataOfferCreationRequest: { + uiAssetCreateRequest: assetCreateRequest, + policy: DataOfferCreationRequestPolicyEnum.PublishRestricted, + uiPolicyExpression: + this.expressionFormHandler.toUiPolicyExpression(), + }, + }); } else { - return this.edcApiService.createAsset(assetCreateRequest); + return this.edcApiService.createDataOffer({ + dataOfferCreationRequest: { + uiAssetCreateRequest: assetCreateRequest, + policy: DataOfferCreationRequestPolicyEnum.DontPublish, + }, + }); } } @@ -164,25 +171,4 @@ export class AssetEditPageComponent implements OnInit { throw new Error(`Unsupported mode: ${mode}`); } - - private createContractDefinition( - assetId: string, - policyId: string, - ): Observable { - return this.edcApiService.createContractDefinition({ - accessPolicyId: policyId, - contractPolicyId: policyId, - contractDefinitionId: assetId, - assetSelector: [ - { - operandLeft: AssetProperty.id, - operator: 'IN', - operandRight: { - type: UiCriterionLiteralType.ValueList, - valueList: [assetId], - }, - }, - ], - }); - } }