From 7df7a482c61f44de8bc1b3fefe32a4951db8686a Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Wed, 6 Oct 2021 10:11:35 +0200
Subject: [PATCH 01/19] add json to describe distribution properties

---
 src/app/mapping/class/dataset.ts     |   9 ++
 src/app/mapping/mapping.component.ts |   4 +-
 src/assets/distribution.json         | 229 +++++++++++++++++++++++++++
 3 files changed, 240 insertions(+), 2 deletions(-)
 create mode 100644 src/assets/distribution.json

diff --git a/src/app/mapping/class/dataset.ts b/src/app/mapping/class/dataset.ts
index 080bc153a..3040e15c8 100644
--- a/src/app/mapping/class/dataset.ts
+++ b/src/app/mapping/class/dataset.ts
@@ -20,4 +20,13 @@ export class DatasetPath {
     }
 }
 
+export class Distribution {
+    public property: string;
+    public uri: string;
+    public range: string;
+    public usageNote: string;
+    public card: string;
+    public geodcat: boolean;
+}
+
 
diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts
index a54053c5e..35928d4ba 100644
--- a/src/app/mapping/mapping.component.ts
+++ b/src/app/mapping/mapping.component.ts
@@ -4,7 +4,6 @@ import { HttpResponse } from '@angular/common/http';
 import { Component, Input, OnInit, ViewChild } from '@angular/core';
 import { MatDialog } from '@angular/material/dialog';
 import { Router } from '@angular/router';
-import { escapeRegExp } from 'lodash';
 import { FileSaverService } from 'ngx-filesaver';
 
 import { Observable, of, Subscription } from 'rxjs';
@@ -12,7 +11,7 @@ import { map } from 'rxjs/operators';
 import { environment } from 'src/environments/environment.prod';
 import { DatasetCrudService } from '../datasets/services/dataset-crud.service';
 
-import { Dataset, DatasetPath } from './class/dataset';
+import { Dataset, DatasetPath, Distribution } from './class/dataset';
 import { FeedbackDialogComponent } from './dialog/feedback-dialog/feedback-dialog.component';
 
 
