diff --git a/src/app/core/services/asset-entry-builder.ts b/src/app/core/services/asset-request-builder.ts similarity index 98% rename from src/app/core/services/asset-entry-builder.ts rename to src/app/core/services/asset-request-builder.ts index 8fa491d37..993c8821f 100644 --- a/src/app/core/services/asset-entry-builder.ts +++ b/src/app/core/services/asset-request-builder.ts @@ -5,7 +5,7 @@ import {APP_CONFIG, AppConfig} from '../config/app-config'; import {DataAddressMapper} from './data-address-mapper'; @Injectable() -export class AssetEntryBuilder { +export class AssetRequestBuilder { constructor( @Inject(APP_CONFIG) private config: AppConfig, private dataAddressMapper: DataAddressMapper, diff --git a/src/app/core/services/data-address-properties.ts b/src/app/core/services/data-address-properties.ts new file mode 100644 index 000000000..f02cc36d7 --- /dev/null +++ b/src/app/core/services/data-address-properties.ts @@ -0,0 +1,19 @@ +const EDC = 'https://w3id.org/edc/v0.0.1/ns/'; + +export const DataAddressProperty = { + authCode: `${EDC}authCode`, + authKey: `${EDC}authKey`, + baseUrl: `${EDC}baseUrl`, + body: `${EDC}body`, + header: `${EDC}header`, + mediaType: `${EDC}mediaType`, + method: `${EDC}method`, + pathSegments: `${EDC}pathSegments`, + proxyBody: `${EDC}proxyBody`, + proxyMethod: `${EDC}proxyMethod`, + proxyPath: `${EDC}proxyPath`, + proxyQueryParams: `${EDC}proxyQueryParams`, + queryParams: `${EDC}queryParams`, + secretName: `${EDC}secretName`, + type: `${EDC}type`, +}; diff --git a/src/app/core/services/http-params-mapper.service.ts b/src/app/core/services/http-params-mapper.service.ts index 52a71b523..e3a0a1c9f 100644 --- a/src/app/core/services/http-params-mapper.service.ts +++ b/src/app/core/services/http-params-mapper.service.ts @@ -3,8 +3,9 @@ import {AssetDatasourceFormValue} from '../../routes/connector-ui/asset-page/ass import {HttpDatasourceHeaderFormValue} from '../../routes/connector-ui/asset-page/asset-create-dialog/model/http-datasource-header-form-model'; import {HttpDatasourceQueryParamFormValue} from '../../routes/connector-ui/asset-page/asset-create-dialog/model/http-datasource-query-param-form-model'; import {ContractAgreementTransferDialogFormValue} from '../../routes/connector-ui/contract-agreement-page/contract-agreement-transfer-dialog/contract-agreement-transfer-dialog-form-model'; -import {removeNullValues} from '../utils/record-utils'; +import {mapKeys, removeNullValues} from '../utils/record-utils'; import {everythingAfter, everythingBefore} from '../utils/string-utils'; +import {DataAddressProperty} from './data-address-properties'; import {Asset} from './models/asset'; import {HttpRequestParams} from './models/http-request-params'; @@ -46,33 +47,36 @@ export class HttpRequestParamsMapper { asset.httpDatasourceHintsProxyBody; return removeNullValues({ - method: proxyMethod ? method : null, - pathSegments: proxyPath ? pathSegments : null, - queryParams: proxyQueryParams ? queryParams : null, - body: proxyBody ? body : null, - mediaType: proxyBody ? contentType : null, + [DataAddressProperty.method]: proxyMethod ? method : null, + [DataAddressProperty.pathSegments]: proxyPath ? pathSegments : null, + [DataAddressProperty.queryParams]: proxyQueryParams ? queryParams : null, + [DataAddressProperty.body]: proxyBody ? body : null, + [DataAddressProperty.mediaType]: proxyBody ? contentType : null, }); } encodeHttpRequestParams( httpRequestParams: HttpRequestParams, ): Record { + const bool = (b?: boolean | null) => (b ? 'true' : null); + const props: Record = { - type: 'HttpData', - baseUrl: httpRequestParams.baseUrl, - method: httpRequestParams.method, - authKey: httpRequestParams.authHeaderName, - authCode: httpRequestParams.authHeaderValue, - secretName: httpRequestParams.authHeaderSecretName, - proxyMethod: httpRequestParams.proxyMethod ? 'true' : null, - proxyPath: httpRequestParams.proxyPath ? 'true' : null, - proxyQueryParams: httpRequestParams.proxyQueryParams ? 'true' : null, - proxyBody: httpRequestParams.proxyBody ? 'true' : null, - queryParams: httpRequestParams.queryParams, - ...Object.fromEntries( - Object.entries(httpRequestParams.headers).map( - ([headerName, headerValue]) => [`header:${headerName}`, headerValue], - ), + [DataAddressProperty.type]: 'HttpData', + [DataAddressProperty.baseUrl]: httpRequestParams.baseUrl, + [DataAddressProperty.method]: httpRequestParams.method, + [DataAddressProperty.authKey]: httpRequestParams.authHeaderName, + [DataAddressProperty.authCode]: httpRequestParams.authHeaderValue, + [DataAddressProperty.secretName]: httpRequestParams.authHeaderSecretName, + [DataAddressProperty.proxyMethod]: bool(httpRequestParams.proxyMethod), + [DataAddressProperty.proxyPath]: bool(httpRequestParams.proxyPath), + [DataAddressProperty.proxyQueryParams]: bool( + httpRequestParams.proxyQueryParams, + ), + [DataAddressProperty.proxyBody]: bool(httpRequestParams.proxyBody), + [DataAddressProperty.queryParams]: httpRequestParams.queryParams, + ...mapKeys( + httpRequestParams.headers, + (k) => `${DataAddressProperty.header}:${k}`, ), }; return removeNullValues(props); diff --git a/src/app/core/utils/record-utils.ts b/src/app/core/utils/record-utils.ts index ecdac1d45..3854067b3 100644 --- a/src/app/core/utils/record-utils.ts +++ b/src/app/core/utils/record-utils.ts @@ -9,3 +9,19 @@ export function removeNullValues( Object.entries(obj).filter(([_, v]) => v != null) as [string, string][], ); } + +/** + * Maps keys of a given object + * @param obj object + * @param mapFn key mapper + * @return new object with keys mapped + */ +export function mapKeys< + K extends string | number | symbol, + L extends string | number | symbol, + V, +>(obj: Record, mapFn: (key: K) => L): Record { + return Object.fromEntries( + Object.entries(obj).map(([k, v]) => [mapFn(k as K), v]), + ) as Record; +} diff --git a/src/app/core/validators/no-whitespace-validator.ts b/src/app/core/validators/no-whitespaces-or-colons-validator.ts similarity index 59% rename from src/app/core/validators/no-whitespace-validator.ts rename to src/app/core/validators/no-whitespaces-or-colons-validator.ts index 07c164f9f..24e814dfb 100644 --- a/src/app/core/validators/no-whitespace-validator.ts +++ b/src/app/core/validators/no-whitespaces-or-colons-validator.ts @@ -4,4 +4,5 @@ import {ValidatorFn, Validators} from '@angular/forms'; * Validates whether value contains whitespaces * @param control control */ -export const noWhitespaceValidator: ValidatorFn = Validators.pattern(/^\S*$/); +export const noWhitespacesOrColonsValidator: ValidatorFn = + Validators.pattern(/^[^\s:]*$/); diff --git a/src/app/core/validators/requires-prefix-validator.ts b/src/app/core/validators/requires-prefix-validator.ts deleted file mode 100644 index 34b2b0c74..000000000 --- a/src/app/core/validators/requires-prefix-validator.ts +++ /dev/null @@ -1,14 +0,0 @@ -import {AbstractControl, ValidationErrors, ValidatorFn} from '@angular/forms'; - -/** - * Validates whether control's value starts with given prefix. - */ -export function requiresPrefixValidator(prefix: string): ValidatorFn { - return (control: AbstractControl): ValidationErrors | null => { - const value = control.value; - if (value && !value.startsWith(prefix)) { - return {requiresPrefix: true}; - } - return null; - }; -} diff --git a/src/app/core/validators/validation-messages.ts b/src/app/core/validators/validation-messages.ts index 21c071000..6402d1930 100644 --- a/src/app/core/validators/validation-messages.ts +++ b/src/app/core/validators/validation-messages.ts @@ -4,10 +4,9 @@ import {Injectable} from '@angular/core'; export class ValidationMessages { invalidUrlMessage = 'Must be valid URL, e.g. https://example.com'; invalidJsonMessage = 'Must be valid JSON'; - invalidWhitespacesMessage = 'Must not contain whitespaces.'; + invalidWhitespacesOrColonsMessage = 'Must not contain whitespaces or colons.'; invalidPrefix = (field: string, prefix: string): string => `${field} must start with "${prefix}".`; invalidDateRangeMessage = 'Need valid date range.'; - invalidDateMessage = 'Must be valid date.'; idExistsErrorMessage = 'ID already exists.'; } diff --git a/src/app/routes/connector-ui/asset-page/asset-create-dialog/asset-create-dialog.component.html b/src/app/routes/connector-ui/asset-page/asset-create-dialog/asset-create-dialog.component.html index 3d25beb08..037d0baee 100644 --- a/src/app/routes/connector-ui/asset-page/asset-create-dialog/asset-create-dialog.component.html +++ b/src/app/routes/connector-ui/asset-page/asset-create-dialog/asset-create-dialog.component.html @@ -31,14 +31,14 @@

Create New Asset

- Id + Asset ID - {{ validationMessages.invalidWhitespacesMessage }} + {{ validationMessages.invalidWhitespacesOrColonsMessage }} {{ validationMessages.invalidPrefix('ID', 'urn:artifact') }} diff --git a/src/app/routes/connector-ui/asset-page/asset-create-dialog/asset-create-dialog.component.ts b/src/app/routes/connector-ui/asset-page/asset-create-dialog/asset-create-dialog.component.ts index b3542a0fa..fc9b1ab6a 100644 --- a/src/app/routes/connector-ui/asset-page/asset-create-dialog/asset-create-dialog.component.ts +++ b/src/app/routes/connector-ui/asset-page/asset-create-dialog/asset-create-dialog.component.ts @@ -3,7 +3,7 @@ import {MatDialogRef} from '@angular/material/dialog'; import {Subject} from 'rxjs'; import {finalize, takeUntil} from 'rxjs/operators'; import {EdcApiService} from '../../../../core/services/api/edc-api.service'; -import {AssetEntryBuilder} from '../../../../core/services/asset-entry-builder'; +import {AssetRequestBuilder} from '../../../../core/services/asset-request-builder'; import {NotificationService} from '../../../../core/services/notification.service'; import {ValidationMessages} from '../../../../core/validators/validation-messages'; import {AssetCreateDialogForm} from './asset-create-dialog-form'; @@ -19,7 +19,7 @@ import {AssetMetadataFormBuilder} from './model/asset-metadata-form-builder'; AssetAdvancedFormBuilder, AssetDatasourceFormBuilder, AssetCreateDialogForm, - AssetEntryBuilder, + AssetRequestBuilder, AssetMetadataFormBuilder, ], }) @@ -32,7 +32,7 @@ export class AssetCreateDialogComponent implements OnDestroy { private edcApiService: EdcApiService, public form: AssetCreateDialogForm, public validationMessages: ValidationMessages, - private assetEntryBuilder: AssetEntryBuilder, + private assetEntryBuilder: AssetRequestBuilder, private notificationService: NotificationService, private dialogRef: MatDialogRef, ) {} diff --git a/src/app/routes/connector-ui/asset-page/asset-create-dialog/model/asset-metadata-form-builder.ts b/src/app/routes/connector-ui/asset-page/asset-create-dialog/model/asset-metadata-form-builder.ts index 011414fad..e89d5ff6b 100644 --- a/src/app/routes/connector-ui/asset-page/asset-create-dialog/model/asset-metadata-form-builder.ts +++ b/src/app/routes/connector-ui/asset-page/asset-create-dialog/model/asset-metadata-form-builder.ts @@ -3,8 +3,7 @@ import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms'; import {combineLatest, distinctUntilChanged, pairwise} from 'rxjs'; import {map} from 'rxjs/operators'; import {value$} from '../../../../../core/utils/form-group-utils'; -import {noWhitespaceValidator} from '../../../../../core/validators/no-whitespace-validator'; -import {requiresPrefixValidator} from '../../../../../core/validators/requires-prefix-validator'; +import {noWhitespacesOrColonsValidator} from '../../../../../core/validators/no-whitespaces-or-colons-validator'; import {urlValidator} from '../../../../../core/validators/url-validator'; import {LanguageSelectItem} from '../../language-select/language-select-item'; import {LanguageSelectItemService} from '../../language-select/language-select-item.service'; @@ -24,11 +23,7 @@ export class AssetMetadataFormBuilder { this.formBuilder.nonNullable.group({ id: [ '', - [ - Validators.required, - noWhitespaceValidator, - requiresPrefixValidator('urn:artifact:'), - ], + [Validators.required, noWhitespacesOrColonsValidator], [this.assetsIdValidatorBuilder.assetIdDoesNotExistsValidator()], ], name: ['', Validators.required], @@ -74,12 +69,12 @@ export class AssetMetadataFormBuilder { } private generateId(name: string | null, version: string | null) { - if (!name) return 'urn:artifact:'; + if (!name) return ''; const normalizedName = name .replace(':', '') .replaceAll(' ', '-') .toLowerCase(); - if (version) return `urn:artifact:${normalizedName}:${version}`; - return `urn:artifact:${normalizedName}`; + if (version) return `${normalizedName}-${version}`; + return normalizedName; } } diff --git a/src/app/routes/connector-ui/contract-agreement-page/contract-agreement-transfer-dialog/contract-agreement-transfer-dialog.component.ts b/src/app/routes/connector-ui/contract-agreement-page/contract-agreement-transfer-dialog/contract-agreement-transfer-dialog.component.ts index f1f533580..5f5e0a530 100644 --- a/src/app/routes/connector-ui/contract-agreement-page/contract-agreement-transfer-dialog/contract-agreement-transfer-dialog.component.ts +++ b/src/app/routes/connector-ui/contract-agreement-page/contract-agreement-transfer-dialog/contract-agreement-transfer-dialog.component.ts @@ -4,7 +4,6 @@ import {Subject} from 'rxjs'; import {finalize} from 'rxjs/operators'; import {ContractAgreementTransferRequest} from '@sovity.de/edc-client'; import {EdcApiService} from '../../../../core/services/api/edc-api.service'; -import {AssetEntryBuilder} from '../../../../core/services/asset-entry-builder'; import {DataAddressMapper} from '../../../../core/services/data-address-mapper'; import {HttpRequestParamsMapper} from '../../../../core/services/http-params-mapper.service'; import {NotificationService} from '../../../../core/services/notification.service'; @@ -17,7 +16,7 @@ import {ContractAgreementTransferDialogResult} from './contract-agreement-transf @Component({ selector: 'contract-agreement-transfer-dialog', templateUrl: './contract-agreement-transfer-dialog.component.html', - providers: [ContractAgreementTransferDialogForm, AssetEntryBuilder], + providers: [ContractAgreementTransferDialogForm], }) export class ContractAgreementTransferDialogComponent implements OnDestroy { loading = false; diff --git a/src/app/routes/connector-ui/contract-definition-page/contract-definition-editor-dialog/contract-definition-editor-dialog-form.ts b/src/app/routes/connector-ui/contract-definition-page/contract-definition-editor-dialog/contract-definition-editor-dialog-form.ts index 76443812c..5ef41c2df 100644 --- a/src/app/routes/connector-ui/contract-definition-page/contract-definition-editor-dialog/contract-definition-editor-dialog-form.ts +++ b/src/app/routes/connector-ui/contract-definition-page/contract-definition-editor-dialog/contract-definition-editor-dialog-form.ts @@ -2,7 +2,7 @@ import {Injectable} from '@angular/core'; import {FormBuilder, FormGroup, Validators} from '@angular/forms'; import {PolicyDefinitionDto} from '@sovity.de/edc-client'; import {Asset} from '../../../../core/services/models/asset'; -import {noWhitespaceValidator} from '../../../../core/validators/no-whitespace-validator'; +import {noWhitespacesOrColonsValidator} from '../../../../core/validators/no-whitespaces-or-colons-validator'; import { ContractDefinitionEditorDialogFormModel, ContractDefinitionEditorDialogFormValue, @@ -26,7 +26,7 @@ export class ContractDefinitionEditorDialogForm { buildFormGroup(): FormGroup { return this.formBuilder.nonNullable.group({ - id: ['', [Validators.required, noWhitespaceValidator]], + id: ['', [Validators.required, noWhitespacesOrColonsValidator]], accessPolicy: [null as PolicyDefinitionDto | null, Validators.required], contractPolicy: [null as PolicyDefinitionDto | null, Validators.required], assets: [[] as Asset[], Validators.required], diff --git a/src/app/routes/connector-ui/contract-definition-page/contract-definition-editor-dialog/contract-definition-editor-dialog.component.html b/src/app/routes/connector-ui/contract-definition-page/contract-definition-editor-dialog/contract-definition-editor-dialog.component.html index a8126c327..cb82a2378 100644 --- a/src/app/routes/connector-ui/contract-definition-page/contract-definition-editor-dialog/contract-definition-editor-dialog.component.html +++ b/src/app/routes/connector-ui/contract-definition-page/contract-definition-editor-dialog/contract-definition-editor-dialog.component.html @@ -10,7 +10,7 @@

Create New Contract Definition

ID {{ - validationMessages.invalidWhitespacesMessage + validationMessages.invalidWhitespacesOrColonsMessage }}
diff --git a/src/app/routes/connector-ui/contract-definition-page/contract-definition-editor-dialog/contract-definition-editor-dialog.component.ts b/src/app/routes/connector-ui/contract-definition-page/contract-definition-editor-dialog/contract-definition-editor-dialog.component.ts index 847984ac8..a77938604 100644 --- a/src/app/routes/connector-ui/contract-definition-page/contract-definition-editor-dialog/contract-definition-editor-dialog.component.ts +++ b/src/app/routes/connector-ui/contract-definition-page/contract-definition-editor-dialog/contract-definition-editor-dialog.component.ts @@ -4,7 +4,6 @@ import {Subject} from 'rxjs'; import {finalize, takeUntil} from 'rxjs/operators'; import {PolicyDefinitionDto} from '@sovity.de/edc-client'; import {EdcApiService} from '../../../../core/services/api/edc-api.service'; -import {AssetEntryBuilder} from '../../../../core/services/asset-entry-builder'; import {AssetServiceMapped} from '../../../../core/services/asset-service-mapped'; import {ContractDefinitionBuilder} from '../../../../core/services/contract-definition-builder'; import {Asset} from '../../../../core/services/models/asset'; @@ -16,7 +15,7 @@ import {ContractDefinitionEditorDialogResult} from './contract-definition-editor @Component({ selector: 'contract-definition-editor-dialog', templateUrl: './contract-definition-editor-dialog.component.html', - providers: [ContractDefinitionEditorDialogForm, AssetEntryBuilder], + providers: [ContractDefinitionEditorDialogForm], }) export class ContractDefinitionEditorDialog implements OnInit, OnDestroy { policies: PolicyDefinitionDto[] = []; diff --git a/src/app/routes/connector-ui/policy-definition-page/new-policy-dialog/new-policy-dialog-form.ts b/src/app/routes/connector-ui/policy-definition-page/new-policy-dialog/new-policy-dialog-form.ts index ce6f76442..fa72d0434 100644 --- a/src/app/routes/connector-ui/policy-definition-page/new-policy-dialog/new-policy-dialog-form.ts +++ b/src/app/routes/connector-ui/policy-definition-page/new-policy-dialog/new-policy-dialog-form.ts @@ -2,7 +2,7 @@ import {Injectable} from '@angular/core'; import {FormBuilder, FormGroup, Validators} from '@angular/forms'; import {switchDisabledControls} from '../../../../core/utils/form-group-utils'; import {dateRangeRequired} from '../../../../core/validators/date-range-required'; -import {noWhitespaceValidator} from '../../../../core/validators/no-whitespace-validator'; +import {noWhitespacesOrColonsValidator} from '../../../../core/validators/no-whitespaces-or-colons-validator'; import { NewPolicyDialogFormModel, NewPolicyDialogFormValue, @@ -32,7 +32,7 @@ export class NewPolicyDialogForm { buildFormGroup(): FormGroup { const newPolicyFormGroup: FormGroup = this.formBuilder.nonNullable.group({ - id: ['', [Validators.required, noWhitespaceValidator]], + id: ['', [Validators.required, noWhitespacesOrColonsValidator]], policyType: [ 'Connector-Restricted-Usage' as PolicyType, Validators.required, diff --git a/src/app/routes/connector-ui/policy-definition-page/new-policy-dialog/new-policy-dialog.component.html b/src/app/routes/connector-ui/policy-definition-page/new-policy-dialog/new-policy-dialog.component.html index f2f6867a0..c128137f3 100644 --- a/src/app/routes/connector-ui/policy-definition-page/new-policy-dialog/new-policy-dialog.component.html +++ b/src/app/routes/connector-ui/policy-definition-page/new-policy-dialog/new-policy-dialog.component.html @@ -9,7 +9,7 @@

Create New Policy

ID {{ - validationMessages.invalidWhitespacesMessage + validationMessages.invalidWhitespacesOrColonsMessage }} diff --git a/src/app/routes/connector-ui/policy-definition-page/new-policy-dialog/new-policy-dialog.component.ts b/src/app/routes/connector-ui/policy-definition-page/new-policy-dialog/new-policy-dialog.component.ts index 147903389..9d3bc94a2 100644 --- a/src/app/routes/connector-ui/policy-definition-page/new-policy-dialog/new-policy-dialog.component.ts +++ b/src/app/routes/connector-ui/policy-definition-page/new-policy-dialog/new-policy-dialog.component.ts @@ -3,7 +3,6 @@ import {MatDialogRef} from '@angular/material/dialog'; import {Subject} from 'rxjs'; import {finalize, takeUntil} from 'rxjs/operators'; import {EdcApiService} from '../../../../core/services/api/edc-api.service'; -import {AssetEntryBuilder} from '../../../../core/services/asset-entry-builder'; import {NotificationService} from '../../../../core/services/notification.service'; import {PolicyDefinitionBuilder} from '../../../../core/services/policy-definition-builder'; import {ValidationMessages} from '../../../../core/validators/validation-messages'; @@ -13,7 +12,7 @@ import {NewPolicyDialogResult} from './new-policy-dialog-result'; @Component({ selector: 'new-policy-dialog', templateUrl: './new-policy-dialog.component.html', - providers: [NewPolicyDialogForm, AssetEntryBuilder], + providers: [NewPolicyDialogForm], }) export class NewPolicyDialogComponent implements OnDestroy { loading = false;