@@ -23,6 +22,7 @@ import { FeedbackDialogComponent } from './dialog/feedback-dialog/feedback-dialo
 })
 export class MappingComponent implements OnInit {
 
+  distributions: Distribution[] = [];
   itemsdataset: Object[] = []
   dcatVocabulary: Dataset[];
   vocabularies: Dataset[];
diff --git a/src/assets/distribution.json b/src/assets/distribution.json
new file mode 100644
index 000000000..ca967ba89
--- /dev/null
+++ b/src/assets/distribution.json
@@ -0,0 +1,229 @@
+[
+    {
+        "property": "access URL",
+        "uri": "dcat:accessURL",
+        "range": "rdfs:Resource",
+        "usageNote": "This property contains a URL that gives access to a Distribution of the Dataset. The resource at the access URL may contain information about how to get the Dataset.",
+        "card": "1..n",
+        "geodcat": false
+    },
+    {
+        "property": "availability",
+        "uri": "dcatap:availability",
+        "range": "skos:Concept",
+        "usageNote": "This property indicates how long it is planned to keep the Distribution of the Dataset available.",
+        "card": "0..1",
+        "geodcat": false
+    },
+    {
+        "property": "description",
+        "uri": "dct:description",
+        "range": "rdfs:Literal",
+        "usageNote": "This property contains a free-text account of the Distribution. This property can be repeated for parallel language versions of the description.",
+        "card": "0..n",
+        "geodcat": false
+    },
+    {
+        "property": "format",
+        "uri": "dct:format",
+        "range": "dct:MediaTypeOrExtent",
+        "usageNote": "This property refers to the file format of the Distribution.",
+        "card": "0..1",
+        "geodcat": false
+    },
+    {
+        "property": "licence",
+        "uri": "dct:license",
+        "range": "dct:LicenseDocument",
+        "usageNote": "This property refers to the licence under which the Distribution is made available.",
+        "card": "0..1",
+        "geodcat": false
+    },
+    {
+        "property": "access service",
+        "uri": "dcat:accessService",
+        "range": "dcat:DataService",
+        "usageNote": "This property refers to a data service that gives access to the distribution of the dataset",
+        "card": "0..n",
+        "geodcat": false
+    },
+    {
+        "property": "byte size",
+        "uri": "dcat:byteSize",
+        "range": "rdfs:Literal typed as xsd:decimal",
+        "usageNote": "This property contains the size of a Distribution in bytes.",
+        "card": "0..1",
+        "geodcat": false
+    },
+    {
+        "property": "Checksum",
+        "uri": "spdx:checksum",
+        "range": "spdx:Checksum",
+        "usageNote": "This property provides a mechanism that can be used to verify that the contents of a distribution have not changed. The checksum is related to the downloadURL.",
+        "card": "0..1",
+        "geodcat": false
+    },
+    {
+        "property": "compression format",
+        "uri": "dcat:compressFormat",
+        "range": "dct:MediaType",
+        "usageNote": "This property refers to the format of the file in which the data is contained in a compressed form, e.g. to reduce the size of the downloadable file. It SHOULD be expressed using a media type as defined in the official register of media types managed by IANA.",
+        "card": "0..1",
+        "geodcat": false
+    },
+    {
+        "property": "Documentation",
+        "uri": "foaf:page",
+        "range": "foaf:Document",
+        "usageNote": "This property refers to a page or document about this Distribution.",
+        "card": "0..n",
+        "geodcat": false
+    },
+    {
+        "property": "download URL",
+        "uri": "dcat:downloadURL",
+        "range": "rdfs:Resource",
+        "usageNote": "This property contains a URL that is a direct link to a downloadable file in a given format.",
+        "card": "0..n",
+        "geodcat": false
+    },
+    {
+        "property": "has policy",
+        "uri": "odrl:hasPolicy",
+        "range": "odrl:Policy",
+        "usageNote": "This property refers to the policy expressing the rights associated with the distribution if using the ODRL vocabulary",
+        "card": "0..1",
+        "geodcat": false
+    },
+    {
+        "property": "Language",
+        "uri": "dct:language",
+        "range": "dct:LinguisticSystem",
+        "usageNote": "This property refers to a language used in the Distribution. This property can be repeated if the metadata is provided in multiple languages.",
+        "card": "0..n",
+        "geodcat": false
+    },
+    {
+        "property": "linked schemas",
+        "uri": "dct:conformsTo",
+        "range": "dct:Standard",
+        "usageNote": "This property refers to an established schema to which the described Distribution conforms.",
+        "card": "0..n",
+        "geodcat": false
+    },
+    {
+        "property": "media type",
+        "uri": "dcat:mediaType",
+        "range": "dct:MediaType",
+        "usageNote": "This property refers to the media type of the Distribution as defined in the official register of media types managed by IANA.",
+        "card": "0..1",
+        "geodcat": false
+    },
+    {
+        "property": "packaging format",
+        "uri": "dcat:packageFormat",
+        "range": "dct:MediaType",
+        "usageNote": "This property refers to the format of the file in which one or more data files are grouped together, e.g. to enable a set of related files to be downloaded together. It SHOULD be expressed using a media type as defined in the official register of media types managed by IANA.",
+        "card": "0..1",
+        "geodcat": false
+    },
+    {
+        "property": "release date",
+        "uri": "dct:issued",
+        "range": "rdfs:Literal typed as xsd:date or xsd:dateTime",
+        "usageNote": "This property contains the date of formal issuance (e.g., publication) of the Distribution.",
+        "card": "0..1",
+        "geodcat": false
+    },
+    {
+        "property": "Rights",
+        "uri": "dct:rights",
+        "range": "dct:RightsStatement",
+        "usageNote": "This property refers to a statement that specifies rights associated with the Distribution.",
+        "card": "0..1",
+        "geodcat": false
+    },
+    {
+        "property": "spatial resolution",
+        "uri": "dcat:spatialResolutionInMeters",
+        "range": "xsd:decimal",
+        "usageNote": "This property refers to the minimum spatial separation resolvable in a dataset distribution, measured in meters.",
+        "card": "0..n",
+        "geodcat": false
+    },
+    {
+        "property": "status",
+        "uri": "adms:status",
+        "range": "skos:Concept",
+        "usageNote": "This property refers to the maturity of the Distribution. It MUST take one of the values Completed, Deprecated, Under Development, Withdrawn.",
+        "card": "0..1",
+        "geodcat": false
+    },
+    {
+        "property": "temporal resolution",
+        "uri": "dcat:temporalResolution",
+        "range": "xsd:duration",
+        "usageNote": "This property refers to the minimum time period resolvable in the dataset distribution.",
+        "card": "0..n",
+        "geodcat": false
+    },
+    {
+        "property": "Title",
+        "uri": "dct:title",
+        "range": "rdfs:Literal",
+        "usageNote": "This property contains a name given to the Distribution. This property can be repeated for parallel language versions of the description.",
+        "card": "0..n",
+        "geodcat": false
+    },
+    {
+        "property": "update/ modification date",
+        "uri": "dct:modified",
+        "range": "rdfs:Literal typed as xsd:date or xsd:dateTime",
+        "usageNote": "This property contains the most recent date on which the Distribution was changed or modified.",
+        "card": "0..1",
+        "geodcat": false
+    },
+    {
+        "property": "representation technique",
+        "uri": "adms:representationTechnique",
+        "range": "skos:Concept",
+        "usageNote": "This property MAY be used to provide more information about the format in which an Distribution is released. This is different from the file format as, for example, a ZIP file (file format) could contain an XML schema (representation technique). In GeoDCAT-AP, this property SHOULD be used to express the spatial representation type (grid, vector, tin), by using the URIs of the corresponding code list operated by the INSPIRE Registry [INSPIRE-SRT].",
+        "card": "0..1",
+        "geodcat": true
+    }, {
+        "property": "character encoding",
+        "uri": "cnt:characterEncoding",
+        "range": "rdfs:Literal",
+        "usageNote": "This property SHOULD be used to specify the character encoding of the Distribution, by using as value the character set names in the IANA register [IANA-CHARSETS].",
+        "card": "0..n",
+        "geodcat": true
+    }, {
+        "property": "access rights",
+        "uri": "dct:accessRights",
+        "range": "dct:RightsStatement",
+        "usageNote": "This property MAY include information regarding access or restrictions based on privacy, security, or other policies. For INSPIRE metadata, this property SHOULD be used with the URIs of the \"Limitations on public access \" code list operated by the INSPIRE Registry [INSPIRE-LPA].",
+        "card": "0..1",
+        "geodcat": true
+    }, {
+        "property": "reference system",
+        "uri": "dct:conformsTo",
+        "range": "dct:Standard",
+        "usageNote": "This property SHOULD be used to specify the reference system used in the Distribution. Spatial reference systems SHOULD be specified by using the corresponding URIs from the “EPSG coordinate reference systems” register operated by OGC [OGC-EPSG].",
+        "card": "0..n",
+        "geodcat": true
+    }, {
+        "property": "spatial resolution",
+        "uri": "dqv:hasQualityMeasurement",
+        "range": "dqv:QualityMeasurement",
+        "usageNote": "Refers to the performed quality measurements. In GeoDCAT-AP, this property is used to specify \"spatial resolution\", as defined in [INSPIRE-MD-REG], [ISO-19115], and [ISO-19115-1].",
+        "card": "0..n",
+        "geodcat": true
+    }, {
+        "property": "spatial resolution as text",
+        "uri": "rdfs:comment",
+        "range": "rdfs:Literal",
+        "usageNote": "This property MAY be used to express spatial resolution types that cannot be specified via dcat:spatialResolutionInMeters - i.e., spatial resolution as equivalent scale, angular distance, vertical distance.",
+        "card": "0..n",
+        "geodcat": true
+    }
+]
\ No newline at end of file
-- 
GitLab


From 777cba416673225410e39d6ed63d8bf0468c534d Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Wed, 6 Oct 2021 15:21:40 +0200
Subject: [PATCH 02/19] add properties to ui an refactoring

---
 src/app/mapping/class/dataset.ts       |  26 +-
 src/app/mapping/mapping.component.html | 120 ++++++--
 src/app/mapping/mapping.component.ts   |  31 +-
 src/assets/distribution.json           |   6 +-
 src/assets/geodcat.json                | 383 ++++++++++++++++---------
 5 files changed, 379 insertions(+), 187 deletions(-)

diff --git a/src/app/mapping/class/dataset.ts b/src/app/mapping/class/dataset.ts
index 29f570784..3fa58fbda 100644
--- a/src/app/mapping/class/dataset.ts
+++ b/src/app/mapping/class/dataset.ts
@@ -1,22 +1,27 @@
-export class Dataset {
-    public name: string;
-    public identifier: string;
+export class Property {
+    public property: string;
+    public uri: string;
     public usageNote: string;
-    public isDuplicated: boolean;
+    public range?: string;
+    public card: string;
+    public geodcat: boolean;
+    public isDuplicated?: boolean = false;
 
-    constructor(name: string, identifier: string, usageNote: string, isDuplicated: boolean) {
-        this.name = name;
-        this.identifier = identifier;
+    constructor(name: string, identifier: string, usageNote: string, isDuplicated: boolean, card: string, geodcat:boolean) {
+        this.property = name;
+        this.uri = identifier;
         this.usageNote = usageNote;
         this.isDuplicated = isDuplicated;
+        this.card = card;
+        this.geodcat = geodcat;
     }
 }
 
 export class DatasetPath {
-    public dcatProperty: Dataset | string;
+    public dcatProperty: Property | string;
     public path: string
 
-    constructor(dcatProperty: Dataset, path: string) {
+    constructor(dcatProperty: Property, path: string) {
         this.dcatProperty = dcatProperty;
         this.path = path;
     }
@@ -29,6 +34,9 @@ export class Distribution {
     public usageNote: string;
     public card: string;
     public geodcat: boolean;
+    public isDuplicated?: boolean = false;
+
+    
 }
 
 
diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html
index 19d00a8b8..8857c580a 100644
--- a/src/app/mapping/mapping.component.html
+++ b/src/app/mapping/mapping.component.html
@@ -12,6 +12,82 @@
         <div class="card-col">
             <nb-card size="giant">
                 <nb-card-header>Dataset metadata</nb-card-header>
+                <nb-card-body>
+                    
+
+                    <ng-container *ngFor="let dataset of dcatVocabulary ; let index = index ;trackBy:trackByIndex ;">
+                        <nb-form-field>
+                            <div class="row">
+
+                                <div class="col-3" style="margin-right: 10px;">
+
+                                    <nb-form-field>
+                                        <input
+                                            *ngIf=" dataset.uri !== 'dct:hasVersion' && dataset.uri !== 'dct:title'"
+                                            nbInput fullWidth type="text" value="{{dataset.uri}} " disabled />
+                                        <input
+                                            *ngIf=" dataset.uri === 'dct:hasVersion' || dataset.uri === 'dct:title' "
+                                            nbInput fullWidth type="text" value="{{dataset.uri}} *" disabled />
+                                        <button nbSuffix nbTooltip="{{dataset.property}}: {{dataset.usageNote}}"
+                                            nbTooltipStatus="info" nbButton status="basic" ghost>
+                                            <nb-icon [icon]=" 'question-mark-circle-outline' " pack="eva">
+                                            </nb-icon>
+                                        </button>
+                                    </nb-form-field>
+
+                                </div>
+                                <div class="col-7">
+
+                                    <nb-form-field>
+                                        <input
+                                            *ngIf="dataset.uri === 'dct:hasVersion' || dataset.uri === 'dct:title' "
+                                            required #autoInput #{{dataset.uri}}="ngModel" fullWidth
+                                            id="{{dataset.uri}}" name="{{dataset.uri}}" nbInput
+                                            (ngModelChange)="onModelChange($event)"  [nbAutocomplete]="auto"
+                                            [(ngModel)]="selectedPaths[index]" autocomplete="false" (focus)="reset()" />
+                                        <div
+                                            *ngIf="dataset.uri.invalid && (dataset.uri.dirty || dataset.uri.touched)">
+                                            champ obligatoire</div>
+                                        <input
+                                            *ngIf=" dataset.uri !== 'dct:hasVersion' && dataset.uri !== 'dct:title'"
+                                            #autoInput #{{dataset.uri}}="ngModel" fullWidth
+                                            id="{{dataset.uri}}" name="{{dataset.uri}}" nbInput
+                                            (ngModelChange)="onModelChange($event)"  [nbAutocomplete]="auto"
+                                            [(ngModel)]="selectedPaths[index]" autocomplete="false" (focus)="reset()" />
+    
+                                        <nb-autocomplete #auto>
+
+                                            <nb-option *ngFor="let option of filteredOptions | async" [value]="option">
+                                                {{ option }}
+                                            </nb-option>
+
+                                        </nb-autocomplete>
+                                    </nb-form-field>
+                                </div>
+                                <div class="col-2" *ngIf="isMultiple(dataset.uri)" style="margin-left: 10px;">
+                                    <button nbButton ghost (click)="addField(index)" *ngIf="!dataset.isDuplicated">
+                                        <nb-icon icon="plus-outline" status="primary">
+                                        </nb-icon>
+                                    </button>
+                                    <button nbButton ghost
+                                        *ngIf="dataset.isDuplicated"
+                                        (click)="deleteField(index)">
+                                        <nb-icon icon="trash-2-outline" status="danger">
+                                        </nb-icon>
+                                    </button>
+                                </div>
+                            </div>
+                        </nb-form-field>
+                    </ng-container>
+
+                </nb-card-body>
+            </nb-card>
+        </div>
+    </div>
+    <div class="card-row">
+        <div class="card-col">
+            <nb-card size="giant">
+                <nb-card-header>Distribution</nb-card-header>
                 <nb-card-body>
                     <div class="row">
                         <p>Upload Or fill out the form with the path corresponding to the dcat property and save a new
@@ -22,7 +98,7 @@
                         <input type="file" id="file" (change)="importJson($event)" accept=".json" />
                     </div>
 
-                    <ng-container *ngFor="let dataset of dcatVocabulary ; let index = index ;trackBy:trackByIndex ;">
+                    <ng-container *ngFor="let distribution of distributions ; let index = index ; trackBy:trackByIndex ;">
                         <nb-form-field>
                             <div class="row">
 
@@ -30,12 +106,12 @@
 
                                     <nb-form-field>
                                         <input
-                                            *ngIf=" dataset.identifier !== 'dct:hasVersion' && dataset.identifier !== 'dct:title'"
-                                            nbInput fullWidth type="text" value="{{dataset.identifier}} " disabled />
+                                            *ngIf=" distribution.card !== '1..n' || distribution.card !== '1..1'"
+                                            nbInput fullWidth type="text" value="{{distribution.uri}} " disabled />
                                         <input
-                                            *ngIf=" dataset.identifier === 'dct:hasVersion' || dataset.identifier === 'dct:title' "
-                                            nbInput fullWidth type="text" value="{{dataset.identifier}} *" disabled />
-                                        <button nbSuffix nbTooltip="{{dataset.name}}: {{dataset.usageNote}}"
+                                            *ngIf="  distribution.card === '1..n' || distribution.card === '1..1'"
+                                            nbInput fullWidth type="text" value="{{distribution.uri}} *" disabled />
+                                        <button nbSuffix nbTooltip="{{distribution.property}}: {{distribution.usageNote}}"
                                             nbTooltipStatus="info" nbButton status="basic" ghost>
                                             <nb-icon [icon]=" 'question-mark-circle-outline' " pack="eva">
                                             </nb-icon>
@@ -47,20 +123,20 @@
 
                                     <nb-form-field>
                                         <input
-                                            *ngIf="dataset.identifier === 'dct:hasVersion' || dataset.identifier === 'dct:title' "
-                                            required #autoInput #{{dataset.identifier}}="ngModel" fullWidth
-                                            id="{{dataset.identifier}}" name="{{dataset.identifier}}" nbInput
+                                            *ngIf="distribution.card === '1..n' || distribution.card === '1..1'"
+                                            required #autoInput #{{distribution.uri}}="ngModel" fullWidth
+                                            id="{{distribution.uri}}" name="{{distribution.uri}}" nbInput
                                             (ngModelChange)="onModelChange($event)"  [nbAutocomplete]="auto"
-                                            [(ngModel)]="selectedPaths[index]" autocomplete="false" (focus)="reset()" />
+                                            [(ngModel)]="distributionSelectedPaths[index]" autocomplete="false" (focus)="reset()" />
                                         <div
-                                            *ngIf="dataset.identifier.invalid && (dataset.identifier.dirty || dataset.identifier.touched)">
+                                            *ngIf="distribution.uri.invalid && (distribution.uri.dirty || distribution.uri.touched)">
                                             champ obligatoire</div>
                                         <input
-                                            *ngIf=" dataset.identifier !== 'dct:hasVersion' && dataset.identifier !== 'dct:title'"
-                                            #autoInput #{{dataset.identifier}}="ngModel" fullWidth
-                                            id="{{dataset.identifier}}" name="{{dataset.identifier}}" nbInput
+                                            *ngIf=" distribution.card !== '1..n' || distribution.card !== '1..1'"
+                                            #autoInput #{{dataset.uri}}="ngModel" fullWidth
+                                            id="{{distribution.uri}}" name="{{distribution.uri}}" nbInput
                                             (ngModelChange)="onModelChange($event)"  [nbAutocomplete]="auto"
-                                            [(ngModel)]="selectedPaths[index]" autocomplete="false" (focus)="reset()" />
+                                            [(ngModel)]="distributionSelectedPaths[index]" autocomplete="false" (focus)="reset()" />
     
                                         <nb-autocomplete #auto>
 
@@ -71,13 +147,13 @@
                                         </nb-autocomplete>
                                     </nb-form-field>
                                 </div>
-                                <div class="col-2" *ngIf="isMultiple(dataset.identifier)" style="margin-left: 10px;">
-                                    <button nbButton ghost (click)="addField(index)" *ngIf="!dataset.isDuplicated">
+                                <div class="col-2" *ngIf="distribution.card === '0..n' || distribution.card === '1..n' " style="margin-left: 10px;">
+                                    <button nbButton ghost (click)="addField(index)" *ngIf="!distribution.isDuplicated">
                                         <nb-icon icon="plus-outline" status="primary">
                                         </nb-icon>
                                     </button>
                                     <button nbButton ghost
-                                        *ngIf="dataset.isDuplicated"
+                                        *ngIf="distribution.isDuplicated"
                                         (click)="deleteField(index)">
                                         <nb-icon icon="trash-2-outline" status="danger">
                                         </nb-icon>
@@ -108,25 +184,25 @@
 
                     <nb-list-item *ngFor="let data of mappedMetadatas[index] | keyvalue; trackBy:trackByIndex; ">
                         <div class="row">
-                            <div class="col-3"><label for="{{data.key}}">{{dcatVocabulary[data.key].identifier}}</label>
+                            <div class="col-3"><label for="{{data.key}}">{{dcatVocabulary[data.key].uri}}</label>
                             </div>
                             <div class="col-7">
                                 <ng-template #normal>
                                     <input nbInput [ngModel]="data.value"
                                         (ngModelChange)="mappedMetadatas[index].set(data.key, $event)" />
                                 </ng-template>
-                                <ng-container *ngIf="isArray(data.value) && !isMultiple(dcatVocabulary[data.key].identifier); else normal">
+                                <ng-container *ngIf="isArray(data.value) && !isMultiple(dcatVocabulary[data.key].uri); else normal">
                                     <input nbInput [ngModel]="data.value[0]"
                                         (ngModelChange)="mappedMetadatas[index].set(data.key, $event)" />
                                 </ng-container>
                                 <ng-container
-                                    *ngIf="isArray(data.value) && isMultiple(dcatVocabulary[data.key].identifier)">
+                                    *ngIf="isArray(data.value) && isMultiple(dcatVocabulary[data.key].uri)">
                                     <ul *ngFor="let val of data.value" style="margin-left: -100px;">
                                         <li>
                                             <div class="row">
                                                 <div class="col-3">
                                                     <label
-                                                        for="{{data.key}}">{{dcatVocabulary[data.key].identifier}}</label>
+                                                        for="{{data.key}}">{{dcatVocabulary[data.key].uri}}</label>
                                                 </div>
                                                 <div class="col-7">
                                                     <input nbInput [ngModel]="val"
diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts
index bf93bbbef..719ed2a2a 100644
--- a/src/app/mapping/mapping.component.ts
+++ b/src/app/mapping/mapping.component.ts
@@ -11,7 +11,7 @@ import { map } from 'rxjs/operators';
 import { environment } from 'src/environments/environment.prod';
 import { DatasetCrudService } from '../datasets/services/dataset-crud.service';
 
-import { Dataset, DatasetPath, Distribution } from './class/dataset';
+import { Property, DatasetPath, Distribution } from './class/dataset';
 import { FeedbackDialogComponent } from './dialog/feedback-dialog/feedback-dialog.component';
 
 
@@ -25,11 +25,12 @@ export class MappingComponent implements OnInit {
   distributions: Distribution[] = [];
   ontology: string;
   itemsdataset: Object[] = []
-  dcatVocabulary: Dataset[];
-  vocabularies: Dataset[];
+  dcatVocabulary: Property[];
+  vocabularies: Property[];
   filteredOptions: Observable<string[]>;
   keys: string[] = [];
   selectedPaths: string[];
+  distributionSelectedPaths: string[];
   mappedMetadatas: Map<number, string>[] = [];
   DatasetToPublish: Map<string, string>[];
   index: number = 0
@@ -55,11 +56,10 @@ export class MappingComponent implements OnInit {
   }
 
   selectOntology(): void {
-    
-      this.dataSetService.getLocally('./assets/'+ this.ontology + '.json').subscribe(
-        dataset => {
-          this.dcatVocabulary = dataset;
-          this.vocabularies = dataset;
+      this.dataSetService.getLocally(`./assets/geodcat.json`).subscribe(
+        datasets => {
+          this.dcatVocabulary = this.ontology === "dcat" ? datasets.filter(d => !d.geodcat) : datasets;
+          this.vocabularies = this.ontology === "dcat" ? datasets.filter(d => !d.geodcat) : datasets;;
           this.selectedPaths = [];
           
         },
@@ -67,6 +67,13 @@ export class MappingComponent implements OnInit {
           console.error(error);
         },
       );
+      this.dataSetService.getLocally('./assets/distribution.json').subscribe(
+        (distributions: Distribution[]) => {
+          this.distributions = this.ontology === "dcat" ? distributions.filter(d => !d.geodcat) : distributions;
+          this.vocabularies = this.vocabularies.concat(this.distributions);
+          this.distributionSelectedPaths = [];
+        }
+      )
   }
 
 
@@ -93,7 +100,7 @@ export class MappingComponent implements OnInit {
     for (let i = 0; i < this.mappedMetadatas.length; i++) {
       properties = "";
       this.mappedMetadatas[i].forEach((value: string, index: number) => {
-        let key = this.dcatVocabulary[index].identifier;
+        let key = this.dcatVocabulary[index].uri;
         if (Array.isArray(value)) {
           if (this.isMultiple(key)) {
             value.forEach(v => {
@@ -375,9 +382,9 @@ export class MappingComponent implements OnInit {
       for (let i = 0; i < datasetPath.length; i++) {
         this.selectedPaths[i] = datasetPath[i].path;
         if (typeof datasetPath[i].dcatProperty !== 'object') {
-          this.dcatVocabulary[i] = this.vocabularies.filter( v => v.identifier === <string>datasetPath[i].dcatProperty)[0];
+          this.dcatVocabulary[i] = this.vocabularies.filter( v => v.uri === <string>datasetPath[i].dcatProperty)[0];
         } else {
-          this.dcatVocabulary[i] = <Dataset>datasetPath[i].dcatProperty;
+          this.dcatVocabulary[i] = <Property>datasetPath[i].dcatProperty;
         }
       }
     }
@@ -385,7 +392,7 @@ export class MappingComponent implements OnInit {
   }
 
   addField(index: number) {
-    let addedDcat: Dataset = new Dataset(this.dcatVocabulary[index].name, this.dcatVocabulary[index].identifier, this.dcatVocabulary[index].usageNote, true);
+    let addedDcat: Property = new Property(this.dcatVocabulary[index].property, this.dcatVocabulary[index].uri, this.dcatVocabulary[index].usageNote, true, this.dcatVocabulary[index].card, this.dcatVocabulary[index].geodcat);
     this.dcatVocabulary.splice(index + 1, 0, addedDcat);
   }
 
diff --git a/src/assets/distribution.json b/src/assets/distribution.json
index ca967ba89..aa93eb4db 100644
--- a/src/assets/distribution.json
+++ b/src/assets/distribution.json
@@ -4,7 +4,7 @@
         "uri": "dcat:accessURL",
         "range": "rdfs:Resource",
         "usageNote": "This property contains a URL that gives access to a Distribution of the Dataset. The resource at the access URL may contain information about how to get the Dataset.",
-        "card": "1..n",
+        "card": "0..1",
         "geodcat": false
     },
     {
@@ -84,7 +84,7 @@
         "uri": "dcat:downloadURL",
         "range": "rdfs:Resource",
         "usageNote": "This property contains a URL that is a direct link to a downloadable file in a given format.",
-        "card": "0..n",
+        "card": "0..1",
         "geodcat": false
     },
     {
@@ -116,7 +116,7 @@
         "uri": "dcat:mediaType",
         "range": "dct:MediaType",
         "usageNote": "This property refers to the media type of the Distribution as defined in the official register of media types managed by IANA.",
-        "card": "0..1",
+        "card": "1..1",
         "geodcat": false
     },
     {
diff --git a/src/assets/geodcat.json b/src/assets/geodcat.json
index 521a168a7..2a4d0774f 100644
--- a/src/assets/geodcat.json
+++ b/src/assets/geodcat.json
@@ -1,237 +1,338 @@
 [
     {
-        "name": "title",
-        "identifier": "dct:title",
-        "usageNote": "Mandatory property. This property contains a name given to the Dataset. This property can be repeated for parallel language versions of the name."
+        "property": "title",
+        "uri": "dct:title",
+        "usageNote": "Mandatory property. This property contains a property given to the Dataset. This property can be repeated for parallel language versions of the name.",
+        "card": "1..n",
+        "geodcat": false
     },
     {
-        "name": "has Version",
-        "identifier": "dct:hasVersion",
-        "usageNote": "Optional property.This property refers to a related Dataset that is a version, edition, or adaptation of the described Dataset."
+        "property": "has Version",
+        "uri": "dct:hasVersion",
+        "usageNote": "Optional property.This property refers to a related Dataset that is a version, edition, or adaptation of the described Dataset.",
+        "card": "1..n",
+        "geodcat": false
     },
     {
-        "name": "description",
-        "identifier": "dct:description",
-        "usageNote": "Mandatory property. This property contains a free-text account of the Dataset. This property can be repeated for parallel language versions of the description."
+        "property": "description",
+        "uri": "dct:description",
+        "usageNote": "Mandatory property. This property contains a free-text account of the Dataset. This property can be repeated for parallel language versions of the description.",
+        "card": "1..n",
+        "geodcat": false
     },
     {
-        "name": "contact point",
-        "identifier": "dcat:contactPoint",
-        "usageNote": "Recommended property.This property contains contact information that can be used for sending comments about the Dataset."
+        "property": "contact point",
+        "uri": "dcat:contactPoint",
+        "usageNote": "Recommended property.This property contains contact information that can be used for sending comments about the Dataset.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "dataset distribution",
-        "identifier": "dcat:distribution",
-        "usageNote": "Recommended property. This property links the Dataset to an available Distribution."
+        "property": "dataset distribution",
+        "uri": "dcat:distribution",
+        "usageNote": "Recommended property. This property links the Dataset to an available Distribution.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "keyword/ tag",
-        "identifier": "dcat:keyword",
-        "usageNote": "Recommended property. This property contains a keyword or tag describing the Dataset."
+        "property": "keyword/ tag",
+        "uri": "dcat:keyword",
+        "usageNote": "Recommended property. This property contains a keyword or tag describing the Dataset.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "publisher",
-        "identifier": "dct:publisher",
-        "usageNote": "Recommended property. This property refers to an entity (organisation) responsible for making the Dataset available."
+        "property": "publisher",
+        "uri": "dct:publisher",
+        "usageNote": "Recommended property. This property refers to an entity (organisation) responsible for making the Dataset available.",
+        "card": "0..1",
+        "geodcat": false
     },
     {
-        "name": "spatial/geographical coverage",
-        "identifier": "dct:spatial",
-        "usageNote": "Recommended property. This property refers to a geographic region that is covered by the Dataset. "
+        "property": "spatial/geographical coverage",
+        "uri": "dct:spatial",
+        "usageNote": "Recommended property. This property refers to a geographic region that is covered by the Dataset. ",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "theme/category",
-        "identifier": "dcat:theme",
-        "usageNote": "Recommended property. This property refers to a category of the Dataset. A Dataset may be associated with multiple themes. Subproperty of dct:subject."
+        "property": "theme/category",
+        "uri": "dcat:theme",
+        "usageNote": "Recommended property. This property refers to a category of the Dataset. A Dataset may be associated with multiple themes. Subproperty of dct:subject.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "temporal coverage",
-        "identifier": "dct:temporal",
-        "usageNote": "Recommended property. This property refers to a temporal period that the Dataset covers."
+        "property": "temporal coverage",
+        "uri": "dct:temporal",
+        "usageNote": "Recommended property. This property refers to a temporal period that the Dataset covers.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "conforms to",
-        "identifier": "dct:conformsTo",
-        "usageNote": "Optional property. This property refers to an implementing rule or other specification."
+        "property": "conforms to",
+        "uri": "dct:conformsTo",
+        "usageNote": "Optional property. This property refers to an implementing rule or other specification.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "creation date",
-        "identifier": "dct:created",
-        "usageNote": "Optional property. This property contains the date on which the Dataset has been first created."
+        "property": "creation date",
+        "uri": "dct:created",
+        "usageNote": "Optional property. This property contains the date on which the Dataset has been first created.",
+        "card": "0..1",
+        "geodcat": true
     },
     {
-        "name": "frequency",
-        "identifier": "dct:accrualPeriodicity",
-        "usageNote": "Optional property. This property refers to the frequency at which Dataset is updated."
+        "property": "frequency",
+        "uri": "dct:accrualPeriodicity",
+        "usageNote": "Optional property. This property refers to the frequency at which Dataset is updated.",
+        "card": "0..1",
+        "geodcat": false
     },
     {
-        "name": "identifier",
-        "identifier": "dct:identifier",
-        "usageNote": "Optional property. This property contains the main identifier for the Dataset, e.g. the URI or other unique identifier in the context of the Catalogue."
+        "property": "identifier",
+        "uri": "dct:identifier",
+        "usageNote": "Optional property. This property contains the main identifier for the Dataset, e.g. the URI or other unique identifier in the context of the Catalogue.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "landing page",
-        "identifier": "dcat:landingPage",
-        "usageNote": "Optional property. This property refers to a web page that provides access to the Dataset, its Distributions and/or additional information."
+        "property": "landing page",
+        "uri": "dcat:landingPage",
+        "usageNote": "Optional property. This property refers to a web page that provides access to the Dataset, its Distributions and/or additional information.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "language",
-        "identifier": "dct:language",
-        "usageNote": "Optional property. This property refers to a language of the Dataset. This property can be repeated if there are multiple languages in the Dataset."
+        "property": "language",
+        "uri": "dct:language",
+        "usageNote": "Optional property. This property refers to a language of the Dataset. This property can be repeated if there are multiple languages in the Dataset.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "other identifier",
-        "identifier": "adms:identifier",
-        "usageNote": "Optional property. This property refers to a secondary identifier of the Dataset, such as MAST/ADS[1], DataCite[2], DOI[3], EZID[4] or W3ID[5]."
+        "property": "other identifier",
+        "uri": "adms:identifier",
+        "usageNote": "Optional property. This property refers to a secondary identifier of the Dataset, such as MAST/ADS[1], DataCite[2], DOI[3], EZID[4] or W3ID[5].",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "release date ",
-        "identifier": "dct:issued",
-        "usageNote": "Optional property. This property contains the date of formal issuance (e.g., publication) of the Dataset."
+        "property": "release date ",
+        "uri": "dct:issued",
+        "usageNote": "Optional property. This property contains the date of formal issuance (e.g., publication) of the Dataset.",
+        "card": "0..1",
+        "geodcat": false
     },
     {
-        "name": "rights holder",
-        "identifier": "dct:rightsHolder",
-        "usageNote": "Optional property. This property refers to an Agent (organisation) holding rights on the Dataset."
+        "property": "rights holder",
+        "uri": "dct:rightsHolder",
+        "usageNote": "Optional property. This property refers to an Agent (organisation) holding rights on the Dataset.",
+        "card": "0..n",
+        "geodcat": true
     },
     {
-        "name": "update/modification date",
-        "identifier": "dct:modified",
-        "usageNote": "Optional property. This property contains the most recent date on which the Dataset was changed or modified."
+        "property": "update/modification date",
+        "uri": "dct:modified",
+        "usageNote": "Optional property. This property contains the most recent date on which the Dataset was changed or modified.",
+        "card": "0..1",
+        "geodcat": false
     },
     {
-        "name": "provenance",
-        "identifier": "dct:provenance",
-        "usageNote": "Optional property. This property contains a statement about the lineage of a Dataset."
+        "property": "provenance",
+        "uri": "dct:provenance",
+        "usageNote": "Optional property. This property contains a statement about the lineage of a Dataset.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "sample",
-        "identifier": "adms:sample",
-        "usageNote": "Optional property. This property refers to a sample distribution of the dataset."
+        "property": "sample",
+        "uri": "adms:sample",
+        "usageNote": "Optional property. This property refers to a sample distribution of the dataset.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "source",
-        "identifier": "dct:source",
-        "usageNote": "Optional property. This property refers to a related Dataset from which the described Dataset is derived."
+        "property": "source",
+        "uri": "dct:source",
+        "usageNote": "Optional property. This property refers to a related Dataset from which the described Dataset is derived.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "topic category",
-        "identifier": "dct:subject",
-        "usageNote": "Optional property. In GeoDCAT-AP, this property SHOULD take as value one of the URIs of the \"Topic categories in accordance with EN ISO 19115\" code list operated by the INSPIRE Registry [INSPIRE-TC]."
+        "property": "topic category",
+        "uri": "dct:subject",
+        "usageNote": "Optional property. In GeoDCAT-AP, this property SHOULD take as value one of the URIs of the \"Topic categories in accordance with EN ISO 19115\" code list operated by the INSPIRE Registry [INSPIRE-TC].",
+        "card": "0..n",
+        "geodcat": true
     },
     {
-        "name": "type",
-        "identifier": "dct:type",
-        "usageNote": "Optional property. This property refers to the type of the Dataset. A controlled vocabulary for the values has not been established."
+        "property": "type",
+        "uri": "dct:type",
+        "usageNote": "Optional property. This property refers to the type of the Dataset. A controlled vocabulary for the values has not been established.",
+        "card": "0..1",
+        "geodcat": false
     },
     {
-        "name": "related resource",
-        "identifier": "dct:relation",
-        "usageNote": "Optional property. This property refers to a related resource."
+        "property": "related resource",
+        "uri": "dct:relation",
+        "usageNote": "Optional property. This property refers to a related resource.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "version",
-        "identifier": "owl:versionInfo",
-        "usageNote": "Optional property. This property contains a version number or other version designation of the Dataset."
+        "property": "version",
+        "uri": "owl:versionInfo",
+        "usageNote": "Optional property. This property contains a version number or other version designation of the Dataset.",
+        "card": "0..1",
+        "geodcat": false
     },
     {
-        "name": "version notes",
-        "identifier": "adms:versionNotes",
-        "usageNote": "Optional property. This property contains a description of the differences between this version and a previous version of the Dataset."
+        "property": "version notes",
+        "uri": "adms:versionNotes",
+        "usageNote": "Optional property. This property contains a description of the differences between this version and a previous version of the Dataset.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "is Version Of",
-        "identifier": "dct:isVersionOf",
-        "usageNote": "Optional property. This property refers to a related Dataset of which the described Dataset is a version, edition, or adaptation."
+        "property": "is Version Of",
+        "uri": "dct:isVersionOf",
+        "usageNote": "Optional property. This property refers to a related Dataset of which the described Dataset is a version, edition, or adaptation.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "documentation",
-        "identifier": "foaf:page",
-        "usageNote": "Optional property. This property refers to a page or document about this Dataset."
+        "property": "documentation",
+        "uri": "foaf:page",
+        "usageNote": "Optional property. This property refers to a page or document about this Dataset.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "access rights",
-        "identifier": "dct:accessRights",
-        "usageNote": "Optional property. This property refers to information that indicates whether the Dataset is open data, has access restrictions or is not public. A controlled vocabulary with three members (:public, :restricted, :non-public) will be created and maintained by the Publications Office of the EU."
+        "property": "access rights",
+        "uri": "dct:accessRights",
+        "usageNote": "Optional property. This property refers to information that indicates whether the Dataset is open data, has access restrictions or is not public. A controlled vocabulary with three members (:public, :restricted, :non-public) will be created and maintained by the Publications Office of the EU.",
+        "card": "0..1",
+        "geodcat": false
     },
     {
-        "name": "creator",
-        "identifier": "dct:creator",
-        "usageNote": "Optional property. This property refers to an entity primarily responsible for making the resource."
+        "property": "creator",
+        "uri": "dct:creator",
+        "usageNote": "Optional property. This property refers to an entity primarily responsible for making the resource.",
+        "card": "0..1",
+        "geodcat": false
     },
     {
-        "name": "qualified attribution",
-        "identifier": "prov:qualifiedAttribution",
-        "usageNote": "Optional property. This property refers to the link to an Agent having some form of responsibility for the resource. "
+        "property": "qualified attribution",
+        "uri": "prov:qualifiedAttribution",
+        "usageNote": "Optional property. This property refers to the link to an Agent having some form of responsibility for the resource. ",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "was generated by",
-        "identifier": "prov:wasGeneratedBy",
-        "usageNote": "Optional property. This property refers to an activity that generated, or provides the business context for, the creation of the dataset."
+        "property": "was generated by",
+        "uri": "prov:wasGeneratedBy",
+        "usageNote": "Optional property. This property refers to an activity that generated, or provides the business context for, the creation of the dataset.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "was used by",
-        "identifier": "prov:wasUsedBy",
-        "usageNote": "Optional property. This property refers to an Activity that used the Dataset. In GeoDCAT-AP, this property MAY be used to specify a testing Activity over a Dataset, against a given Standard, producing as output a conformance degree."
+        "property": "was used by",
+        "uri": "prov:wasUsedBy",
+        "usageNote": "Optional property. This property refers to an Activity that used the Dataset. In GeoDCAT-AP, this property MAY be used to specify a testing Activity over a Dataset, against a given Standard, producing as output a conformance degree.",
+        "card": "0..n",
+        "geodcat": true
     },
     {
-        "name": "temporal resolution",
-        "identifier": "dcat:temporalResolution",
-        "usageNote": "This property refers to the minimum time period resolvable in the dataset."
+        "property": "temporal resolution",
+        "uri": "dcat:temporalResolution",
+        "usageNote": "This property refers to the minimum time period resolvable in the dataset.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "spatial resolution",
-        "identifier": "dqv:hasQualityMeasurement",
-        "usageNote": "Optional property. Refers to the performed quality measurements. In GeoDCAT-AP, this property is used to specify \"spatial resolution\", as defined in [INSPIRE-MD-REG], [ISO-19115], and [ISO-19115-1]."
+        "property": "spatial resolution",
+        "uri": "dqv:hasQualityMeasurement",
+        "usageNote": "Optional property. Refers to the performed quality measurements. In GeoDCAT-AP, this property is used to specify \"spatial resolution\", as defined in [INSPIRE-MD-REG], [ISO-19115], and [ISO-19115-1].",
+        "card": "0..n",
+        "geodcat": true
     },
     {
-        "name": "spatial resolution in metres",
-        "identifier": "dcat:spatialResolutionInMeters",
-        "usageNote": "Optional property. This property refers to the minimum spatial separation resolvable in a dataset, measured in meters. "
+        "property": "spatial resolution in metres",
+        "uri": "dcat:spatialResolutionInMeters",
+        "usageNote": "Optional property. This property refers to the minimum spatial separation resolvable in a dataset, measured in meters. ",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "is reference by",
-        "identifier": "dct:isReferencedBy",
-        "usageNote": "Optional property. This property refers to a related resource, such as a publication, that references, cites, or otherwise points to the dataset."
+        "property": "spatial resolution as text",
+        "uri": "rdfs:comment",
+        "usageNote": "Optional property. This property MAY be used to express spatial resolution as free-text, when it cannot be specified via dqv:hasQualityMeasurement and dcat:spatialResolutionInMeters. ",
+        "card": "0..n",
+        "geodcat": true
     },
     {
-        "name": "custodian",
-        "identifier": "geodcat:custodian",
-        "usageNote": "Optional property. Party that accepts accountability and responsibility for the data and ensures appropriate care and maintenance of the resource [ISO-19115]."
+        "property": "is reference by",
+        "uri": "dct:isReferencedBy",
+        "usageNote": "Optional property. This property refers to a related resource, such as a publication, that references, cites, or otherwise points to the dataset.",
+        "card": "0..n",
+        "geodcat": false
     },
     {
-        "name": "distributor",
-        "identifier": "geodcat:distributor",
-        "usageNote": "Optional property. Party who distributes the resource [ISO-19115]."
+        "property": "custodian",
+        "uri": "geodcat:custodian",
+        "usageNote": "Optional property. Party that accepts accountability and responsibility for the data and ensures appropriate care and maintenance of the resource [ISO-19115].",
+        "card": "0..n",
+        "geodcat": true
     },
     {
-        "name": "originator",
-        "identifier": "geodcat:originator",
-        "usageNote": "Optional property. Party who created the resource [ISO-19115]."
+        "property": "distributor",
+        "uri": "geodcat:distributor",
+        "usageNote": "Optional property. Party who distributes the resource [ISO-19115].",
+        "card": "0..n",
+        "geodcat": true
     },
     {
-        "name": "principal investigator",
-        "identifier": "geodcat:principalInvestigator",
-        "usageNote": "Optional property. Key party responsible for gathering information and conducting research [ISO-19115]."
+        "property": "originator",
+        "uri": "geodcat:originator",
+        "usageNote": "Optional property. Party who created the resource [ISO-19115].",
+        "card": "0..n",
+        "geodcat": true
     },
     {
-        "name": "processor",
-        "identifier": "geodcat:processor",
-        "usageNote": "Optional property. Party who has processed the data in a manner such that the resource has been modified [ISO-19115]."
+        "property": "principal investigator",
+        "uri": "geodcat:principalInvestigator",
+        "usageNote": "Optional property. Key party responsible for gathering information and conducting research [ISO-19115].",
+        "card": "0..n",
+        "geodcat": true
     },
     {
-        "name": "resource provider",
-        "identifier": "geodcat:resourceProvider",
-        "usageNote": "Optional property. Party that supplies the resource [ISO-19115]."
+        "property": "processor",
+        "uri": "geodcat:processor",
+        "usageNote": "Optional property. Party who has processed the data in a manner such that the resource has been modified [ISO-19115].",
+        "card": "0..n",
+        "geodcat": true
     },
     {
-        "name": "user",
-        "identifier": "geodcat:user",
-        "usageNote": "Optional property. Party who uses the resource [ISO-19115]."
+        "property": "resource provider",
+        "uri": "geodcat:resourceProvider",
+        "usageNote": "Optional property. Party that supplies the resource [ISO-19115].",
+        "card": "0..n",
+        "geodcat": true
     },
     {
-        "name": "qualified Relation",
-        "identifier": "dcat:qualifiedRelation",
-        "usageNote": "Deprecated property. This property provides a link to a description of a relationship with another resource."
+        "property": "user",
+        "uri": "geodcat:user",
+        "usageNote": "Optional property. Party who uses the resource [ISO-19115].",
+        "card": "0..n",
+        "geodcat": true
+    },
+    {
+        "property": "qualified Relation",
+        "uri": "dcat:qualifiedRelation",
+        "usageNote": "Optional property. This property provides a link to a description of a relationship with another resource.",
+        "card": "0..n",
+        "geodcat": false
     }
 ]
\ No newline at end of file
-- 
GitLab


From f3e42772e4c8507eae44a531778754b986a657f9 Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Wed, 6 Oct 2021 16:57:52 +0200
Subject: [PATCH 03/19] fix

---
 src/app/mapping/mapping.component.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts
index 719ed2a2a..31cfa3190 100644
--- a/src/app/mapping/mapping.component.ts
+++ b/src/app/mapping/mapping.component.ts
@@ -70,7 +70,7 @@ export class MappingComponent implements OnInit {
       this.dataSetService.getLocally('./assets/distribution.json').subscribe(
         (distributions: Distribution[]) => {
           this.distributions = this.ontology === "dcat" ? distributions.filter(d => !d.geodcat) : distributions;
-          this.vocabularies = this.vocabularies.concat(this.distributions);
+          this.vocabularies = this.vocabularies.concat(this.ontology === "dcat" ? distributions.filter(d => !d.geodcat) : distributions);
           this.distributionSelectedPaths = [];
         }
       )
-- 
GitLab


From 7ef920232a69f4496c221373094504bd77622534 Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Thu, 21 Oct 2021 11:42:53 +0200
Subject: [PATCH 04/19] bug fix

---
 src/app/publishapi/publishapi.component.ts | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/src/app/publishapi/publishapi.component.ts b/src/app/publishapi/publishapi.component.ts
index ce1088ca3..b86fee9fc 100644
--- a/src/app/publishapi/publishapi.component.ts
+++ b/src/app/publishapi/publishapi.component.ts
@@ -114,7 +114,6 @@ export class PublishApiComponent implements OnInit {
     this.openApi.info['x-catalog-id'] = catId;
     this.catalogSelect.selected = catId;
     this.onChangeRepository(catId);
-    this.type = this.getType(catId);
   }
 
   getTitleFromFdpApi(fdpApiResponse: FdpApiResponseItem[]): string {
@@ -175,9 +174,10 @@ export class PublishApiComponent implements OnInit {
   }
 
   downloadJson(): void {
+    let windowVar: any =  window.navigator;
     const newBlob = new Blob([this.openApiService.getPrettyJson(this.openApi)], { type: 'application/json' });
-    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
-      window.navigator.msSaveOrOpenBlob(newBlob);
+    if (windowVar && windowVar.msSaveOrOpenBlob) {
+      windowVar.msSaveOrOpenBlob(newBlob);
       return;
     }
     const data = window.URL.createObjectURL(newBlob);
@@ -268,7 +268,6 @@ export class PublishApiComponent implements OnInit {
       this.openApi = this.openApiService.getFromString(reader.result as string);
       this.openApi.cleanServers(servers[0].url);
       this.openApi.info['x-catalog-id'] = catId;
-      this.type = this.getType(catId)
     };
 
     reader.readAsText(jsonFile);
-- 
GitLab


From b62001ab894d435bdc37fc0a557279fca284a2a4 Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Fri, 22 Oct 2021 10:54:27 +0200
Subject: [PATCH 05/19] refactoring

---
 src/app/mapping/mapping.component.html | 44 +++++++++++++-------------
 src/app/mapping/mapping.component.scss |  2 +-
 src/app/mapping/mapping.component.ts   | 42 +++++++-----------------
 src/assets/geodcat.json                |  2 +-
 4 files changed, 35 insertions(+), 55 deletions(-)

diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html
index daa42ebf6..f95519c26 100644
--- a/src/app/mapping/mapping.component.html
+++ b/src/app/mapping/mapping.component.html
@@ -33,10 +33,10 @@
                                     <div class="col-3" style="margin-right: 10px;">
 
                                         <nb-form-field>
-                                            <input *ngIf="  dataset.uri !== 'dct:title'" nbInput fullWidth
-                                                type="text" value="{{dataset.uri}} " disabled />
-                                            <input *ngIf=" dataset.uri === 'dct:title' " nbInput fullWidth
-                                                type="text" value="{{dataset.uri}} *" disabled />
+                                            <input *ngIf="!isMandatory(dataset.card)" nbInput fullWidth
+                                                type="text" value="{{dataset.uri}} " disabled style="color: black;" />
+                                            <input *ngIf="isMandatory(dataset.card)" nbInput fullWidth
+                                                type="text" value="{{dataset.uri}} *" disabled style="color: black;" />
                                             <button nbSuffix nbTooltip="{{dataset.name}}: {{dataset.usageNote}}"
                                                 nbTooltipStatus="info" nbButton status="basic" ghost>
                                                 <nb-icon [icon]=" 'question-mark-circle-outline' " pack="eva">
@@ -49,17 +49,17 @@
 
                                         <nb-form-field>
                                             <input
-                                                *ngIf=" dataset.uri === 'dct:title' "
+                                                *ngIf="isMandatory(dataset.card)"
                                                 required   fullWidth
-                                                name=" {{index}}" nbInput
+                                                name=" data{{index}}" nbInput
                                                 (ngModelChange)="onModelChange($event)" [nbAutocomplete]="auto"
                                                 [(ngModel)]="selectedPaths[index]" 
                                                 (focus)="reset()"/>
                                            
                                             <input
-                                                *ngIf=" dataset.uri !== 'dct:title'"
+                                                *ngIf="!isMandatory(dataset.card)"
                                                   fullWidth
-                                                 name=" {{index}}" nbInput
+                                                 name=" data{{index}}" nbInput
                                                 (ngModelChange)="onModelChange($event)" [nbAutocomplete]="auto"
                                                 [(ngModel)]="selectedPaths[index]" 
                                                 (focus)="reset()"/>
@@ -74,7 +74,7 @@
                                             </nb-autocomplete>
                                         </nb-form-field>
                                     </div>
-                                    <div class="col-2" *ngIf="isMultiple(dataset.uri)"
+                                    <div class="col-2" *ngIf="isReplicable(dataset.card)"
                                         style="margin-left: 10px;">
                                         <button nbButton ghost (click)="addField(index)" *ngIf="!dataset.isDuplicated">
                                             <nb-icon icon="plus-outline" status="primary">
@@ -107,10 +107,10 @@
                                     <div class="col-3" style="margin-right: 10px;">
 
                                         <nb-form-field>
-                                            <input *ngIf="  distribution.uri !== 'dct:title'" nbInput fullWidth
-                                                type="text" value="{{distribution.uri}} " disabled />
-                                            <input *ngIf=" distribution.uri === 'dct:title' " nbInput fullWidth
-                                                type="text" value="{{distribution.uri}} *" disabled />
+                                            <input *ngIf="!isMandatory(distribution.card)" nbInput fullWidth
+                                                type="text" value="{{distribution.uri}} " disabled style="color: black;" />
+                                            <input *ngIf="isMandatory(distribution.card)" nbInput fullWidth
+                                                type="text" value="{{distribution.uri}} *" disabled style="color: black;" />
                                             <button nbSuffix nbTooltip="{{distribution.name}}: {{distribution.usageNote}}"
                                                 nbTooltipStatus="info" nbButton status="basic" ghost>
                                                 <nb-icon [icon]=" 'question-mark-circle-outline' " pack="eva">
@@ -123,19 +123,19 @@
 
                                         <nb-form-field>
                                             <input
-                                                *ngIf=" distribution.uri === 'dct:title' "
+                                                *ngIf="isMandatory(distribution.card)"
                                                 required   fullWidth
-                                                name=" {{index}}" nbInput
+                                                name=" distri{{index}}" nbInput
                                                 (ngModelChange)="onModelChange($event)" [nbAutocomplete]="auto"
-                                                [(ngModel)]="selectedPaths[index]" 
+                                                [(ngModel)]="distributionSelectedPaths[index]" 
                                                 (focus)="reset()"/>
                                            
                                             <input
-                                                *ngIf=" distribution.uri !== 'dct:title'"
+                                                *ngIf="!isMandatory(distribution.card)"
                                                   fullWidth
-                                                 name=" {{index}}" nbInput
+                                                 name=" distri{{index}}" nbInput
                                                 (ngModelChange)="onModelChange($event)" [nbAutocomplete]="auto"
-                                                [(ngModel)]="selectedPaths[index]" 
+                                                [(ngModel)]="distributionSelectedPaths[index]" 
                                                 (focus)="reset()"/>
 
                                             <nb-autocomplete #auto>
@@ -148,7 +148,7 @@
                                             </nb-autocomplete>
                                         </nb-form-field>
                                     </div>
-                                    <div class="col-2" *ngIf="isMultiple(distribution.uri)"
+                                    <div class="col-2" *ngIf="isReplicable(distribution.card)"
                                         style="margin-left: 10px;">
                                         <button nbButton ghost (click)="addField(index)" *ngIf="!distribution.isDuplicated">
                                             <nb-icon icon="plus-outline" status="primary">
@@ -195,12 +195,12 @@
                                             (ngModelChange)="mappedMetadatas[index].set(data.key, $event)" />
                                     </ng-template>
                                     <ng-container
-                                        *ngIf="isArray(data.value) && !isMultiple(dcatVocabulary[data.key].uri); else normal">
+                                        *ngIf="isArray(data.value) && !isReplicable(dcatVocabulary[data.key].card); else normal">
                                         <input nbInput [ngModel]="data.value[0]"
                                             (ngModelChange)="mappedMetadatas[index].set(data.key, $event)" />
                                     </ng-container>
                                     <ng-container
-                                        *ngIf="isArray(data.value) && isMultiple(dcatVocabulary[data.key].uri)">
+                                        *ngIf="isArray(data.value) && isReplicable(dcatVocabulary[data.key].card)">
                                         <ul *ngFor="let val of data.value" style="margin-left: -100px;">
                                             <li>
                                                 <div class="row">
diff --git a/src/app/mapping/mapping.component.scss b/src/app/mapping/mapping.component.scss
index 68382b729..48e53e376 100644
--- a/src/app/mapping/mapping.component.scss
+++ b/src/app/mapping/mapping.component.scss
@@ -17,7 +17,7 @@
     margin: 10px 10px;
     
   }
-  input:disabled{
+  .inputDisabled{
     color: black
   }
   
diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts
index 3a43bd014..866aaf2cd 100644
--- a/src/app/mapping/mapping.component.ts
+++ b/src/app/mapping/mapping.component.ts
@@ -138,7 +138,7 @@ export class MappingComponent implements OnInit {
         }
 
         if (Array.isArray(value)) {
-          if (this.isMultiple(key)) {
+          if (this.isReplicable(this.getCard(key))) {
             value.forEach(v => {
               properties += this.writeRdf(key, v);
             })
@@ -499,29 +499,6 @@ export class MappingComponent implements OnInit {
     console.table(this.selectedPaths)
   }
 
-
-  isMultiple(vocabulary: string): boolean {
-    let bool: boolean = true;
-    switch (vocabulary) {
-      case "dct:isPartOf":
-        bool = false;
-        break;
-      case "dcat:landingPage":
-        bool = false;
-        break;
-      case "dcat:contactPoint":
-        bool = false;
-        break;
-      case "dct:title":
-        bool = false;
-        break;
-      default:
-        bool = true;
-        break;
-    }
-    return bool;
-  }
-
   // to delete a property of dcat dataset mapped
   deleteProperty(key: number) {
     this.mappedMetadatas[this.index].delete(key);
@@ -553,15 +530,18 @@ export class MappingComponent implements OnInit {
   toggle(checked: boolean) {
     this.default = checked;
   }
-}
-
-
-
-
 
+  isMandatory(card: string): boolean {
+    return card.startsWith("1");
+  }
 
+  isReplicable(card: string): boolean {
+    return card.endsWith("n");
+  }
 
-function addField(index: any, number: any) {
-  throw new Error('Function not implemented.');
+  getCard(uri:string): string {
+    return this.vocabularies.filter((vocabulary: Property) => vocabulary.uri === uri).map((vocabulary: Property) => vocabulary.card).pop();
+  }
 }
 
+
diff --git a/src/assets/geodcat.json b/src/assets/geodcat.json
index 2a4d0774f..b1138eb3e 100644
--- a/src/assets/geodcat.json
+++ b/src/assets/geodcat.json
@@ -10,7 +10,7 @@
         "property": "has Version",
         "uri": "dct:hasVersion",
         "usageNote": "Optional property.This property refers to a related Dataset that is a version, edition, or adaptation of the described Dataset.",
-        "card": "1..n",
+        "card": "0..n",
         "geodcat": false
     },
     {
-- 
GitLab


From 2451f67d5c28a0c45c975a51ec62830daa3bb0db Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Fri, 22 Oct 2021 14:05:24 +0200
Subject: [PATCH 06/19] bug fix

---
 src/app/datasets/datasets.component.html | 2 +-
 src/app/mapping/mapping.component.ts     | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/app/datasets/datasets.component.html b/src/app/datasets/datasets.component.html
index 60124271d..5fdfcf3a1 100644
--- a/src/app/datasets/datasets.component.html
+++ b/src/app/datasets/datasets.component.html
@@ -41,7 +41,7 @@
               <ng-template #preview>
                 <ng-container *ngIf="request.tags != null && request.tags.length > 0">
                   <pre *ngIf="request.tags[0] === tagEnum.dataset && openApi.info['x-result'] === 'xml' ">{{ previews.get(path.pathName)  }}</pre>
-                  <pre *ngIf="request.tags[0] === tagEnum.dataset && openApi.info['x-result'] === 'json' ">{{ previews.get(path.pathName) | json }}</pre>
+                  <pre *ngIf="request.tags[0] === tagEnum.dataset && openApi.info['x-result'] !== 'xml' ">{{ previews.get(path.pathName) | json }}</pre>
                   <ul *ngIf="request.tags[0] === tagEnum.search">
                     <li *ngFor="let datasetId of previews.get(path.pathName)">{{datasetId}}</li>
                   </ul>
diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts
index 866aaf2cd..ced38a3e2 100644
--- a/src/app/mapping/mapping.component.ts
+++ b/src/app/mapping/mapping.component.ts
@@ -109,7 +109,6 @@ export class MappingComponent implements OnInit {
 
 
   createDataset(item: Object): Map<number, string> {
-    console.log("rerereer" + this.selectedPaths)
     let mappedMetadata: Map<number, string> = new Map()
     for (let i = 0; i < this.selectedPaths.length; i++) {
       if (this.selectedPaths[i]) {
-- 
GitLab


From ffc63210f3641723a479e16bf9e9f227be913374 Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Fri, 22 Oct 2021 14:57:34 +0200
Subject: [PATCH 07/19] bug fixes and distributions items retrieving

---
 src/app/mapping/mapping.component.html | 240 +++++++++++++++----------
 src/app/mapping/mapping.component.ts   |  51 +++---
 2 files changed, 170 insertions(+), 121 deletions(-)

diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html
index f95519c26..8a188dfd9 100644
--- a/src/app/mapping/mapping.component.html
+++ b/src/app/mapping/mapping.component.html
@@ -13,7 +13,7 @@
         <div class="card-row">
             <div class="card-col">
                 <nb-card size="giant">
-                    <nb-card-header>Dataset metadata</nb-card-header>
+                    <nb-card-header>Dataset</nb-card-header>
                     <nb-card-body>
                         <div class="row">
                             <p>Upload Or fill out the form with the path corresponding to the dcat property and save a
@@ -25,18 +25,17 @@
                             <input type="file" id="file" (change)="importJson($event)" accept=".json" />
                         </div>
 
-                        <ng-container
-                            *ngFor="let dataset of dcatVocabulary ; let index = index">
+                        <ng-container *ngFor="let dataset of dcatVocabulary ; let index = index">
                             <nb-form-field>
                                 <div class="row">
 
                                     <div class="col-3" style="margin-right: 10px;">
 
                                         <nb-form-field>
-                                            <input *ngIf="!isMandatory(dataset.card)" nbInput fullWidth
-                                                type="text" value="{{dataset.uri}} " disabled style="color: black;" />
-                                            <input *ngIf="isMandatory(dataset.card)" nbInput fullWidth
-                                                type="text" value="{{dataset.uri}} *" disabled style="color: black;" />
+                                            <input *ngIf="!isMandatory(dataset.card)" nbInput fullWidth type="text"
+                                                value="{{dataset.uri}} " disabled style="color: black;" />
+                                            <input *ngIf="isMandatory(dataset.card)" nbInput fullWidth type="text"
+                                                value="{{dataset.uri}} *" disabled style="color: black;" />
                                             <button nbSuffix nbTooltip="{{dataset.name}}: {{dataset.usageNote}}"
                                                 nbTooltipStatus="info" nbButton status="basic" ghost>
                                                 <nb-icon [icon]=" 'question-mark-circle-outline' " pack="eva">
@@ -48,21 +47,14 @@
                                     <div class="col-7">
 
                                         <nb-form-field>
-                                            <input
-                                                *ngIf="isMandatory(dataset.card)"
-                                                required   fullWidth
-                                                name=" data{{index}}" nbInput
-                                                (ngModelChange)="onModelChange($event)" [nbAutocomplete]="auto"
-                                                [(ngModel)]="selectedPaths[index]" 
-                                                (focus)="reset()"/>
-                                           
-                                            <input
-                                                *ngIf="!isMandatory(dataset.card)"
-                                                  fullWidth
-                                                 name=" data{{index}}" nbInput
-                                                (ngModelChange)="onModelChange($event)" [nbAutocomplete]="auto"
-                                                [(ngModel)]="selectedPaths[index]" 
-                                                (focus)="reset()"/>
+                                            <input *ngIf="isMandatory(dataset.card)" required fullWidth
+                                                name=" data{{index}}" nbInput (ngModelChange)="onModelChange($event)"
+                                                [nbAutocomplete]="auto" [(ngModel)]="selectedPaths[index]"
+                                                (focus)="reset()" />
+
+                                            <input *ngIf="!isMandatory(dataset.card)" fullWidth name=" data{{index}}"
+                                                nbInput (ngModelChange)="onModelChange($event)" [nbAutocomplete]="auto"
+                                                [(ngModel)]="selectedPaths[index]" (focus)="reset()" />
 
                                             <nb-autocomplete #auto>
 
@@ -74,8 +66,7 @@
                                             </nb-autocomplete>
                                         </nb-form-field>
                                     </div>
-                                    <div class="col-2" *ngIf="isReplicable(dataset.card)"
-                                        style="margin-left: 10px;">
+                                    <div class="col-2" *ngIf="isReplicable(dataset.card)" style="margin-left: 10px;">
                                         <button nbButton ghost (click)="addField(index)" *ngIf="!dataset.isDuplicated">
                                             <nb-icon icon="plus-outline" status="primary">
                                             </nb-icon>
@@ -97,21 +88,21 @@
         <div class="card-row">
             <div class="card-col">
                 <nb-card size="giant">
-                    <nb-card-header>Dataset metadata</nb-card-header>
+                    <nb-card-header>Distribution</nb-card-header>
                     <nb-card-body>
-                        <ng-container
-                            *ngFor="let distribution of distributions ; let index = index">
+                        <ng-container *ngFor="let distribution of distributions ; let index = index">
                             <nb-form-field>
                                 <div class="row">
 
                                     <div class="col-3" style="margin-right: 10px;">
 
                                         <nb-form-field>
-                                            <input *ngIf="!isMandatory(distribution.card)" nbInput fullWidth
-                                                type="text" value="{{distribution.uri}} " disabled style="color: black;" />
-                                            <input *ngIf="isMandatory(distribution.card)" nbInput fullWidth
-                                                type="text" value="{{distribution.uri}} *" disabled style="color: black;" />
-                                            <button nbSuffix nbTooltip="{{distribution.name}}: {{distribution.usageNote}}"
+                                            <input *ngIf="!isMandatory(distribution.card)" nbInput fullWidth type="text"
+                                                value="{{distribution.uri}} " disabled style="color: black;" />
+                                            <input *ngIf="isMandatory(distribution.card)" nbInput fullWidth type="text"
+                                                value="{{distribution.uri}} *" disabled style="color: black;" />
+                                            <button nbSuffix
+                                                nbTooltip="{{distribution.name}}: {{distribution.usageNote}}"
                                                 nbTooltipStatus="info" nbButton status="basic" ghost>
                                                 <nb-icon [icon]=" 'question-mark-circle-outline' " pack="eva">
                                                 </nb-icon>
@@ -122,21 +113,15 @@
                                     <div class="col-7">
 
                                         <nb-form-field>
-                                            <input
-                                                *ngIf="isMandatory(distribution.card)"
-                                                required   fullWidth
-                                                name=" distri{{index}}" nbInput
-                                                (ngModelChange)="onModelChange($event)" [nbAutocomplete]="auto"
-                                                [(ngModel)]="distributionSelectedPaths[index]" 
-                                                (focus)="reset()"/>
-                                           
-                                            <input
-                                                *ngIf="!isMandatory(distribution.card)"
-                                                  fullWidth
-                                                 name=" distri{{index}}" nbInput
-                                                (ngModelChange)="onModelChange($event)" [nbAutocomplete]="auto"
-                                                [(ngModel)]="distributionSelectedPaths[index]" 
-                                                (focus)="reset()"/>
+                                            <input *ngIf="isMandatory(distribution.card)" required fullWidth
+                                                name=" distri{{index}}" nbInput (ngModelChange)="onModelChange($event)"
+                                                [nbAutocomplete]="auto" [(ngModel)]="distributionSelectedPaths[index]"
+                                                (focus)="reset()" />
+
+                                            <input *ngIf="!isMandatory(distribution.card)" fullWidth
+                                                name=" distri{{index}}" nbInput (ngModelChange)="onModelChange($event)"
+                                                [nbAutocomplete]="auto" [(ngModel)]="distributionSelectedPaths[index]"
+                                                (focus)="reset()" />
 
                                             <nb-autocomplete #auto>
 
@@ -150,7 +135,8 @@
                                     </div>
                                     <div class="col-2" *ngIf="isReplicable(distribution.card)"
                                         style="margin-left: 10px;">
-                                        <button nbButton ghost (click)="addField(index)" *ngIf="!distribution.isDuplicated">
+                                        <button nbButton ghost (click)="addField(index)"
+                                            *ngIf="!distribution.isDuplicated">
                                             <nb-icon icon="plus-outline" status="primary">
                                             </nb-icon>
                                         </button>
@@ -172,69 +158,127 @@
             <button class="button-center" nbButton status="primary" (click)="downloadJson()">Save locally</button>
         </div>
         <div class="row">
-            <button class="button-center" nbButton status="primary" (click)="mapDataset()"
+            <button class="button-center" nbButton status="primary" (click)="mapDataset(); check = true"
                 [disabled]="!form.valid">Check
                 mapping</button>
         </div>
     </form>
-    <div class="card-row">
+    <div class="card-row" *ngIf="check">
         <div class="card-col">
             <nb-card [nbSpinner]="loadingCr" nbSpinnerStatus="primary" nbSpinnerSize="giant" nbSpinnerMessage="loading">
-                <nb-card-header>Map</nb-card-header>
+
                 <nb-card-body>
-                    <nb-list>
+                    <nb-card>
+                        <nb-card-header>Dataset</nb-card-header>
 
-                        <nb-list-item *ngFor="let data of mappedMetadatas[index] | keyvalue; trackBy:trackByIndex; ">
-                            <div class="row">
-                                <div class="col-3"><label
-                                        for="{{data.key}}">{{dcatVocabulary[data.key].uri}}</label>
-                                </div>
-                                <div class="col-7">
-                                    <ng-template #normal>
-                                        <input nbInput [ngModel]="data.value"
-                                            (ngModelChange)="mappedMetadatas[index].set(data.key, $event)" />
-                                    </ng-template>
-                                    <ng-container
-                                        *ngIf="isArray(data.value) && !isReplicable(dcatVocabulary[data.key].card); else normal">
-                                        <input nbInput [ngModel]="data.value[0]"
-                                            (ngModelChange)="mappedMetadatas[index].set(data.key, $event)" />
-                                    </ng-container>
-                                    <ng-container
-                                        *ngIf="isArray(data.value) && isReplicable(dcatVocabulary[data.key].card)">
-                                        <ul *ngFor="let val of data.value" style="margin-left: -100px;">
-                                            <li>
-                                                <div class="row">
-                                                    <div class="col-3">
-                                                        <label
-                                                            for="{{data.key}}">{{dcatVocabulary[data.key].uri}}</label>
-                                                    </div>
-                                                    <div class="col-7">
-                                                        <input nbInput [ngModel]="val"
-                                                            (ngModelChange)="mappedMetadatas[index].set(data.key, $event)" />
+                        <nb-list>
+                            <nb-list-item
+                                *ngFor="let data of datasetMappedMetadatas[index] | keyvalue; trackBy:trackByIndex; ">
+                                <div class="row">
+                                    <div class="col-3"><label
+                                            for="{{data.key}}">{{dcatVocabulary[data.key].uri}}</label>
+                                    </div>
+                                    <div class="col-7">
+                                        <ng-template #normal>
+                                            <input nbInput [ngModel]="data.value"
+                                                (ngModelChange)="datasetMappedMetadatas[index].set(data.key, $event)" />
+                                        </ng-template>
+                                        <ng-container
+                                            *ngIf="isArray(data.value) && !isReplicable(dcatVocabulary[data.key].card); else normal">
+                                            <input nbInput [ngModel]="data.value[0]"
+                                                (ngModelChange)="datasetMappedMetadatas[index].set(data.key, $event)" />
+                                        </ng-container>
+                                        <ng-container
+                                            *ngIf="isArray(data.value) && isReplicable(dcatVocabulary[data.key].card)">
+                                            <ul *ngFor="let val of data.value" style="margin-left: -100px;">
+                                                <li>
+                                                    <div class="row">
+                                                        <div class="col-3">
+                                                            <label
+                                                                for="{{data.key}}">{{dcatVocabulary[data.key].uri}}</label>
+                                                        </div>
+                                                        <div class="col-7">
+                                                            <input nbInput [ngModel]="val"
+                                                                (ngModelChange)="datasetMappedMetadatas[index].set(data.key, $event)" />
+                                                        </div>
+                                                        <div class="col-2">
+
+                                                        </div>
                                                     </div>
-                                                    <div class="col-2">
+                                                </li>
+                                            </ul>
+                                        </ng-container>
+
+                                    </div>
+                                    <div class="col-2">
+                                        <button nbButton ghost>
+                                            <nb-icon icon="trash-2-outline" status="danger"
+                                                (click)="deleteProperty(data.key)">
+                                            </nb-icon>
+                                        </button>
+                                    </div>
+                                </div>
+                            </nb-list-item>
 
+                        </nb-list>
+                    </nb-card>
+                    <nb-card>
+                        <nb-card-header>Distribution</nb-card-header>
+
+                        <nb-list>
+                            <nb-list-item
+                                *ngFor="let data of distributionMappedMetadatas[index] | keyvalue; trackBy:trackByIndex; ">
+                                <div class="row">
+                                    <div class="col-3"><label
+                                            for="{{data.key}}">{{distributions[data.key].uri}}</label>
+                                    </div>
+                                    <div class="col-7">
+                                        <ng-template #normal>
+                                            <input nbInput [ngModel]="data.value"
+                                                (ngModelChange)="distributionMappedMetadatas[index].set(data.key, $event)" />
+                                        </ng-template>
+                                        <ng-container
+                                            *ngIf="isArray(data.value) && !isReplicable(distributions[data.key].card); else normal">
+                                            <input nbInput [ngModel]="data.value[0]"
+                                                (ngModelChange)="distributionMappedMetadatas[index].set(data.key, $event)" />
+                                        </ng-container>
+                                        <ng-container
+                                            *ngIf="isArray(data.value) && isReplicable(distributions[data.key].card)">
+                                            <ul *ngFor="let val of data.value" style="margin-left: -100px;">
+                                                <li>
+                                                    <div class="row">
+                                                        <div class="col-3">
+                                                            <label
+                                                                for="{{data.key}}">{{distributions[data.key].uri}}</label>
+                                                        </div>
+                                                        <div class="col-7">
+                                                            <input nbInput [ngModel]="val"
+                                                                (ngModelChange)="distributionMappedMetadatas[index].set(data.key, $event)" />
+                                                        </div>
+                                                        <div class="col-2">
+
+                                                        </div>
                                                     </div>
-                                                </div>
-                                            </li>
-                                        </ul>
-                                    </ng-container>
+                                                </li>
+                                            </ul>
+                                        </ng-container>
 
+                                    </div>
+                                    <div class="col-2">
+                                        <button nbButton ghost>
+                                            <nb-icon icon="trash-2-outline" status="danger"
+                                                (click)="deleteProperty(data.key)">
+                                            </nb-icon>
+                                        </button>
+                                    </div>
                                 </div>
-                                <div class="col-2">
-                                    <button nbButton ghost>
-                                        <nb-icon icon="trash-2-outline" status="danger"
-                                            (click)="deleteProperty(data.key)">
-                                        </nb-icon>
-                                    </button>
-                                </div>
-                            </div>
-                        </nb-list-item>
+                            </nb-list-item>
 
-                    </nb-list>
+                        </nb-list>
+                    </nb-card>
                     <div class="row">
                         <button class="button-center" nbButton status="danger" *ngIf=" !first "
-                            (click)="mappedMetadatas.splice(index, 1); prev()">Delete datset<nb-icon
+                            (click)="distributionMappedMetadatas.splice(index, 1); prev()">Delete datset<nb-icon
                                 icon="trash-2-outline">
                             </nb-icon></button>
                     </div>
@@ -247,7 +291,7 @@
 
                         <div *ngIf="!first ">
                             <button nbButton (click)=" next()"
-                                [disabled]="index == mappedMetadatas.length -1">next</button>
+                                [disabled]="index == itemsdataset.length -1">next</button>
                         </div>
 
                     </div>
@@ -288,7 +332,7 @@
                 </div>
 
                 <div>
-                    <button nbButton (click)=" next()" [disabled]="index == mappedMetadatas.length -1"
+                    <button nbButton (click)=" next()" [disabled]="index == datasetMappedMetadatas.length -1"
                         [disabled]="index == itemsdataset.length -1 ">next</button>
                 </div>
 
@@ -303,4 +347,4 @@
         </nb-card-footer>
     </nb-card>
 
-</ng-template>
+</ng-template>
\ No newline at end of file
diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts
index ced38a3e2..550c2fbee 100644
--- a/src/app/mapping/mapping.component.ts
+++ b/src/app/mapping/mapping.component.ts
@@ -23,7 +23,8 @@ import { FeedbackDialogComponent } from './dialog/feedback-dialog/feedback-dialo
 })
 export class MappingComponent implements OnInit {
 
-  distributions: Distribution[] = [];
+  check = false;
+  distributions: Property[] = [];
   ontology: string;
   urls: any[] = [];  
   itemsdataset: any[] = []
@@ -33,7 +34,8 @@ export class MappingComponent implements OnInit {
   keys: string[] = [];
   selectedPaths: string[];
   distributionSelectedPaths: string[];
-  mappedMetadatas: Map<number, string>[] = [];
+  datasetMappedMetadatas: Map<number, string>[] = [];
+  distributionMappedMetadatas: Map<number, string>[] = [];
   DatasetToPublish: Map<string, string>[];
   index: number = 0
   first: boolean = true;
@@ -56,7 +58,7 @@ export class MappingComponent implements OnInit {
       console.log(this.itemsdataset)
       this.ids = this.dataSetService.ids;
       this.keys = [];
-      this.type == "Dataverse" ? this.getKeysFromMetadataDataverse(this.itemsdataset[0], '') : this.getKeysFromMetadataCustom(this.itemsdataset[0], '');
+      this.type == "Dataverse" ? this.getKeysFromMetadataCustom(this.itemsdataset[0], '') : this.getKeysFromMetadataCustom(this.itemsdataset[0], '');
       this.keys = Array.from(new Set(this.keys));
       this.filteredOptions = of(this.keys);
     } else {
@@ -67,24 +69,24 @@ export class MappingComponent implements OnInit {
   }
 
   selectOntology(): void {
-    this.dataSetService.getLocally(`./assets/geodcat.json`).subscribe(
+       this.dataSetService.getLocally(`./assets/geodcat.json`).subscribe(
       datasets => {
         this.dcatVocabulary = this.ontology === "dcat" ? datasets.filter(d => !d.geodcat) : datasets;
         this.vocabularies = this.ontology === "dcat" ? datasets.filter(d => !d.geodcat) : datasets;;
         this.selectedPaths = [];
-        
+        this.dataSetService.getLocally('./assets/distribution.json').subscribe(
+          (distributions: Distribution[]) => {
+            this.distributions = this.ontology === "dcat" ? distributions.filter(d => !d.geodcat) : distributions;
+            this.vocabularies = this.vocabularies.concat(this.ontology === "dcat" ? distributions.filter(d => !d.geodcat) : distributions);
+            this.distributionSelectedPaths = [];
+          }
+        );
       },
       error => {
         console.error(error);
       },
     );
-    this.dataSetService.getLocally('./assets/distribution.json').subscribe(
-      (distributions: Distribution[]) => {
-        this.distributions = this.ontology === "dcat" ? distributions.filter(d => !d.geodcat) : distributions;
-        this.vocabularies = this.vocabularies.concat(this.ontology === "dcat" ? distributions.filter(d => !d.geodcat) : distributions);
-        this.distributionSelectedPaths = [];
-      }
-    );
+    
 }
 
 
@@ -108,12 +110,13 @@ export class MappingComponent implements OnInit {
   }
 
 
-  createDataset(item: Object): Map<number, string> {
+  createDataset(item: Object, classDcat: string): Map<number, string> {
     let mappedMetadata: Map<number, string> = new Map()
-    for (let i = 0; i < this.selectedPaths.length; i++) {
-      if (this.selectedPaths[i]) {
-        let tab = this.selectedPaths[i].split(' : ');
-        this.type == "Dataverse" ? mappedMetadata.set(i, this.getValueDataverse(tab, item)) : mappedMetadata.set(i, this.getValueCustom(tab, item));
+    const array: string[] = (classDcat === "dataset") ? this.selectedPaths : this.distributionSelectedPaths
+    for (let i = 0; i < array.length; i++) {
+      if (array[i]) {
+        let tab = array[i].split(' : ') ;
+        this.type == "Dataverse" ? mappedMetadata.set(i, this.getValueCustom(tab, item)) : mappedMetadata.set(i, this.getValueCustom(tab, item));
       }
     }
     this.loadingCr = false;
@@ -128,9 +131,9 @@ export class MappingComponent implements OnInit {
     let notPostedDatasets = [];
     this.loading = true;
     const requestPromises: Promise<any>[] = [];
-    for (let i = 0; i < this.mappedMetadatas.length; i++) {
+    for (let i = 0; i < this.datasetMappedMetadatas.length; i++) {
       properties = "";
-      this.mappedMetadatas[i].forEach((value: string, index: number) => {
+      this.datasetMappedMetadatas[i].forEach((value: string, index: number) => {
         let key = this.dcatVocabulary[index].uri;
         if (key === 'dct:hasVersion') {
           version = true;
@@ -420,11 +423,13 @@ export class MappingComponent implements OnInit {
 
   mapDataset() {
     this.loadingCr = true;
-    this.mappedMetadatas = [];
+    this.datasetMappedMetadatas = [];
     this.itemsdataset.forEach((dataset: Object) => {
-      this.mappedMetadatas.push(this.createDataset(dataset));
+      this.datasetMappedMetadatas.push(this.createDataset(dataset, "dataset"));
+      this.distributionMappedMetadatas.push(this.createDataset(dataset, "distribution"))
     })
-    console.log(this.mappedMetadatas);
+    console.log(this.datasetMappedMetadatas);
+    console.log(this.distributionMappedMetadatas);
     this.first = false;
   }
   next() {
@@ -500,7 +505,7 @@ export class MappingComponent implements OnInit {
 
   // to delete a property of dcat dataset mapped
   deleteProperty(key: number) {
-    this.mappedMetadatas[this.index].delete(key);
+    this.datasetMappedMetadatas[this.index].delete(key);
   }
   
   trackByIndex(index: number): any {
-- 
GitLab


From a8394894d4f1e68722b2d8f6832e7700adc531a4 Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Fri, 22 Oct 2021 15:58:51 +0200
Subject: [PATCH 08/19] change methode to retrieve catId

---
 src/app/repository/services/publish-repository.service.ts | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/app/repository/services/publish-repository.service.ts b/src/app/repository/services/publish-repository.service.ts
index 5677cf78b..f562c25da 100644
--- a/src/app/repository/services/publish-repository.service.ts
+++ b/src/app/repository/services/publish-repository.service.ts
@@ -41,9 +41,9 @@ export class PublishRepositoryService {
       const myRequest = new Request(FDP_URL + "/catalog", myInit);
 
       const response = await fetch(myRequest, myInit);
-      const responseText = await response.text();
-
-      const catId = responseText.substring(38, 74);
+      const id = await response.headers.get("location");
+      
+      const catId = id.substring(id.search("catalog/") + 8, id.length);
       console.log('catalog creaetd with fdp / id = ' + catId);
       return this.addUserCatalog(catId);
     }
-- 
GitLab


From aee506bf735fd8d4d91e0b8e28aac3ee311e19ef Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Thu, 28 Oct 2021 10:04:35 +0200
Subject: [PATCH 09/19] feature distribution create an publish to fdp

---
 .../datasets/services/dataset-crud.service.ts |   8 +-
 src/app/mapping/mapping.component.ts          | 153 +++++++++++-------
 src/assets/distribution.json                  |  49 +++---
 src/assets/geodcat.json                       |   2 +-
 4 files changed, 121 insertions(+), 91 deletions(-)

diff --git a/src/app/datasets/services/dataset-crud.service.ts b/src/app/datasets/services/dataset-crud.service.ts
index 70b4b6747..5501eeb68 100644
--- a/src/app/datasets/services/dataset-crud.service.ts
+++ b/src/app/datasets/services/dataset-crud.service.ts
@@ -78,6 +78,7 @@ export class DatasetCrudService {
     }
   }
 
+
   draftDataset(url: string) {
     if (this.fds2Token) {
       const httpOptions = {
@@ -104,7 +105,7 @@ export class DatasetCrudService {
     }
   }
 
-  createDistribution(data: string) {
+  createDistribution(data: string): Observable<Object> {
 
     if (this.fds2Token) {
       const httpOptions = {
@@ -115,10 +116,7 @@ export class DatasetCrudService {
         })
       };
 
-      const resultat = this.http.post(FDP_URL + '/distribution', data, httpOptions).subscribe((r) => {
-        console.log('reponse: ', r);
-        return JSON.stringify(resultat);
-      });
+      return this.http.post(FDP_URL + '/distribution', data, httpOptions);
     }
   }
 
diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts
index 550c2fbee..b3171ab9c 100644
--- a/src/app/mapping/mapping.component.ts
+++ b/src/app/mapping/mapping.component.ts
@@ -23,6 +23,7 @@ import { FeedbackDialogComponent } from './dialog/feedback-dialog/feedback-dialo
 })
 export class MappingComponent implements OnInit {
 
+
   check = false;
   distributions: Property[] = [];
   ontology: string;
@@ -123,60 +124,18 @@ export class MappingComponent implements OnInit {
     return mappedMetadata;
   }
 
-  publishDataset() {
-    let version = false;
+  publishDataset(): void {
+    let properties = ""
     let data: string = '';
-    let properties: string = '';
     let postedDatastes = [];
     let notPostedDatasets = [];
     this.loading = true;
     const requestPromises: Promise<any>[] = [];
     for (let i = 0; i < this.datasetMappedMetadatas.length; i++) {
-      properties = "";
-      this.datasetMappedMetadatas[i].forEach((value: string, index: number) => {
-        let key = this.dcatVocabulary[index].uri;
-        if (key === 'dct:hasVersion') {
-          version = true;
-        }
-
-        if (Array.isArray(value)) {
-          if (this.isReplicable(this.getCard(key))) {
-            value.forEach(v => {
-              properties += this.writeRdf(key, v);
-            })
-          } else {
-            properties += this.writeRdf(key, value[0]);
-          }
-        } else {
-          properties += this.writeRdf(key, value);
-        }
-
-      })
-
-      if (!version) properties += "dct:hasVersion \"undefined\";\n";
-      data = '\@prefix dcat: <http://www.w3.org/ns/dcat#>.\n\
-               @prefix dct: <http://purl.org/dc/terms/>.\n\
-               @prefix adms: <http://www.w3.org/ns/adms#> .\n\
-               @prefix dqv:  <http://www.w3.org/ns/dqv#> .\n\
-               @prefix geodcat: <http://data.europa.eu/930/>.\n\
-               @prefix prov: <http://www.w3.org/ns/prov#>. \n\
-               @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>. \n\
-               @prefix language: <http://id.loc.gov/vocabulary/iso639-1/>.\n\
-               @prefix s: <'+ this.FDP_URL + '/>.\n\
-               @prefix c: <'+ this.FDP_URL + '/catalog/>.\n\
-               \n\
-               s:new\n\
-               a dcat:Dataset, dcat:Resource;\n\
-               dct:isPartOf c:'+ this.catalogId + ';\n' + properties + '.';
-
-      /*let query = 'query=PREFIX dcat: <http://www.w3.org/ns/dcat#>\n\
-               PREFIX dct: <http://purl.org/dc/terms/>\n\
-               SELECT ?dataset\n\
-               where {\n\
-                      ?dataset a dcat:Dataset;\n\
-                      dct:title "' + title + '" ;\n\
-                      dct:isPartOf <https://f2ds.eosc-pillar.eu/catalog/' + this.catalogId + '>. } '*/
-
+      
+      properties = this.buildRDF(this.dcatVocabulary, this.datasetMappedMetadatas, i);
+      
+      data = this.getDatasetEmpty(properties);
 
       let requestPromise = this.dataSetService.createDataset(data).then((resp: HttpResponse<any>) => {
         if (resp.status.toString().startsWith('2')) {
@@ -184,6 +143,14 @@ export class MappingComponent implements OnInit {
         } else {
           notPostedDatasets.push(this.ids[i]);
         }
+        
+        const location = resp.headers.get("location");
+        const datasetId = location.substring(location.search("dataset/") + 8, location.length);
+
+        const properties = this.buildRDF(this.distributions, this.distributionMappedMetadatas, i)
+        const distribution = this.getDistributionEmpty(properties, datasetId)
+        console.log(datasetId);
+        this.dataSetService.createDistribution(distribution).subscribe();
       })
       requestPromises.push(requestPromise);
     }
@@ -199,6 +166,36 @@ export class MappingComponent implements OnInit {
     })
   }
 
+  buildRDF(vocabularies: Property[], array: Map<number, string>[], i: number): string {
+      let properties = "";
+      let version = false;
+      array[i].forEach((value: string, key: number) => {
+        let uri = vocabularies[key].uri;
+        if (uri === 'dct:hasVersion') {
+          version = true;
+        }
+
+        if (Array.isArray(value)) {
+          console.log(`${uri} => ${value}`);
+          if (this.isReplicable(this.getCard(uri))) {
+            value.forEach(v => {
+              console.log(`${uri} => ${v}`);
+              properties += this.writeRdf(uri, v);
+            })
+          } else {
+            properties += this.writeRdf(uri, value[0]);
+          }
+        } else {
+          properties += this.writeRdf(uri, value);
+        }
+
+      })
+
+      if (!version) properties += `dct:hasVersion "undefined";\n`;
+
+      return properties;
+  }
+
   publishDatasetFromGeodcatApi() {
     let postedDatastes = [];
     let notPostedDatasets = [];
@@ -232,30 +229,23 @@ export class MappingComponent implements OnInit {
 
   private writeRdf(key: string, value: string): string {
     let properties = "";
-    (value && typeof value === "string") ? value = this.replaceAll(value, '\n', '') : value;
+    value = (value && typeof value === "string") ? value.replace(/\n/g, '') : value;
 
     switch (key) {
       case 'dcat:landingPage':
-        properties += key + ' <' + value + '>;\n';
-        break;
       case 'dcat:theme':
-        properties += key + ' <' + value + '>;\n';
-        break;
       case 'dcat:contactPoint':
-        properties += key + ' <' + value + '>;\n';
-        break;
+      case 'dcat:accessURL':
+      case 'dcat:downloadURL':
       case 'dct:language':
         properties += key + ' <' + value + '>;\n';
         break;
       case 'dct:issued':
-        properties += key + ' "' + value + '"^^xsd:dateTime;\n';
-        break;
       case 'dct:modified':
         properties += key + ' "' + value + '"^^xsd:dateTime;\n';
         break;
       default:
-        properties += key + ' "' + value + '";\n';
-        break;
+        properties += key + ' "' + value + '";\n'; break;
     }
     return properties;
   }
@@ -428,7 +418,7 @@ export class MappingComponent implements OnInit {
       this.datasetMappedMetadatas.push(this.createDataset(dataset, "dataset"));
       this.distributionMappedMetadatas.push(this.createDataset(dataset, "distribution"))
     })
-    console.log(this.datasetMappedMetadatas);
+    console.table(this.datasetMappedMetadatas);
     console.log(this.distributionMappedMetadatas);
     this.first = false;
   }
@@ -544,7 +534,48 @@ export class MappingComponent implements OnInit {
   }
 
   getCard(uri:string): string {
-    return this.vocabularies.filter((vocabulary: Property) => vocabulary.uri === uri).map((vocabulary: Property) => vocabulary.card).pop();
+    return this.vocabularies.find((vocabulary: Property) => vocabulary.uri === uri).card;
+  }
+
+  private getDistributionEmpty(properties: string, datasetId: string): string {
+    return `@prefix dcat: <http://www.w3.org/ns/dcat#>.
+    @prefix dct: <http://purl.org/dc/terms/>.
+    @prefix adms: <http://www.w3.org/ns/adms#> .
+    @prefix dqv:  <http://www.w3.org/ns/dqv#> .
+    @prefix geodcat: <http://data.europa.eu/930/>.
+    @prefix prov: <http://www.w3.org/ns/prov#>. 
+    @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>. 
+    @prefix skos: <http://www.w3.org/2004/02/skos/core#>. 
+    @prefix spdx:  <http://spdx.org/rdf/terms#>. 
+    @prefix foaf: <http://xmlns.com/foaf/0.1/>. 
+    @prefix odrl: <http://www.w3.org/ns/odrl/2/>. 
+    @prefix cnt:   <http://www.w3.org/2011/content#>.
+    @prefix language: <http://id.loc.gov/vocabulary/iso639-1/>.
+    @prefix s: <${this.FDP_URL}/>.
+    @prefix c: <${this.FDP_URL}/dataset/>.
+    
+    s:new
+    a dcat:Distribution, dcat:Resource;
+    dct:isPartOf c:${datasetId};
+    ${properties}.`;
+  }
+
+  private getDatasetEmpty(properties: string): string {
+    return `@prefix dcat: <http://www.w3.org/ns/dcat#>.
+    @prefix dct: <http://purl.org/dc/terms/>.
+    @prefix adms: <http://www.w3.org/ns/adms#> .
+    @prefix dqv:  <http://www.w3.org/ns/dqv#> .
+    @prefix geodcat: <http://data.europa.eu/930/>.
+    @prefix prov: <http://www.w3.org/ns/prov#>. 
+    @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>. 
+    @prefix language: <http://id.loc.gov/vocabulary/iso639-1/>.
+    @prefix s: <${this.FDP_URL}/>.
+    @prefix c: <${this.FDP_URL}/catalog/>.
+    
+    s:new
+    a dcat:Dataset, dcat:Resource;
+    dct:isPartOf c:${this.catalogId} ;
+    ${properties}.`;
   }
 }
 
diff --git a/src/assets/distribution.json b/src/assets/distribution.json
index aa93eb4db..b82a0e09a 100644
--- a/src/assets/distribution.json
+++ b/src/assets/distribution.json
@@ -4,6 +4,31 @@
         "uri": "dcat:accessURL",
         "range": "rdfs:Resource",
         "usageNote": "This property contains a URL that gives access to a Distribution of the Dataset. The resource at the access URL may contain information about how to get the Dataset.",
+        "card": "1..n",
+        "geodcat": false
+    },
+    {
+        "property": "Title",
+        "uri": "dct:title",
+        "range": "rdfs:Literal",
+        "usageNote": "This property contains a name given to the Distribution. This property can be repeated for parallel language versions of the description.",
+        "card": "1..n",
+        "geodcat": false
+    },
+    
+    {
+        "property": "media type",
+        "uri": "dcat:mediaType",
+        "range": "dct:MediaType",
+        "usageNote": "This property refers to the media type of the Distribution as defined in the official register of media types managed by IANA.",
+        "card": "1..1",
+        "geodcat": false
+    },
+    {
+        "property": "compression format",
+        "uri": "dcat:compressFormat",
+        "range": "dct:MediaType",
+        "usageNote": "This property refers to the format of the file in which the data is contained in a compressed form, e.g. to reduce the size of the downloadable file. It SHOULD be expressed using a media type as defined in the official register of media types managed by IANA.",
         "card": "0..1",
         "geodcat": false
     },
@@ -63,14 +88,6 @@
         "card": "0..1",
         "geodcat": false
     },
-    {
-        "property": "compression format",
-        "uri": "dcat:compressFormat",
-        "range": "dct:MediaType",
-        "usageNote": "This property refers to the format of the file in which the data is contained in a compressed form, e.g. to reduce the size of the downloadable file. It SHOULD be expressed using a media type as defined in the official register of media types managed by IANA.",
-        "card": "0..1",
-        "geodcat": false
-    },
     {
         "property": "Documentation",
         "uri": "foaf:page",
@@ -111,14 +128,6 @@
         "card": "0..n",
         "geodcat": false
     },
-    {
-        "property": "media type",
-        "uri": "dcat:mediaType",
-        "range": "dct:MediaType",
-        "usageNote": "This property refers to the media type of the Distribution as defined in the official register of media types managed by IANA.",
-        "card": "1..1",
-        "geodcat": false
-    },
     {
         "property": "packaging format",
         "uri": "dcat:packageFormat",
@@ -167,14 +176,6 @@
         "card": "0..n",
         "geodcat": false
     },
-    {
-        "property": "Title",
-        "uri": "dct:title",
-        "range": "rdfs:Literal",
-        "usageNote": "This property contains a name given to the Distribution. This property can be repeated for parallel language versions of the description.",
-        "card": "0..n",
-        "geodcat": false
-    },
     {
         "property": "update/ modification date",
         "uri": "dct:modified",
diff --git a/src/assets/geodcat.json b/src/assets/geodcat.json
index b1138eb3e..5f235ddba 100644
--- a/src/assets/geodcat.json
+++ b/src/assets/geodcat.json
@@ -3,7 +3,7 @@
         "property": "title",
         "uri": "dct:title",
         "usageNote": "Mandatory property. This property contains a property given to the Dataset. This property can be repeated for parallel language versions of the name.",
-        "card": "1..n",
+        "card": "1..1",
         "geodcat": false
     },
     {
-- 
GitLab


From 4eec92a478a17664a94aab45f76fd4644a277e96 Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Thu, 28 Oct 2021 10:39:30 +0200
Subject: [PATCH 10/19] add toggle

---
 src/app/mapping/mapping.component.html | 9 ++++++++-
 src/app/mapping/mapping.component.ts   | 6 +++++-
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html
index 8a188dfd9..462fc7d43 100644
--- a/src/app/mapping/mapping.component.html
+++ b/src/app/mapping/mapping.component.html
@@ -85,7 +85,14 @@
                 </nb-card>
             </div>
         </div>
-        <div class="card-row">
+        <div class="car-col">
+            <nb-card>
+                <nb-card-body>
+                    <nb-checkbox (checkedChange)="toggleDistri($event)">Add a distribution</nb-checkbox>
+                </nb-card-body>
+            </nb-card>
+        </div>
+        <div class="card-row" *ngIf="addDistribution">
             <div class="card-col">
                 <nb-card size="giant">
                     <nb-card-header>Distribution</nb-card-header>
diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts
index b3171ab9c..2d5a21e11 100644
--- a/src/app/mapping/mapping.component.ts
+++ b/src/app/mapping/mapping.component.ts
@@ -23,7 +23,7 @@ import { FeedbackDialogComponent } from './dialog/feedback-dialog/feedback-dialo
 })
 export class MappingComponent implements OnInit {
 
-
+  addDistribution = false
   check = false;
   distributions: Property[] = [];
   ontology: string;
@@ -525,6 +525,10 @@ export class MappingComponent implements OnInit {
     this.default = checked;
   }
 
+  toggleDistri(checked: boolean){
+    this.addDistribution = checked;
+  }
+
   isMandatory(card: string): boolean {
     return card.startsWith("1");
   }
-- 
GitLab


From 648d90063760419fe7cfdec02afa2c4f2c67dc3a Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Thu, 28 Oct 2021 12:14:08 +0200
Subject: [PATCH 11/19] bug fix

---
 src/app/mapping/mapping.component.html |  2 +-
 src/app/mapping/mapping.component.ts   | 20 ++++++++++----------
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html
index 462fc7d43..feb50ffcb 100644
--- a/src/app/mapping/mapping.component.html
+++ b/src/app/mapping/mapping.component.html
@@ -285,7 +285,7 @@
                     </nb-card>
                     <div class="row">
                         <button class="button-center" nbButton status="danger" *ngIf=" !first "
-                            (click)="distributionMappedMetadatas.splice(index, 1); prev()">Delete datset<nb-icon
+                            (click)="distributionMappedMetadatas.splice(index, 1); prev()">Delete dataset<nb-icon
                                 icon="trash-2-outline">
                             </nb-icon></button>
                     </div>
diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts
index 2d5a21e11..bee530cc8 100644
--- a/src/app/mapping/mapping.component.ts
+++ b/src/app/mapping/mapping.component.ts
@@ -115,7 +115,7 @@ export class MappingComponent implements OnInit {
     let mappedMetadata: Map<number, string> = new Map()
     const array: string[] = (classDcat === "dataset") ? this.selectedPaths : this.distributionSelectedPaths
     for (let i = 0; i < array.length; i++) {
-      if (array[i]) {
+      if (array[i] && array.length > 0) {
         let tab = array[i].split(' : ') ;
         this.type == "Dataverse" ? mappedMetadata.set(i, this.getValueCustom(tab, item)) : mappedMetadata.set(i, this.getValueCustom(tab, item));
       }
@@ -146,11 +146,12 @@ export class MappingComponent implements OnInit {
         
         const location = resp.headers.get("location");
         const datasetId = location.substring(location.search("dataset/") + 8, location.length);
-
-        const properties = this.buildRDF(this.distributions, this.distributionMappedMetadatas, i)
-        const distribution = this.getDistributionEmpty(properties, datasetId)
-        console.log(datasetId);
-        this.dataSetService.createDistribution(distribution).subscribe();
+        if (this.distributionMappedMetadatas.length > 0) {
+          const properties = this.buildRDF(this.distributions, this.distributionMappedMetadatas, i)
+          const distribution = this.getDistributionEmpty(properties, datasetId)
+          console.log(datasetId);
+          this.dataSetService.createDistribution(distribution).subscribe();
+        }
       })
       requestPromises.push(requestPromise);
     }
@@ -176,10 +177,8 @@ export class MappingComponent implements OnInit {
         }
 
         if (Array.isArray(value)) {
-          console.log(`${uri} => ${value}`);
           if (this.isReplicable(this.getCard(uri))) {
             value.forEach(v => {
-              console.log(`${uri} => ${v}`);
               properties += this.writeRdf(uri, v);
             })
           } else {
@@ -414,9 +413,10 @@ export class MappingComponent implements OnInit {
   mapDataset() {
     this.loadingCr = true;
     this.datasetMappedMetadatas = [];
+    this.distributionMappedMetadatas = [];
     this.itemsdataset.forEach((dataset: Object) => {
-      this.datasetMappedMetadatas.push(this.createDataset(dataset, "dataset"));
-      this.distributionMappedMetadatas.push(this.createDataset(dataset, "distribution"))
+       this.datasetMappedMetadatas.push(this.createDataset(dataset, "dataset"));
+       this.distributionMappedMetadatas.push(this.createDataset(dataset, "distribution"))
     })
     console.table(this.datasetMappedMetadatas);
     console.log(this.distributionMappedMetadatas);
-- 
GitLab


From 6710ee25c4dee6a531c8085c56013ae07e5a3a0e Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Thu, 28 Oct 2021 17:17:48 +0200
Subject: [PATCH 12/19] bug fix

---
 src/app/mapping/mapping.component.ts | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts
index bee530cc8..8746e7c91 100644
--- a/src/app/mapping/mapping.component.ts
+++ b/src/app/mapping/mapping.component.ts
@@ -37,13 +37,11 @@ export class MappingComponent implements OnInit {
   distributionSelectedPaths: string[];
   datasetMappedMetadatas: Map<number, string>[] = [];
   distributionMappedMetadatas: Map<number, string>[] = [];
-  DatasetToPublish: Map<string, string>[];
   index: number = 0
   first: boolean = true;
   loading = false;
   loadingCr = false;
   FDP_URL = environment.fdpUrl;
-  Object: Object;
   ids: number[];
   default = true;
   @ViewChild('autoInput') input;
-- 
GitLab


From 282dd17f9f09fd98a2a5754917e7d1203afef217 Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Mon, 8 Nov 2021 16:35:40 +0100
Subject: [PATCH 13/19] wip

---
 src/app/mapping/class/dataset.ts              |   7 ++
 src/app/mapping/class/stringUtils.ts          |  33 ++++++
 src/app/mapping/mapping.component.html        |   2 +-
 src/app/mapping/mapping.component.ts          |  51 ++++++---
 .../mapping/service/mapping.service.spec.ts   |  16 +++
 src/app/mapping/service/mapping.service.ts    | 102 ++++++++++++++++++
 6 files changed, 197 insertions(+), 14 deletions(-)
 create mode 100644 src/app/mapping/class/stringUtils.ts
 create mode 100644 src/app/mapping/service/mapping.service.spec.ts
 create mode 100644 src/app/mapping/service/mapping.service.ts

diff --git a/src/app/mapping/class/dataset.ts b/src/app/mapping/class/dataset.ts
index 3fa58fbda..09c568e35 100644
--- a/src/app/mapping/class/dataset.ts
+++ b/src/app/mapping/class/dataset.ts
@@ -39,4 +39,11 @@ export class Distribution {
     
 }
 
+export class ResponseFileTsv {
+    public subject_id: string;
+    public predicat_id: string;
+    public object_id: string;
+    public match_type: string;
+}
+
 
diff --git a/src/app/mapping/class/stringUtils.ts b/src/app/mapping/class/stringUtils.ts
new file mode 100644
index 000000000..d6516a1a0
--- /dev/null
+++ b/src/app/mapping/class/stringUtils.ts
@@ -0,0 +1,33 @@
+export class StringUtils {
+
+    trimPropertyName(value) {
+        return value.replace(/\s/g, '');
+    }
+
+    getValueFormatByType(value) {
+        if(value === undefined || value === ''){
+            return String();
+        }
+        //is Number
+        let isNumber = !isNaN(value);
+        if (isNumber) {
+            return Number(value);
+        }
+        // is Boolean
+        if(value === "true" || value === "false"){
+            return JSON.parse(value.toLowerCase());
+        }
+        return String(value);
+    }
+
+    hasContent(values) {
+        if (values.length > 0) {
+            for (let i = 0; i < values.length; i++) {
+                if (values[i]) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html
index feb50ffcb..47cd236c4 100644
--- a/src/app/mapping/mapping.component.html
+++ b/src/app/mapping/mapping.component.html
@@ -22,7 +22,7 @@
                             <button class="button-center" nbButton status="primary" (click)="openFileInputDialog()">
                                 <nb-icon icon="upload-outline"></nb-icon>Import file
                             </button>
-                            <input type="file" id="file" (change)="importJson($event)" accept=".json" />
+                            <input type="file" id="file" (change)="importJson($event)" accept=".json, .tsv" />
                         </div>
 
                         <ng-container *ngFor="let dataset of dcatVocabulary ; let index = index">
diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts
index 8746e7c91..d7f73edaf 100644
--- a/src/app/mapping/mapping.component.ts
+++ b/src/app/mapping/mapping.component.ts
@@ -12,8 +12,9 @@ import { map } from 'rxjs/operators';
 import { environment } from 'src/environments/environment.prod';
 import { DatasetCrudService } from '../datasets/services/dataset-crud.service';
 
-import { Property, DatasetPath, Distribution } from './class/dataset';
+import { Property, DatasetPath, Distribution, ResponseFileTsv } from './class/dataset';
 import { FeedbackDialogComponent } from './dialog/feedback-dialog/feedback-dialog.component';
+import { MappingService } from './service/mapping.service';
 
 
 @Component({
@@ -48,7 +49,7 @@ export class MappingComponent implements OnInit {
   @Input() type: string;
   @Input() catalogId: any;
 
-  constructor(private dataSetService: DatasetCrudService, private dialog: MatDialog, private route: Router, private fileSaverService: FileSaverService) { }
+  constructor(private dataSetService: DatasetCrudService, private dialog: MatDialog, private route: Router, private fileSaverService: FileSaverService, private mappingService: MappingService) { }
 
   ngOnInit() {
     console.log(this.type)
@@ -448,10 +449,11 @@ export class MappingComponent implements OnInit {
 
     }
 
-    const fileName = 'paths.json';
+    /*const fileName = 'paths.json';
     const fileType = this.fileSaverService.genType(fileName);
     const txtBlob = new Blob([(JSON.stringify(datasetPathArray)).toString()], { type: fileName });
-    this.fileSaverService.save(txtBlob, fileName);
+    this.fileSaverService.save(txtBlob, fileName);*/
+    this.mappingService.downloadFile(datasetPathArray);
   }
 
   openFileInputDialog(): void {
@@ -463,17 +465,40 @@ export class MappingComponent implements OnInit {
     const jsonFile = files[0];
     console.log(jsonFile)
     let reader = new FileReader();
-    let datasetPath: DatasetPath[] = [];
+    let datasetPath: DatasetPath[] | ResponseFileTsv[] = [];
     reader.onloadend = () => {
-      datasetPath = <DatasetPath[]>JSON.parse(reader.result as string);
-      for (let i = 0; i < datasetPath.length; i++) {
-        this.selectedPaths[i] = datasetPath[i].path;
-        if (typeof datasetPath[i].dcatProperty !== 'object') {
-          this.dcatVocabulary[i] = this.vocabularies.filter( v => v.uri === <string>datasetPath[i].dcatProperty)[0];
-        } else {
-          this.dcatVocabulary[i] = <Property>datasetPath[i].dcatProperty;
+      if (files[0].name.split('.')[1] === "tsv") {
+        let datasetPath: ResponseFileTsv[] = <ResponseFileTsv[]> this.mappingService.tsvToJson(reader.result as string);
+        let index = 0;
+        
+        
+        for (let i = 0; i < datasetPath.length; i++) {
+          for (let j = 0; j < this.dcatVocabulary.length; j++){
+            if (datasetPath[i].object_id === this.dcatVocabulary[j].uri){
+              if (i > 0 && datasetPath[i].object_id === datasetPath[i - 1].object_id ) {
+                this.selectedPaths = this.selectedPaths.splice(j + 1, 0, '');
+                this.selectedPaths[j + 1] = datasetPath[i - 1].subject_id;
+                this.dcatVocabulary[i] = this.vocabularies.find( v => v.uri === <string>datasetPath[i].object_id);
+                ++i;
+              } else {
+                this.selectedPaths[j] = datasetPath[i].subject_id;
+                this.dcatVocabulary[i] = this.vocabularies.find( v => v.uri === <string>datasetPath[i].object_id);
+              }
+            }
+          }
+        }
+      } else {
+        let datasetPath: DatasetPath[] = <DatasetPath[]> JSON.parse(reader.result as string);
+        for (let i = 0; i < datasetPath.length; i++) {
+          this.selectedPaths[i] = datasetPath[i].path;
+          if (typeof datasetPath[i].dcatProperty !== 'object') {
+            this.dcatVocabulary[i] = this.vocabularies.filter( v => v.uri === <string>datasetPath[i].dcatProperty)[0];
+          } else {
+            this.dcatVocabulary[i] = <Property>datasetPath[i].dcatProperty;
+          }
         }
       }
+      
     }
     reader.readAsText(jsonFile);
   }
@@ -481,7 +506,7 @@ export class MappingComponent implements OnInit {
   addField(index: number) {
     let addedDcat: Property = new Property(this.dcatVocabulary[index].property, this.dcatVocabulary[index].uri, this.dcatVocabulary[index].usageNote, true, this.dcatVocabulary[index].card, this.dcatVocabulary[index].geodcat);
     this.dcatVocabulary.splice(index + 1, 0, addedDcat);
-    this.selectedPaths = this.selectedPaths.splice(index + 1, 0, '');
+    this.selectedPaths.splice(index + 1, 0, '');
     console.table(this.selectedPaths)
   }
 
diff --git a/src/app/mapping/service/mapping.service.spec.ts b/src/app/mapping/service/mapping.service.spec.ts
new file mode 100644
index 000000000..002366707
--- /dev/null
+++ b/src/app/mapping/service/mapping.service.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { MappingService } from './mapping.service';
+
+describe('MappingService', () => {
+  let service: MappingService;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({});
+    service = TestBed.inject(MappingService);
+  });
+
+  it('should be created', () => {
+    expect(service).toBeTruthy();
+  });
+});
diff --git a/src/app/mapping/service/mapping.service.ts b/src/app/mapping/service/mapping.service.ts
new file mode 100644
index 000000000..d11d8af37
--- /dev/null
+++ b/src/app/mapping/service/mapping.service.ts
@@ -0,0 +1,102 @@
+import { Injectable } from '@angular/core';
+import { TokenStorageService } from 'src/app/authentication/services/token-storage.service';
+import { DatasetPath } from '../class/dataset';
+
+@Injectable({
+  providedIn: 'root'
+})
+
+export class MappingService {
+
+  constructor(private storageService: TokenStorageService) { }
+
+  downloadFile(data: DatasetPath[], filename = 'dcatMapping') {
+    let tsvData = this.convertToTSV(data, [
+      'subject_id',
+      'predicate_id',
+      'object_id',
+      'match_type'
+    ]);
+
+    let blob = new Blob(['\ufeff' + tsvData], {
+      type: 'text/tsv;charset=utf-8;',
+    });
+    let dwldLink = document.createElement('a');
+    let url = URL.createObjectURL(blob);
+    let safariBrowser = navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1;
+    if (safariBrowser) {
+      dwldLink.setAttribute('target', '_blank');
+    }
+    dwldLink.setAttribute('href', url);
+    dwldLink.setAttribute('download', filename + '.tsv');
+    dwldLink.style.visibility = 'hidden';
+    document.body.appendChild(dwldLink);
+    dwldLink.click();
+    document.body.removeChild(dwldLink);
+  }
+
+  convertToTSV(objArray: DatasetPath[], headerList: string[]): string {
+    let array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
+    let str = '';
+    let row = '';
+
+    for (let index in headerList) {
+      row += headerList[index] + '\t';
+    }
+    row = row.slice(0, -1);
+    str += row + '\r\n';
+    for (let i = 0; i < array.length; i++) {
+
+      if (array[i].path) {
+        let line = '';
+        for (let index in headerList) {
+          let head = headerList[index];
+          switch (head) {
+            case 'subject_id':
+              line += array[i].path + '\t';
+              break;
+            case 'predicate_id':
+              line += 'skos:exactMatch' + '\t';
+              break;
+            case 'object_id':
+              line += array[i].dcatProperty.uri + '\t';
+              break;
+            case 'match_type':
+              line += 'lexical' + '\t';
+          }
+        }
+        str += line + '\r\n';
+      }
+
+
+
+    }
+    return str;
+  }
+
+  tsvToJson(tsv: string): Object {
+    let lines: string[] = tsv.split('\n');
+    let result = [];
+    
+    for (let i = 0; i < lines.length; i++) {
+      if (lines[i].startsWith('#')) {
+        lines.splice(i, 1);
+      } 
+    }
+    let headers = lines[0].split('\t');
+    lines.shift()
+    for (let i = 0; i < lines.length; i++) {
+      
+      let obj = {};
+      let currentLine = lines[i].split('\t');
+
+      for (var j = 0; j < headers.length; j++) {
+        obj[headers[j]] = currentLine[j];
+      }
+
+      result.push(obj);
+    }
+
+    return result;
+  }
+}
-- 
GitLab


From fddfa64818ca839ad8d9e74f4980dd2e7d2f50df Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Mon, 8 Nov 2021 17:02:12 +0100
Subject: [PATCH 14/19] import and export ok have to valid subject_id

---
 src/app/mapping/mapping.component.html | 2 +-
 src/app/mapping/mapping.component.ts   | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html
index 47cd236c4..895e63770 100644
--- a/src/app/mapping/mapping.component.html
+++ b/src/app/mapping/mapping.component.html
@@ -71,7 +71,7 @@
                                             <nb-icon icon="plus-outline" status="primary">
                                             </nb-icon>
                                         </button>
-                                        <button nbButton ghost *ngIf="dataset.isDuplicated"
+                                        <button nbButton ghost *ngIf="dataset.uri === dcatVocabulary[index - 1].uri"
                                             (click)="deleteField(index)">
                                             <nb-icon icon="trash-2-outline" status="danger">
                                             </nb-icon>
diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts
index d7f73edaf..9721163fd 100644
--- a/src/app/mapping/mapping.component.ts
+++ b/src/app/mapping/mapping.component.ts
@@ -476,8 +476,8 @@ export class MappingComponent implements OnInit {
           for (let j = 0; j < this.dcatVocabulary.length; j++){
             if (datasetPath[i].object_id === this.dcatVocabulary[j].uri){
               if (i > 0 && datasetPath[i].object_id === datasetPath[i - 1].object_id ) {
-                this.selectedPaths = this.selectedPaths.splice(j + 1, 0, '');
-                this.selectedPaths[j + 1] = datasetPath[i - 1].subject_id;
+                this.selectedPaths.splice(j + 1, 0, '');
+                this.selectedPaths[j + 1] = datasetPath[i].subject_id;
                 this.dcatVocabulary[i] = this.vocabularies.find( v => v.uri === <string>datasetPath[i].object_id);
                 ++i;
               } else {
-- 
GitLab


From 2bbc6d40c0704fc67ffce6c2c4b8fb2e14360952 Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Wed, 10 Nov 2021 11:10:34 +0100
Subject: [PATCH 15/19] bug fix wip

---
 src/app/mapping/class/dataset.ts           |  25 ++-
 src/app/mapping/mapping.component.html     |  44 ++---
 src/app/mapping/mapping.component.ts       | 189 ++++++++++++---------
 src/app/mapping/service/mapping.service.ts |  10 +-
 src/assets/distribution.json               |  17 +-
 5 files changed, 169 insertions(+), 116 deletions(-)

diff --git a/src/app/mapping/class/dataset.ts b/src/app/mapping/class/dataset.ts
index 09c568e35..824e8b02d 100644
--- a/src/app/mapping/class/dataset.ts
+++ b/src/app/mapping/class/dataset.ts
@@ -6,7 +6,8 @@ export class Property {
     public card: string;
     public geodcat: boolean;
     public isDuplicated?: boolean = false;
-
+    public dcatClass?: string;
+  
     constructor(name: string, identifier: string, usageNote: string, isDuplicated: boolean, card: string, geodcat:boolean) {
         this.property = name;
         this.uri = identifier;
@@ -17,13 +18,30 @@ export class Property {
     }
 }
 
+
+export class OldProperty {
+    public name: string;
+    public identifier: string;
+    public usageNote: string;
+    public isDuplicated?: boolean = false;
+  
+    constructor(name: string, identifier: string, usageNote: string, isDuplicated: boolean, card: string, geodcat:boolean) {
+        this.name = name;
+        this.identifier = identifier;
+        this.usageNote = usageNote;
+        this.isDuplicated = isDuplicated;
+        
+    }
+}
 export class DatasetPath {
     public dcatProperty: Property | string;
-    public path: string
+    public path: string;
+    public dcatClass: string;
 
-    constructor(dcatProperty: Property, path: string) {
+    constructor(dcatProperty: Property, path: string, dcatClass: string) {
         this.dcatProperty = dcatProperty;
         this.path = path;
+        this.dcatClass = dcatClass;
     }
 }
 
@@ -44,6 +62,7 @@ export class ResponseFileTsv {
     public predicat_id: string;
     public object_id: string;
     public match_type: string;
+    public object_category: string;
 }
 
 
diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html
index 895e63770..14603b2fd 100644
--- a/src/app/mapping/mapping.component.html
+++ b/src/app/mapping/mapping.component.html
@@ -9,23 +9,25 @@
         </nb-card-body>
     </nb-card>
 
+    
     <form #form="ngForm" *ngIf="ontology">
+        <div class="row">
+            <p>Upload Or fill out the form with the path corresponding to the dcat property and save a
+                new
+                file for next mappings:</p>
+            <button class="button-center" nbButton status="primary" (click)="openFileInputDialog()">
+                <nb-icon icon="upload-outline"></nb-icon>Import file
+            </button>
+            <input type="file" id="file" (change)="importJson($event)" accept=".json, .tsv" />
+        </div>
         <div class="card-row">
             <div class="card-col">
                 <nb-card size="giant">
                     <nb-card-header>Dataset</nb-card-header>
                     <nb-card-body>
-                        <div class="row">
-                            <p>Upload Or fill out the form with the path corresponding to the dcat property and save a
-                                new
-                                file for next mappings:</p>
-                            <button class="button-center" nbButton status="primary" (click)="openFileInputDialog()">
-                                <nb-icon icon="upload-outline"></nb-icon>Import file
-                            </button>
-                            <input type="file" id="file" (change)="importJson($event)" accept=".json, .tsv" />
-                        </div>
+                        
 
-                        <ng-container *ngFor="let dataset of dcatVocabulary ; let index = index">
+                        <ng-container *ngFor="let dataset of datasets ; let index = index">
                             <nb-form-field>
                                 <div class="row">
 
@@ -36,7 +38,7 @@
                                                 value="{{dataset.uri}} " disabled style="color: black;" />
                                             <input *ngIf="isMandatory(dataset.card)" nbInput fullWidth type="text"
                                                 value="{{dataset.uri}} *" disabled style="color: black;" />
-                                            <button nbSuffix nbTooltip="{{dataset.name}}: {{dataset.usageNote}}"
+                                            <button nbSuffix nbTooltip="{{dataset.property}}: {{dataset.usageNote}}"
                                                 nbTooltipStatus="info" nbButton status="basic" ghost>
                                                 <nb-icon [icon]=" 'question-mark-circle-outline' " pack="eva">
                                                 </nb-icon>
@@ -66,12 +68,12 @@
                                             </nb-autocomplete>
                                         </nb-form-field>
                                     </div>
-                                    <div class="col-2" *ngIf="isReplicable(dataset.card)" style="margin-left: 10px;">
-                                        <button nbButton ghost (click)="addField(index)" *ngIf="!dataset.isDuplicated">
+                                    <div class="col-2" *ngIf="isReplicable(dataset.card) " style="margin-left: 10px;">
+                                        <button nbButton ghost (click)="addField(index)" *ngIf="dataset.uri !== datasets[index - 1].uri">
                                             <nb-icon icon="plus-outline" status="primary">
                                             </nb-icon>
                                         </button>
-                                        <button nbButton ghost *ngIf="dataset.uri === dcatVocabulary[index - 1].uri"
+                                        <button nbButton ghost *ngIf="dataset.uri === datasets[index - 1].uri"
                                             (click)="deleteField(index)">
                                             <nb-icon icon="trash-2-outline" status="danger">
                                             </nb-icon>
@@ -109,7 +111,7 @@
                                             <input *ngIf="isMandatory(distribution.card)" nbInput fullWidth type="text"
                                                 value="{{distribution.uri}} *" disabled style="color: black;" />
                                             <button nbSuffix
-                                                nbTooltip="{{distribution.name}}: {{distribution.usageNote}}"
+                                                nbTooltip="{{distribution.property}}: {{distribution.usageNote}}"
                                                 nbTooltipStatus="info" nbButton status="basic" ghost>
                                                 <nb-icon [icon]=" 'question-mark-circle-outline' " pack="eva">
                                                 </nb-icon>
@@ -143,11 +145,11 @@
                                     <div class="col-2" *ngIf="isReplicable(distribution.card)"
                                         style="margin-left: 10px;">
                                         <button nbButton ghost (click)="addField(index)"
-                                            *ngIf="!distribution.isDuplicated">
+                                            *ngIf="distribution.uri !== distributions[index - 1].uri">
                                             <nb-icon icon="plus-outline" status="primary">
                                             </nb-icon>
                                         </button>
-                                        <button nbButton ghost *ngIf="distribution.isDuplicated"
+                                        <button nbButton ghost *ngIf="distribution.uri === distributions[index - 1].uri"
                                             (click)="deleteField(index)">
                                             <nb-icon icon="trash-2-outline" status="danger">
                                             </nb-icon>
@@ -183,7 +185,7 @@
                                 *ngFor="let data of datasetMappedMetadatas[index] | keyvalue; trackBy:trackByIndex; ">
                                 <div class="row">
                                     <div class="col-3"><label
-                                            for="{{data.key}}">{{dcatVocabulary[data.key].uri}}</label>
+                                            for="{{data.key}}">{{datasets[data.key].uri}}</label>
                                     </div>
                                     <div class="col-7">
                                         <ng-template #normal>
@@ -191,18 +193,18 @@
                                                 (ngModelChange)="datasetMappedMetadatas[index].set(data.key, $event)" />
                                         </ng-template>
                                         <ng-container
-                                            *ngIf="isArray(data.value) && !isReplicable(dcatVocabulary[data.key].card); else normal">
+                                            *ngIf="isArray(data.value) && !isReplicable(datasets[data.key].card); else normal">
                                             <input nbInput [ngModel]="data.value[0]"
                                                 (ngModelChange)="datasetMappedMetadatas[index].set(data.key, $event)" />
                                         </ng-container>
                                         <ng-container
-                                            *ngIf="isArray(data.value) && isReplicable(dcatVocabulary[data.key].card)">
+                                            *ngIf="isArray(data.value) && isReplicable(datasets[data.key].card)">
                                             <ul *ngFor="let val of data.value" style="margin-left: -100px;">
                                                 <li>
                                                     <div class="row">
                                                         <div class="col-3">
                                                             <label
-                                                                for="{{data.key}}">{{dcatVocabulary[data.key].uri}}</label>
+                                                                for="{{data.key}}">{{datasets[data.key].uri}}</label>
                                                         </div>
                                                         <div class="col-7">
                                                             <input nbInput [ngModel]="val"
diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts
index 9721163fd..05f326814 100644
--- a/src/app/mapping/mapping.component.ts
+++ b/src/app/mapping/mapping.component.ts
@@ -6,13 +6,14 @@ import { FormArray } from '@angular/forms';
 import { MatDialog } from '@angular/material/dialog';
 import { Router } from '@angular/router';
 import { FileSaverService } from 'ngx-filesaver';
+import { version } from 'process';
 
 import { Observable, of, Subscription } from 'rxjs';
 import { map } from 'rxjs/operators';
 import { environment } from 'src/environments/environment.prod';
 import { DatasetCrudService } from '../datasets/services/dataset-crud.service';
 
-import { Property, DatasetPath, Distribution, ResponseFileTsv } from './class/dataset';
+import { Property, DatasetPath, Distribution, ResponseFileTsv, OldProperty } from './class/dataset';
 import { FeedbackDialogComponent } from './dialog/feedback-dialog/feedback-dialog.component';
 import { MappingService } from './service/mapping.service';
 
@@ -28,9 +29,9 @@ export class MappingComponent implements OnInit {
   check = false;
   distributions: Property[] = [];
   ontology: string;
-  urls: any[] = [];  
+  urls: any[] = [];
   itemsdataset: any[] = []
-  dcatVocabulary: Property[];
+  datasets: Property[];
   vocabularies: Property[];
   filteredOptions: Observable<string[]>;
   keys: string[] = [];
@@ -69,15 +70,17 @@ export class MappingComponent implements OnInit {
   }
 
   selectOntology(): void {
-       this.dataSetService.getLocally(`./assets/geodcat.json`).subscribe(
+    this.dataSetService.getLocally(`./assets/geodcat.json`).subscribe(
       datasets => {
-        this.dcatVocabulary = this.ontology === "dcat" ? datasets.filter(d => !d.geodcat) : datasets;
-        this.vocabularies = this.ontology === "dcat" ? datasets.filter(d => !d.geodcat) : datasets;;
+        this.datasets = this.ontology === "dcat" ? datasets.filter(d => !d.geodcat) : datasets;
+        this.vocabularies = this.ontology === "dcat" ? datasets.filter(d => !d.geodcat) : datasets;
+        this.vocabularies.forEach(dataset => dataset.dcatClass = 'dcat:dataset');
         this.selectedPaths = [];
         this.dataSetService.getLocally('./assets/distribution.json').subscribe(
           (distributions: Distribution[]) => {
             this.distributions = this.ontology === "dcat" ? distributions.filter(d => !d.geodcat) : distributions;
-            this.vocabularies = this.vocabularies.concat(this.ontology === "dcat" ? distributions.filter(d => !d.geodcat) : distributions);
+            this.distributions.forEach(distribution => distribution.dcatClass = 'dcat:distribution');
+            this.vocabularies = this.vocabularies.concat(this.ontology === "dcat" ? this.distributions.filter(d => !d.geodcat) : distributions);
             this.distributionSelectedPaths = [];
           }
         );
@@ -86,8 +89,8 @@ export class MappingComponent implements OnInit {
         console.error(error);
       },
     );
-    
-}
+
+  }
 
 
   mapFromXslt() {
@@ -115,7 +118,7 @@ export class MappingComponent implements OnInit {
     const array: string[] = (classDcat === "dataset") ? this.selectedPaths : this.distributionSelectedPaths
     for (let i = 0; i < array.length; i++) {
       if (array[i] && array.length > 0) {
-        let tab = array[i].split(' : ') ;
+        let tab = array[i].split(' : ');
         this.type == "Dataverse" ? mappedMetadata.set(i, this.getValueCustom(tab, item)) : mappedMetadata.set(i, this.getValueCustom(tab, item));
       }
     }
@@ -131,9 +134,9 @@ export class MappingComponent implements OnInit {
     this.loading = true;
     const requestPromises: Promise<any>[] = [];
     for (let i = 0; i < this.datasetMappedMetadatas.length; i++) {
-      
-      properties = this.buildRDF(this.dcatVocabulary, this.datasetMappedMetadatas, i);
-      
+
+      properties = this.buildRDF(this.datasets, this.datasetMappedMetadatas, i);
+
       data = this.getDatasetEmpty(properties);
 
       let requestPromise = this.dataSetService.createDataset(data).then((resp: HttpResponse<any>) => {
@@ -142,7 +145,7 @@ export class MappingComponent implements OnInit {
         } else {
           notPostedDatasets.push(this.ids[i]);
         }
-        
+
         const location = resp.headers.get("location");
         const datasetId = location.substring(location.search("dataset/") + 8, location.length);
         if (this.distributionMappedMetadatas.length > 0) {
@@ -167,31 +170,31 @@ export class MappingComponent implements OnInit {
   }
 
   buildRDF(vocabularies: Property[], array: Map<number, string>[], i: number): string {
-      let properties = "";
-      let version = false;
-      array[i].forEach((value: string, key: number) => {
-        let uri = vocabularies[key].uri;
-        if (uri === 'dct:hasVersion') {
-          version = true;
-        }
+    let properties = "";
+    let version = false;
+    array[i].forEach((value: string, key: number) => {
+      let uri = vocabularies[key].uri;
+      if (uri === 'dct:hasVersion') {
+        version = true;
+      }
 
-        if (Array.isArray(value)) {
-          if (this.isReplicable(this.getCard(uri))) {
-            value.forEach(v => {
-              properties += this.writeRdf(uri, v);
-            })
-          } else {
-            properties += this.writeRdf(uri, value[0]);
-          }
+      if (Array.isArray(value)) {
+        if (this.isReplicable(this.getCard(uri))) {
+          value.forEach(v => {
+            properties += this.writeRdf(uri, v);
+          })
         } else {
-          properties += this.writeRdf(uri, value);
+          properties += this.writeRdf(uri, value[0]);
         }
+      } else {
+        properties += this.writeRdf(uri, value);
+      }
 
-      })
+    })
 
-      if (!version) properties += `dct:hasVersion "undefined";\n`;
+    if (!version) properties += `dct:hasVersion "undefined";\n`;
 
-      return properties;
+    return properties;
   }
 
   publishDatasetFromGeodcatApi() {
@@ -261,7 +264,7 @@ export class MappingComponent implements OnInit {
   getKeysFromMetadataCustom(obj: Object, keyParent: string) {
     Object.keys(obj).forEach(key => {
       if (typeof obj[key] === 'object') {
-        if (Array.isArray(obj[key])) {   
+        if (Array.isArray(obj[key])) {
           obj[key].forEach(e => {
             if (typeof e === 'object') {
               Object.keys(e).forEach(k => {
@@ -270,15 +273,15 @@ export class MappingComponent implements OnInit {
               this.getKeysFromMetadataCustom(e, keyParent + key + ' : ');
             }
           });
-          this.keys.push(keyParent + key )
+          this.keys.push(keyParent + key)
           this.getKeysFromMetadataCustom(obj[key], keyParent + key + ' : ');
         } else {
-          this.keys.push(keyParent + key )
+          this.keys.push(keyParent + key)
           this.getKeysFromMetadataCustom(obj[key], keyParent + key + ' : ');
         }
       } else {
 
-        this.keys.push(keyParent + key );
+        this.keys.push(keyParent + key);
 
       }
     });
@@ -333,7 +336,7 @@ export class MappingComponent implements OnInit {
           if (Array.isArray(obj) && obj.some(e => typeof e === 'object')) {
             let array = [];
             obj.forEach(e => {
-              if (e[tab[i]]){
+              if (e[tab[i]]) {
                 array.push(e[tab[i]]);
               }
             });
@@ -342,7 +345,7 @@ export class MappingComponent implements OnInit {
             let array = [];
             for (let element in obj) {
               obj[element].forEach(e => {
-                if (e[tab[i]]){
+                if (e[tab[i]]) {
                   array.push(e[tab[i]]);
                 }
               })
@@ -414,8 +417,8 @@ export class MappingComponent implements OnInit {
     this.datasetMappedMetadatas = [];
     this.distributionMappedMetadatas = [];
     this.itemsdataset.forEach((dataset: Object) => {
-       this.datasetMappedMetadatas.push(this.createDataset(dataset, "dataset"));
-       this.distributionMappedMetadatas.push(this.createDataset(dataset, "distribution"))
+      this.datasetMappedMetadatas.push(this.createDataset(dataset, "dataset"));
+      this.distributionMappedMetadatas.push(this.createDataset(dataset, "distribution"))
     })
     console.table(this.datasetMappedMetadatas);
     console.log(this.distributionMappedMetadatas);
@@ -440,14 +443,17 @@ export class MappingComponent implements OnInit {
 
   downloadJson() {
     let datasetPathArray: DatasetPath[] = [];
-    for (let i = 0; i < this.dcatVocabulary.length; i++) {
+    for (let i = 0; i < this.datasets.length; i++) {
       if (this.selectedPaths[i]) {
-        datasetPathArray.push(new DatasetPath(this.dcatVocabulary[i], this.selectedPaths[i]));
-      } else {
-        datasetPathArray.push(new DatasetPath(this.dcatVocabulary[i], ""));
+        datasetPathArray.push(new DatasetPath(this.datasets[i], this.selectedPaths[i], 'dcat:dataset'));
+      }
+    }
+    for (let i = 0; i < this.distributions.length; i++) {
+      if (this.distributionSelectedPaths[i]) {
+        datasetPathArray.push(new DatasetPath(this.distributions[i], this.distributionSelectedPaths[i], 'dcat:distribution'))
       }
-
     }
+    console.table(datasetPathArray)
 
     /*const fileName = 'paths.json';
     const fileType = this.fileSaverService.genType(fileName);
@@ -460,58 +466,81 @@ export class MappingComponent implements OnInit {
     document.getElementById('file').click();
   }
 
+  fillFromTsv(vocabulary: Property[], paths: string[], tsvFile: ResponseFileTsv[], dcatClass: string) {
+    for (let i = 0; i < tsvFile.length; i++) {
+      if (i > 0 && tsvFile[i].object_id === tsvFile[i - 1].object_id) {
+        const voc: Property = vocabulary.find(e => e.uri === tsvFile[i].object_id);
+        const index = vocabulary.indexOf(voc);
+        vocabulary.splice(index + 1, 0, voc);
+        paths.splice(index + 1, 0, tsvFile[i].subject_id);
+      } else {
+        const voc: Property = vocabulary.find(e => e.uri === tsvFile[i].object_id);
+        const index = vocabulary.indexOf(voc);
+        paths[index] = tsvFile[i].subject_id;
+      }
+    }
+  }
+
+  
   importJson(event: Event) {
     const files: FileList = (event.target as HTMLInputElement).files;
     const jsonFile = files[0];
-    console.log(jsonFile)
-    let reader = new FileReader();
-    let datasetPath: DatasetPath[] | ResponseFileTsv[] = [];
+    const reader = new FileReader();
+
     reader.onloadend = () => {
-      if (files[0].name.split('.')[1] === "tsv") {
-        let datasetPath: ResponseFileTsv[] = <ResponseFileTsv[]> this.mappingService.tsvToJson(reader.result as string);
-        let index = 0;
+      if (jsonFile.name.split('.')[1] === "tsv") {
+        let paths: ResponseFileTsv[] = <ResponseFileTsv[]>this.mappingService.tsvToJson(reader.result as string);
+        let datasetPath: ResponseFileTsv[] = [];
+        let distributionPath: ResponseFileTsv[] = [];
+        console.table(paths)
+        paths.forEach(path => {
+          (path.object_category.includes('dataset')) ? datasetPath.push(path) : distributionPath.push(path);
+        })
         
+        console.log(datasetPath)
+        console.log(distributionPath)
+        if (distributionPath.length > 0) this.addDistribution = true;
+        this.fillFromTsv(this.datasets, this.selectedPaths, datasetPath, 'dcat:dataset');
+        this.fillFromTsv(this.distributions, this.distributionSelectedPaths, distributionPath, 'dcat:distribution');
+      } else {
+        let paths: DatasetPath[] = <DatasetPath[]> JSON.parse(reader.result as string);
+        console.table(paths)
         
-        for (let i = 0; i < datasetPath.length; i++) {
-          for (let j = 0; j < this.dcatVocabulary.length; j++){
-            if (datasetPath[i].object_id === this.dcatVocabulary[j].uri){
-              if (i > 0 && datasetPath[i].object_id === datasetPath[i - 1].object_id ) {
-                this.selectedPaths.splice(j + 1, 0, '');
-                this.selectedPaths[j + 1] = datasetPath[i].subject_id;
-                this.dcatVocabulary[i] = this.vocabularies.find( v => v.uri === <string>datasetPath[i].object_id);
-                ++i;
-              } else {
-                this.selectedPaths[j] = datasetPath[i].subject_id;
-                this.dcatVocabulary[i] = this.vocabularies.find( v => v.uri === <string>datasetPath[i].object_id);
-              }
+        for (let i = 0; i < paths.length; i++) {
+          if (i > 0 && paths[i].dcatProperty === paths[i - 1].dcatProperty) {
+            this.selectedPaths.splice(i + 1, 0, '');
+            this.selectedPaths[i + 1] = paths[i].path;
+            if (typeof paths[i].dcatProperty !== 'object') {
+              this.datasets[i] = this.vocabularies.filter(e => e.dcatClass === 'dcat:dataset').find(v => v.uri === <string>paths[i].dcatProperty);
+            } else {
+              this.datasets[i] = this.vocabularies.filter(e => e.dcatClass === 'dcat:dataset').find(v => v.uri === (<OldProperty><unknown>paths[i].dcatProperty).identifier);
             }
-          }
-        }
-      } else {
-        let datasetPath: DatasetPath[] = <DatasetPath[]> JSON.parse(reader.result as string);
-        for (let i = 0; i < datasetPath.length; i++) {
-          this.selectedPaths[i] = datasetPath[i].path;
-          if (typeof datasetPath[i].dcatProperty !== 'object') {
-            this.dcatVocabulary[i] = this.vocabularies.filter( v => v.uri === <string>datasetPath[i].dcatProperty)[0];
+           
           } else {
-            this.dcatVocabulary[i] = <Property>datasetPath[i].dcatProperty;
+            this.selectedPaths[i] = paths[i].path;
+            if (typeof paths[i].dcatProperty !== 'object') {
+              this.datasets[i] = this.vocabularies.find(v => v.uri === <string>paths[i].dcatProperty);
+            } else {
+              this.datasets[i] = this.vocabularies.find(v => v.uri === (<OldProperty><unknown>paths[i].dcatProperty).identifier);
+            }
           }
+          
+         
         }
       }
-      
     }
     reader.readAsText(jsonFile);
   }
 
   addField(index: number) {
-    let addedDcat: Property = new Property(this.dcatVocabulary[index].property, this.dcatVocabulary[index].uri, this.dcatVocabulary[index].usageNote, true, this.dcatVocabulary[index].card, this.dcatVocabulary[index].geodcat);
-    this.dcatVocabulary.splice(index + 1, 0, addedDcat);
+    let addedDcat: Property = new Property(this.datasets[index].property, this.datasets[index].uri, this.datasets[index].usageNote, true, this.datasets[index].card, this.datasets[index].geodcat);
+    this.datasets.splice(index + 1, 0, addedDcat);
     this.selectedPaths.splice(index + 1, 0, '');
     console.table(this.selectedPaths)
   }
 
   deleteField(index: number) {
-    this.dcatVocabulary.splice(index, 1);
+    this.datasets.splice(index, 1);
     this.selectedPaths.splice(index, 1);
     console.table(this.selectedPaths)
   }
@@ -520,7 +549,7 @@ export class MappingComponent implements OnInit {
   deleteProperty(key: number) {
     this.datasetMappedMetadatas[this.index].delete(key);
   }
-  
+
   trackByIndex(index: number): any {
     return index;
   }
@@ -548,7 +577,7 @@ export class MappingComponent implements OnInit {
     this.default = checked;
   }
 
-  toggleDistri(checked: boolean){
+  toggleDistri(checked: boolean) {
     this.addDistribution = checked;
   }
 
@@ -560,7 +589,7 @@ export class MappingComponent implements OnInit {
     return card.endsWith("n");
   }
 
-  getCard(uri:string): string {
+  getCard(uri: string): string {
     return this.vocabularies.find((vocabulary: Property) => vocabulary.uri === uri).card;
   }
 
diff --git a/src/app/mapping/service/mapping.service.ts b/src/app/mapping/service/mapping.service.ts
index d11d8af37..6e0b4e6e6 100644
--- a/src/app/mapping/service/mapping.service.ts
+++ b/src/app/mapping/service/mapping.service.ts
@@ -15,7 +15,8 @@ export class MappingService {
       'subject_id',
       'predicate_id',
       'object_id',
-      'match_type'
+      'match_type',
+      'object_category'
     ]);
 
     let blob = new Blob(['\ufeff' + tsvData], {
@@ -44,7 +45,7 @@ export class MappingService {
       row += headerList[index] + '\t';
     }
     row = row.slice(0, -1);
-    str += row + '\r\n';
+    str += row + '\n';
     for (let i = 0; i < array.length; i++) {
 
       if (array[i].path) {
@@ -63,9 +64,12 @@ export class MappingService {
               break;
             case 'match_type':
               line += 'lexical' + '\t';
+              break;
+            case 'object_category':
+              line += array[i].dcatClass + '\t';
           }
         }
-        str += line + '\r\n';
+        str += (i != array.length - 1) ? line + '\n' : line;
       }
 
 
diff --git a/src/assets/distribution.json b/src/assets/distribution.json
index b82a0e09a..eef15addc 100644
--- a/src/assets/distribution.json
+++ b/src/assets/distribution.json
@@ -1,4 +1,12 @@
 [
+    {
+        "property": "media type",
+        "uri": "dcat:mediaType",
+        "range": "dct:MediaType",
+        "usageNote": "This property refers to the media type of the Distribution as defined in the official register of media types managed by IANA.",
+        "card": "1..1",
+        "geodcat": false
+    },
     {
         "property": "access URL",
         "uri": "dcat:accessURL",
@@ -15,15 +23,6 @@
         "card": "1..n",
         "geodcat": false
     },
-    
-    {
-        "property": "media type",
-        "uri": "dcat:mediaType",
-        "range": "dct:MediaType",
-        "usageNote": "This property refers to the media type of the Distribution as defined in the official register of media types managed by IANA.",
-        "card": "1..1",
-        "geodcat": false
-    },
     {
         "property": "compression format",
         "uri": "dcat:compressFormat",
-- 
GitLab


From d08fbb2ca4e355cdba8d88c38060fae95987872a Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Wed, 10 Nov 2021 15:54:19 +0100
Subject: [PATCH 16/19] fix bug when import external file

---
 src/app/mapping/mapping.component.html | 25 ++++++------
 src/app/mapping/mapping.component.ts   | 54 +++++++++++++++-----------
 2 files changed, 44 insertions(+), 35 deletions(-)

diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html
index 14603b2fd..bcc97e856 100644
--- a/src/app/mapping/mapping.component.html
+++ b/src/app/mapping/mapping.component.html
@@ -27,7 +27,7 @@
                     <nb-card-body>
                         
 
-                        <ng-container *ngFor="let dataset of datasets ; let index = index">
+                        <ng-container *ngFor="let dataset of datasets ; let index = index; trackBy: trackByIndex">
                             <nb-form-field>
                                 <div class="row">
 
@@ -51,12 +51,12 @@
                                         <nb-form-field>
                                             <input *ngIf="isMandatory(dataset.card)" required fullWidth
                                                 name=" data{{index}}" nbInput (ngModelChange)="onModelChange($event)"
-                                                [nbAutocomplete]="auto" [(ngModel)]="selectedPaths[index]"
+                                                [nbAutocomplete]="auto" [(ngModel)]="selectedPaths[index]" [value]="selectedPaths[index]? selectedPaths[index] : ''"
                                                 (focus)="reset()" />
 
                                             <input *ngIf="!isMandatory(dataset.card)" fullWidth name=" data{{index}}"
                                                 nbInput (ngModelChange)="onModelChange($event)" [nbAutocomplete]="auto"
-                                                [(ngModel)]="selectedPaths[index]" (focus)="reset()" />
+                                                [(ngModel)]="selectedPaths[index]" [value]="selectedPaths[index]? selectedPaths[index] : ''" (focus)="reset()" />
 
                                             <nb-autocomplete #auto>
 
@@ -69,12 +69,12 @@
                                         </nb-form-field>
                                     </div>
                                     <div class="col-2" *ngIf="isReplicable(dataset.card) " style="margin-left: 10px;">
-                                        <button nbButton ghost (click)="addField(index)" *ngIf="dataset.uri !== datasets[index - 1].uri">
+                                        <button nbButton ghost (click)="addField(index, datasets, selectedPaths)" *ngIf="dataset.uri !== datasets[index - 1].uri">
                                             <nb-icon icon="plus-outline" status="primary">
                                             </nb-icon>
                                         </button>
                                         <button nbButton ghost *ngIf="dataset.uri === datasets[index - 1].uri"
-                                            (click)="deleteField(index)">
+                                            (click)="deleteField(index, datasets, selectedPaths)">
                                             <nb-icon icon="trash-2-outline" status="danger">
                                             </nb-icon>
                                         </button>
@@ -99,7 +99,7 @@
                 <nb-card size="giant">
                     <nb-card-header>Distribution</nb-card-header>
                     <nb-card-body>
-                        <ng-container *ngFor="let distribution of distributions ; let index = index">
+                        <ng-container *ngFor="let distribution of distributions; let index = index; trackBy: trackByIndex" >
                             <nb-form-field>
                                 <div class="row">
 
@@ -124,12 +124,13 @@
                                         <nb-form-field>
                                             <input *ngIf="isMandatory(distribution.card)" required fullWidth
                                                 name=" distri{{index}}" nbInput (ngModelChange)="onModelChange($event)"
-                                                [nbAutocomplete]="auto" [(ngModel)]="distributionSelectedPaths[index]"
+                                                [nbAutocomplete]="auto" [(ngModel)]="distributionSelectedPaths[index]" [value]="distributionSelectedPaths[index]? distributionSelectedPaths[index] : ''"
                                                 (focus)="reset()" />
 
                                             <input *ngIf="!isMandatory(distribution.card)" fullWidth
                                                 name=" distri{{index}}" nbInput (ngModelChange)="onModelChange($event)"
-                                                [nbAutocomplete]="auto" [(ngModel)]="distributionSelectedPaths[index]"
+                                                [nbAutocomplete]="auto" [(ngModel)]="distributionSelectedPaths[index]" 
+                                                [value]="distributionSelectedPaths[index]? distributionSelectedPaths[index] : ''"
                                                 (focus)="reset()" />
 
                                             <nb-autocomplete #auto>
@@ -144,13 +145,13 @@
                                     </div>
                                     <div class="col-2" *ngIf="isReplicable(distribution.card)"
                                         style="margin-left: 10px;">
-                                        <button nbButton ghost (click)="addField(index)"
+                                        <button nbButton ghost (click)="addField(index, distributions, distributionSelectedPaths)"
                                             *ngIf="distribution.uri !== distributions[index - 1].uri">
                                             <nb-icon icon="plus-outline" status="primary">
                                             </nb-icon>
                                         </button>
                                         <button nbButton ghost *ngIf="distribution.uri === distributions[index - 1].uri"
-                                            (click)="deleteField(index)">
+                                            (click)="deleteField(index, distributions, distributionSelectedPaths)">
                                             <nb-icon icon="trash-2-outline" status="danger">
                                             </nb-icon>
                                         </button>
@@ -222,7 +223,7 @@
                                     <div class="col-2">
                                         <button nbButton ghost>
                                             <nb-icon icon="trash-2-outline" status="danger"
-                                                (click)="deleteProperty(data.key)">
+                                                (click)="deleteProperty(data.key, datasetMappedMetadatas)">
                                             </nb-icon>
                                         </button>
                                     </div>
@@ -276,7 +277,7 @@
                                     <div class="col-2">
                                         <button nbButton ghost>
                                             <nb-icon icon="trash-2-outline" status="danger"
-                                                (click)="deleteProperty(data.key)">
+                                                (click)="deleteProperty(data.key, distributionMappedMetadatas)">
                                             </nb-icon>
                                         </button>
                                     </div>
diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts
index 05f326814..b2ec3612e 100644
--- a/src/app/mapping/mapping.component.ts
+++ b/src/app/mapping/mapping.component.ts
@@ -1,7 +1,7 @@
 
 
 import { HttpResponse } from '@angular/common/http';
-import { Component, Input, OnInit, ViewChild } from '@angular/core';
+import { AfterContentChecked, AfterViewChecked, ChangeDetectorRef, Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core';
 import { FormArray } from '@angular/forms';
 import { MatDialog } from '@angular/material/dialog';
 import { Router } from '@angular/router';
@@ -50,7 +50,15 @@ export class MappingComponent implements OnInit {
   @Input() type: string;
   @Input() catalogId: any;
 
-  constructor(private dataSetService: DatasetCrudService, private dialog: MatDialog, private route: Router, private fileSaverService: FileSaverService, private mappingService: MappingService) { }
+  constructor(private ref: ChangeDetectorRef,private dataSetService: DatasetCrudService, private dialog: MatDialog, private route: Router, private fileSaverService: FileSaverService, private mappingService: MappingService) { 
+    ref.detach();
+    setInterval(() => {
+      this.ref.detectChanges();
+    }, 1000);
+  }
+  
+  
+  
 
   ngOnInit() {
     console.log(this.type)
@@ -69,6 +77,8 @@ export class MappingComponent implements OnInit {
 
   }
 
+  
+
   selectOntology(): void {
     this.dataSetService.getLocally(`./assets/geodcat.json`).subscribe(
       datasets => {
@@ -250,14 +260,7 @@ export class MappingComponent implements OnInit {
     }
     return properties;
   }
-  private replaceAll(str: string, find: string, replace: string) {
-    if (str.includes(find)) {
-      const strT = str.replace(find, replace)
-      this.replaceAll(strT, find, replace)
-    } else {
-      return str;
-    }
-  }
+  
 
   /* function to get recursively all the keys and values from the JSON object */
 
@@ -508,8 +511,10 @@ export class MappingComponent implements OnInit {
         
         for (let i = 0; i < paths.length; i++) {
           if (i > 0 && paths[i].dcatProperty === paths[i - 1].dcatProperty) {
-            this.selectedPaths.splice(i + 1, 0, '');
-            this.selectedPaths[i + 1] = paths[i].path;
+            const voc: Property = this.datasets.find(e => e.uri === (<Property>paths[i].dcatProperty).uri);
+            this.datasets.splice(i + 1, 0, voc);
+            this.selectedPaths.splice(i + 1, 0, paths[i].path);
+            
             if (typeof paths[i].dcatProperty !== 'object') {
               this.datasets[i] = this.vocabularies.filter(e => e.dcatClass === 'dcat:dataset').find(v => v.uri === <string>paths[i].dcatProperty);
             } else {
@@ -530,24 +535,27 @@ export class MappingComponent implements OnInit {
       }
     }
     reader.readAsText(jsonFile);
+    this.ref.markForCheck()
+  
+    
   }
 
-  addField(index: number) {
-    let addedDcat: Property = new Property(this.datasets[index].property, this.datasets[index].uri, this.datasets[index].usageNote, true, this.datasets[index].card, this.datasets[index].geodcat);
-    this.datasets.splice(index + 1, 0, addedDcat);
-    this.selectedPaths.splice(index + 1, 0, '');
-    console.table(this.selectedPaths)
+  addField(index: number, properties: Property[], paths: string[]) {
+    let addedDcat: Property = properties.find(e => e.uri === properties[index].uri);
+    properties.splice(index + 1, 0, addedDcat);
+    
+    paths.splice(index + 1, 0, '');
+   
   }
 
-  deleteField(index: number) {
-    this.datasets.splice(index, 1);
-    this.selectedPaths.splice(index, 1);
-    console.table(this.selectedPaths)
+  deleteField(index: number, properties: Property[], paths: string[]) {
+    properties.splice(index, 1);
+    paths.splice(index, 1);
   }
 
   // to delete a property of dcat dataset mapped
-  deleteProperty(key: number) {
-    this.datasetMappedMetadatas[this.index].delete(key);
+  deleteProperty(key: number, map: Map<number, string>[]) {
+    map[this.index].delete(key);
   }
 
   trackByIndex(index: number): any {
-- 
GitLab


From 47e08c6b894054780fe88f84a9d96a9ed42fe651 Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Wed, 10 Nov 2021 16:20:22 +0100
Subject: [PATCH 17/19] add metadatas inhead of tsv file

---
 src/app/mapping/service/mapping.service.ts | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/src/app/mapping/service/mapping.service.ts b/src/app/mapping/service/mapping.service.ts
index 6e0b4e6e6..a5b4875ec 100644
--- a/src/app/mapping/service/mapping.service.ts
+++ b/src/app/mapping/service/mapping.service.ts
@@ -1,5 +1,6 @@
 import { Injectable } from '@angular/core';
 import { TokenStorageService } from 'src/app/authentication/services/token-storage.service';
+import { SmartHarvesterUser } from 'src/app/user/model/user';
 import { DatasetPath } from '../class/dataset';
 
 @Injectable({
@@ -37,8 +38,10 @@ export class MappingService {
   }
 
   convertToTSV(objArray: DatasetPath[], headerList: string[]): string {
+    let date = new Date();
+    let user: SmartHarvesterUser = this.storageService.getUser();
     let array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
-    let str = '';
+    let str = `#mapping_date: ${date.getDate()}/${date.getMonth()}/${date.getFullYear()}\n#creator_label: ${user.firstName} ${user.lastName}\n`;
     let row = '';
 
     for (let index in headerList) {
@@ -81,12 +84,12 @@ export class MappingService {
   tsvToJson(tsv: string): Object {
     let lines: string[] = tsv.split('\n');
     let result = [];
-    
-    for (let i = 0; i < lines.length; i++) {
-      if (lines[i].startsWith('#')) {
-        lines.splice(i, 1);
-      } 
+    console.table(lines)
+    while (lines[0].startsWith('#')) {
+      lines.shift();
     }
+    
+    console.table(lines)
     let headers = lines[0].split('\t');
     lines.shift()
     for (let i = 0; i < lines.length; i++) {
-- 
GitLab


From 25df3b4c8e371c4ea7ed4c025b315ab7894759bd Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Tue, 16 Nov 2021 15:29:29 +0100
Subject: [PATCH 18/19] add request to post tsv description mapping to mongodb

---
 src/app/mapping/mapping.component.ts       | 20 +++++------
 src/app/mapping/service/mapping.service.ts | 42 ++++++++++++++++++++--
 2 files changed, 49 insertions(+), 13 deletions(-)

diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts
index b2ec3612e..9f935c495 100644
--- a/src/app/mapping/mapping.component.ts
+++ b/src/app/mapping/mapping.component.ts
@@ -1,7 +1,7 @@
 
 
 import { HttpResponse } from '@angular/common/http';
-import { AfterContentChecked, AfterViewChecked, ChangeDetectorRef, Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core';
+import { AfterContentChecked, AfterViewChecked, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild } from '@angular/core';
 import { FormArray } from '@angular/forms';
 import { MatDialog } from '@angular/material/dialog';
 import { Router } from '@angular/router';
@@ -23,8 +23,9 @@ import { MappingService } from './service/mapping.service';
   templateUrl: './mapping.component.html',
   styleUrls: ['./mapping.component.scss']
 })
-export class MappingComponent implements OnInit {
+export class MappingComponent implements OnInit, OnDestroy {
 
+  datasetPathArray: DatasetPath[] = [];
   addDistribution = false
   check = false;
   distributions: Property[] = [];
@@ -56,9 +57,6 @@ export class MappingComponent implements OnInit {
       this.ref.detectChanges();
     }, 1000);
   }
-  
-  
-  
 
   ngOnInit() {
     console.log(this.type)
@@ -445,24 +443,23 @@ export class MappingComponent implements OnInit {
   }
 
   downloadJson() {
-    let datasetPathArray: DatasetPath[] = [];
     for (let i = 0; i < this.datasets.length; i++) {
       if (this.selectedPaths[i]) {
-        datasetPathArray.push(new DatasetPath(this.datasets[i], this.selectedPaths[i], 'dcat:dataset'));
+        this.datasetPathArray.push(new DatasetPath(this.datasets[i], this.selectedPaths[i], 'dcat:dataset'));
       }
     }
     for (let i = 0; i < this.distributions.length; i++) {
       if (this.distributionSelectedPaths[i]) {
-        datasetPathArray.push(new DatasetPath(this.distributions[i], this.distributionSelectedPaths[i], 'dcat:distribution'))
+        this.datasetPathArray.push(new DatasetPath(this.distributions[i], this.distributionSelectedPaths[i], 'dcat:distribution'))
       }
     }
-    console.table(datasetPathArray)
+    console.table(this.datasetPathArray)
 
     /*const fileName = 'paths.json';
     const fileType = this.fileSaverService.genType(fileName);
     const txtBlob = new Blob([(JSON.stringify(datasetPathArray)).toString()], { type: fileName });
     this.fileSaverService.save(txtBlob, fileName);*/
-    this.mappingService.downloadFile(datasetPathArray);
+    this.mappingService.downloadFile(this.datasetPathArray);
   }
 
   openFileInputDialog(): void {
@@ -601,6 +598,9 @@ export class MappingComponent implements OnInit {
     return this.vocabularies.find((vocabulary: Property) => vocabulary.uri === uri).card;
   }
 
+  ngOnDestroy(): void {
+    this.mappingService.postFile(this.datasetPathArray, this.catalogId).subscribe();
+  }
   private getDistributionEmpty(properties: string, datasetId: string): string {
     return `@prefix dcat: <http://www.w3.org/ns/dcat#>.
     @prefix dct: <http://purl.org/dc/terms/>.
diff --git a/src/app/mapping/service/mapping.service.ts b/src/app/mapping/service/mapping.service.ts
index a5b4875ec..e898632a7 100644
--- a/src/app/mapping/service/mapping.service.ts
+++ b/src/app/mapping/service/mapping.service.ts
@@ -1,6 +1,8 @@
+import { HttpClient, HttpHeaders, HttpRequest } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 import { TokenStorageService } from 'src/app/authentication/services/token-storage.service';
 import { SmartHarvesterUser } from 'src/app/user/model/user';
+import { environment } from 'src/environments/environment';
 import { DatasetPath } from '../class/dataset';
 
 @Injectable({
@@ -9,7 +11,41 @@ import { DatasetPath } from '../class/dataset';
 
 export class MappingService {
 
-  constructor(private storageService: TokenStorageService) { }
+  fds2Token: string = this.storageService.getToken();
+
+  constructor(private storageService: TokenStorageService, private http: HttpClient) { }
+
+  postFile(objArray: DatasetPath[], catalogId: String) {
+
+    
+
+
+
+    const body: Blob = new Blob(['\ufeff' + this.convertToTSV(objArray, [
+      'subject_id',
+      'predicate_id',
+      'object_id',
+      'match_type',
+      'object_category'
+    ])], {
+      type: 'text/tsv;charset=utf-8;',
+    });
+
+    const data: FormData = new FormData();
+    data.append('file', body);
+    const req = new HttpRequest('POST', `${environment.smartharvesterUrl}/harvester/api/storeMapping/upload/${catalogId}`, data, {
+      headers: new HttpHeaders({
+        
+        'Authorization': 'Bearer ' + this.fds2Token
+      }),
+		  reportProgress: true,
+		  responseType: 'json'
+		});
+	
+		return this.http.request(req);
+
+
+  }
 
   downloadFile(data: DatasetPath[], filename = 'dcatMapping') {
     let tsvData = this.convertToTSV(data, [
@@ -88,12 +124,12 @@ export class MappingService {
     while (lines[0].startsWith('#')) {
       lines.shift();
     }
-    
+
     console.table(lines)
     let headers = lines[0].split('\t');
     lines.shift()
     for (let i = 0; i < lines.length; i++) {
-      
+
       let obj = {};
       let currentLine = lines[i].split('\t');
 
-- 
GitLab


From f834a1e67f0ff21d4e7ac859ca646646eb59f85f Mon Sep 17 00:00:00 2001
From: Baptiste Toulemonde <toulemonde@cines.fr>
Date: Mon, 22 Nov 2021 09:39:46 +0100
Subject: [PATCH 19/19] bug fix

---
 src/app/mapping/class/dataset.ts           | 2 +-
 src/app/mapping/mapping.component.ts       | 4 ++--
 src/app/mapping/service/mapping.service.ts | 8 ++++----
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/app/mapping/class/dataset.ts b/src/app/mapping/class/dataset.ts
index 824e8b02d..d1834ce91 100644
--- a/src/app/mapping/class/dataset.ts
+++ b/src/app/mapping/class/dataset.ts
@@ -58,7 +58,7 @@ export class Distribution {
 }
 
 export class ResponseFileTsv {
-    public subject_id: string;
+    public subject_label: string;
     public predicat_id: string;
     public object_id: string;
     public match_type: string;
diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts
index 9f935c495..8c96f2d49 100644
--- a/src/app/mapping/mapping.component.ts
+++ b/src/app/mapping/mapping.component.ts
@@ -472,11 +472,11 @@ export class MappingComponent implements OnInit, OnDestroy {
         const voc: Property = vocabulary.find(e => e.uri === tsvFile[i].object_id);
         const index = vocabulary.indexOf(voc);
         vocabulary.splice(index + 1, 0, voc);
-        paths.splice(index + 1, 0, tsvFile[i].subject_id);
+        paths.splice(index + 1, 0, tsvFile[i].subject_label);
       } else {
         const voc: Property = vocabulary.find(e => e.uri === tsvFile[i].object_id);
         const index = vocabulary.indexOf(voc);
-        paths[index] = tsvFile[i].subject_id;
+        paths[index] = tsvFile[i].subject_label;
       }
     }
   }
diff --git a/src/app/mapping/service/mapping.service.ts b/src/app/mapping/service/mapping.service.ts
index e898632a7..b43b8d434 100644
--- a/src/app/mapping/service/mapping.service.ts
+++ b/src/app/mapping/service/mapping.service.ts
@@ -22,7 +22,7 @@ export class MappingService {
 
 
     const body: Blob = new Blob(['\ufeff' + this.convertToTSV(objArray, [
-      'subject_id',
+      'subject_label',
       'predicate_id',
       'object_id',
       'match_type',
@@ -49,7 +49,7 @@ export class MappingService {
 
   downloadFile(data: DatasetPath[], filename = 'dcatMapping') {
     let tsvData = this.convertToTSV(data, [
-      'subject_id',
+      'subject_label',
       'predicate_id',
       'object_id',
       'match_type',
@@ -77,7 +77,7 @@ export class MappingService {
     let date = new Date();
     let user: SmartHarvesterUser = this.storageService.getUser();
     let array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
-    let str = `#mapping_date: ${date.getDate()}/${date.getMonth()}/${date.getFullYear()}\n#creator_label: ${user.firstName} ${user.lastName}\n`;
+    let str = `#mapping_date: ${date.getDate()}/${date.getMonth()}/${date.getFullYear()}\n#creator_label: ${user.firstName} ${user.lastName}\n#curie_map:\n#  dcat: "http://www.w3.org/ns/dcat#"\n#  dct: "http://purl.org/dc/terms/"\n#  adms: "http://www.w3.org/ns/adms#\n#  dqv: "http://www.w3.org/ns/dqv#"\n#  geodcat: "http://data.europa.eu/930/"\n#  prov: "http://www.w3.org/ns/prov#"\n# rdfs: "http://www.w3.org/2000/01/rdf-schema#"`;
     let row = '';
 
     for (let index in headerList) {
@@ -92,7 +92,7 @@ export class MappingService {
         for (let index in headerList) {
           let head = headerList[index];
           switch (head) {
-            case 'subject_id':
+            case 'subject_label':
               line += array[i].path + '\t';
               break;
             case 'predicate_id':
-- 
GitLab