From 764b92ae66c45836e9d59ff0f9c3827addef4ead Mon Sep 17 00:00:00 2001 From: argirok Date: Fri, 11 Nov 2022 11:20:02 +0200 Subject: [PATCH 01/16] Eosc data transfer: - add and use separate property for login url - use new API url --- utils/dataTransfer/transferData.component.ts | 2 +- utils/properties/env-properties.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/dataTransfer/transferData.component.ts b/utils/dataTransfer/transferData.component.ts index e0ede1ee..3fa5129a 100644 --- a/utils/dataTransfer/transferData.component.ts +++ b/utils/dataTransfer/transferData.component.ts @@ -35,7 +35,7 @@ export class EGIDataTransferComponent { subscriptions = []; accessToken = null; @Input() dois; - loginURL = properties.environment == "development"? "http://rudie.di.uoa.gr:8580/openid_connect_login":"https://explore.eosc-portal.eu/egi-login-service/openid_connect_login" + loginURL = properties.eoscDataTransferLoginUrl; sourceUrls = []; selectedSourceUrl = null; destinationPath = ""; diff --git a/utils/properties/env-properties.ts b/utils/properties/env-properties.ts index f0f7aacf..a414667b 100644 --- a/utils/properties/env-properties.ts +++ b/utils/properties/env-properties.ts @@ -143,5 +143,6 @@ export interface EnvProperties { egiNotebookLink?: string; connectPortalUrl?; eoscDataTransferAPI?; + eoscDataTransferLoginUrl?; eoscDataTransferDestinations?; } From 8e22fe60b0e68371649d57461c4d08683a397d7e Mon Sep 17 00:00:00 2001 From: argirok Date: Fri, 11 Nov 2022 11:55:15 +0200 Subject: [PATCH 02/16] Data transfer: remove checks for only zenodo dois --- landingPages/result/resultLanding.component.html | 6 ++---- utils/dataTransfer/transferData.component.html | 4 ++-- utils/dataTransfer/transferData.component.ts | 6 ++---- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/landingPages/result/resultLanding.component.html b/landingPages/result/resultLanding.component.html index cedd2c18..a41ffda3 100644 --- a/landingPages/result/resultLanding.component.html +++ b/landingPages/result/resultLanding.component.html @@ -60,8 +60,7 @@
  • @@ -157,8 +156,7 @@
    diff --git a/utils/dataTransfer/transferData.component.html b/utils/dataTransfer/transferData.component.html index 2a478607..2e4c059f 100644 --- a/utils/dataTransfer/transferData.component.html +++ b/utils/dataTransfer/transferData.component.html @@ -28,8 +28,8 @@
    -

    Available Zenodo DOI URLs:

    -
    Available DOI URLs:

    +
    {{this.downloadElements.length}} files found:
    diff --git a/utils/dataTransfer/transferData.component.ts b/utils/dataTransfer/transferData.component.ts index 3fa5129a..736a1ee7 100644 --- a/utils/dataTransfer/transferData.component.ts +++ b/utils/dataTransfer/transferData.component.ts @@ -87,9 +87,7 @@ export class EGIDataTransferComponent { } for (let doi of this.dois) { - if (doi.indexOf("zenodo.") != -1) { this.sourceUrls.push(this.doiPrefix + doi); - } } try { this.sourceUrls.sort(function (a, b) { @@ -147,8 +145,8 @@ export class EGIDataTransferComponent { this.status = "init"; }, error => { this.status = "errorParser"; - this.message = "Couldn't get download URLs from zenodo"; - UIkit.notification("Couldn't get download URLs from zenodo", { + this.message = error.error && error.error.id && error.error.id == 'doiNotSupported'?'DOI not supported':( error.error && error.error.id && error.error.id? error.error.id:'Error parsing information') ; + UIkit.notification(this.message, { status: 'error', timeout: 3000, pos: 'bottom-right' From ce4b358ce9ced23e48f34a8e2ae37bbaa9f6dc5d Mon Sep 17 00:00:00 2001 From: argirok Date: Fri, 11 Nov 2022 12:28:07 +0200 Subject: [PATCH 03/16] add access token in parser method --- utils/dataTransfer/transferData.component.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/utils/dataTransfer/transferData.component.ts b/utils/dataTransfer/transferData.component.ts index 736a1ee7..d884038d 100644 --- a/utils/dataTransfer/transferData.component.ts +++ b/utils/dataTransfer/transferData.component.ts @@ -138,19 +138,20 @@ export class EGIDataTransferComponent { this.status = "loading"; this.message = null; this.downloadElements = []; - this.subscriptions.push(this.http.get(this.APIURL + "/parser?doi=" + encodeURIComponent(this.selectedSourceUrl)).subscribe( + let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); + this.subscriptions.push(this.http.get(this.APIURL + "/parser?doi=" + encodeURIComponent(this.selectedSourceUrl), {headers: headers}).subscribe( res => { this.downloadElements= res['elements'] // console.log(this.downloadElements) this.status = "init"; }, error => { this.status = "errorParser"; - this.message = error.error && error.error.id && error.error.id == 'doiNotSupported'?'DOI not supported':( error.error && error.error.id && error.error.id? error.error.id:'Error parsing information') ; - UIkit.notification(this.message, { + this.message = error.error && error.error.id && error.error.id == 'doiNotSupported'?'DOI not supported':( error.error && error.error.description && error.error.description? error.error.description:'Error parsing information') ; + /* UIkit.notification(this.message, { status: 'error', timeout: 3000, pos: 'bottom-right' - }); + });*/ } )); From 7666b55b6c2e02e029fe32722337eff889cc1ce9 Mon Sep 17 00:00:00 2001 From: argirok Date: Fri, 11 Nov 2022 13:56:58 +0200 Subject: [PATCH 04/16] Data transfer: add input for destination URL, inputs for destination authorization add destination authorization header in parser --- .../dataTransfer/transferData.component.html | 51 ++++++++++++++----- utils/dataTransfer/transferData.component.ts | 29 +++++++---- 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/utils/dataTransfer/transferData.component.html b/utils/dataTransfer/transferData.component.html index 2e4c059f..6e835e1b 100644 --- a/utils/dataTransfer/transferData.component.html +++ b/utils/dataTransfer/transferData.component.html @@ -44,23 +44,49 @@
    -

    Please select the Destination Storage type:

    + + Testing:
    + https://dcache-demo.desy.de:2443 +
    + /Demonstrators/EOSC-Future/EGI/ +
    + +

    Please select the + Destination Storage technology:

    - + [options]="destinationOptions">
    + +

    Provide the + corresponding storage destination url:

    +
    + + +

    Provide + authentication if needed:

    +
    +
    +
    +
    +
    +

    Provide the corresponding storage destination path:

    -
    + [validators]="pathValidators" class="">
    +

    or browse to + class="uk-text-primary" (click)="browseFolder('/')">browse to select a folder.

    -
    - +
    +
    -
    - +

    Comming soon!

    @@ -117,7 +143,8 @@
    • - + @@ -144,7 +171,7 @@ title="Expand/ Collapse"> {{folder.name?folder.name:folder.accessUrl.split(selectedDestination.url)[1]}} + class="uk-width-expand uk-text-truncate uk-margin-small-left">{{folder.name?folder.name:folder.accessUrl.split(destinationUrl)[1]}}
    diff --git a/utils/dataTransfer/transferData.component.ts b/utils/dataTransfer/transferData.component.ts index d884038d..eacaa5aa 100644 --- a/utils/dataTransfer/transferData.component.ts +++ b/utils/dataTransfer/transferData.component.ts @@ -7,6 +7,7 @@ import {COOKIE} from "../../login/utils/helper.class"; import {Router} from "@angular/router"; import {properties} from "../../../../environments/environment"; import {delay, repeat} from "rxjs/operators"; +import {StringUtils} from "../string-utils.class"; declare var UIkit; @Component({ @@ -38,9 +39,12 @@ export class EGIDataTransferComponent { loginURL = properties.eoscDataTransferLoginUrl; sourceUrls = []; selectedSourceUrl = null; + destinationUrl = ""; + destinationAuthUser = ""; + destinationAuthPass = ""; destinationPath = ""; destinationOptions = properties.eoscDataTransferDestinations; - selectedDestination = null; + selectedDestination:{label :string, id: string, auth: 'token' | 'password' | 'keys'} = null; folders = {}; files = {}; downloadElements = null; @@ -51,7 +55,8 @@ export class EGIDataTransferComponent { status: "loading" | "success" | "errorParser" | "errorUser" | "errorTransfer" | "init" | "canceled" = "init"; message; doiPrefix = properties.doiURL; - validators = [Validators.required, this.pathValidator() /*StringUtils.urlValidator()*/]; + pathValidators = [Validators.required, this.pathValidator() /*StringUtils.urlValidator()*/]; + URLValidators = [Validators.required, StringUtils.urlValidator()]; jobId = null; statusMessage = null; jobStatus; @@ -179,7 +184,7 @@ export class EGIDataTransferComponent { let file = { "sources": [element['downloadUrl']], - "destinations": [this.selectedDestination.url + this.destinationPath + element.name], + "destinations": [this.destinationUrl + this.destinationPath + element.name], }; //TODO priority? checksum? filesize? @@ -188,6 +193,10 @@ export class EGIDataTransferComponent { } let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); + if(this.selectedDestination.auth != "token" && this.destinationAuthPass.length > 0 && this.destinationAuthUser.length > 0){ + headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken, + 'Authorization-Storage': btoa(this.destinationAuthUser + ':' + this.destinationAuthPass)}); + } this.subscriptions.push(this.http.post(this.APIURL + "/transfers" ,body, {headers: headers}).subscribe( res => { // console.log(res) @@ -201,7 +210,7 @@ export class EGIDataTransferComponent { this.egiTransferModal.okButton = false; this.message = ` -
    Transfer of ` + this.downloadElements.length + ` files to `+this.selectedDestination.label+` has began.`; +
    Transfer of ` + this.downloadElements.length + ` files to `+this.selectedDestination.label+` has began.`; /*this.message += `
      `; @@ -255,7 +264,7 @@ export class EGIDataTransferComponent { this.jobStatus = res; this.message = ` -
      Transfer of ` + this.downloadElements.length + ` files to `+this.selectedDestination.label+` has began.`; +
      Transfer of ` + this.downloadElements.length + ` files to ` + this.selectedDestination.label+` has began.`; /*this.message += `
        `; @@ -313,7 +322,7 @@ export class EGIDataTransferComponent { } hasBrowse(){ let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); - this.subscriptions.push(this.http.get(this.APIURL + "/storage/info?dest="+this.selectedDestination.id+"&seUrl="+encodeURIComponent(this.selectedDestination.url + this.destinationPath) , {headers: headers}).subscribe( + this.subscriptions.push(this.http.get(this.APIURL + "/storage/info?dest="+this.selectedDestination.id+"&seUrl="+encodeURIComponent(this.destinationUrl + this.destinationPath) , {headers: headers}).subscribe( res => { console.log(res); } @@ -323,7 +332,7 @@ export class EGIDataTransferComponent { getFolder(folderPath){ //TODO is this necessary? let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); - this.subscriptions.push(this.http.get(this.APIURL + "/storage/folder?dest="+this.selectedDestination.id+"&seUrl="+encodeURIComponent(this.selectedDestination.url + folderPath) , {headers: headers}).subscribe( + this.subscriptions.push(this.http.get(this.APIURL + "/storage/folder?dest="+this.selectedDestination.id+"&seUrl="+encodeURIComponent(this.destinationUrl + folderPath) , {headers: headers}).subscribe( res => { this.folders[folderPath]= res; this.folders[folderPath]['isOpen'] = true; @@ -338,7 +347,7 @@ export class EGIDataTransferComponent { } this.getFolder(folderPath); let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); - this.subscriptions.push(this.http.get(this.APIURL + "/storage/folder/list?dest="+this.selectedDestination.id+"&folderUrl="+encodeURIComponent(this.selectedDestination.url + folderPath) , {headers: headers}).subscribe( + this.subscriptions.push(this.http.get(this.APIURL + "/storage/folder/list?dest="+this.selectedDestination.id+"&folderUrl="+encodeURIComponent(this.destinationUrl + folderPath) , {headers: headers}).subscribe( res => { this.files[folderPath]= res['elements']; } @@ -348,7 +357,7 @@ export class EGIDataTransferComponent { createFolder(){ let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); this.subscriptions.push(this.http.post(this.APIURL + "/storage/folder?dest="+this.selectedDestination.id+"&seUrl="+ - encodeURIComponent(this.selectedDestination.url + this.destinationPath + "test1/") , {headers: headers}).subscribe( + encodeURIComponent(this.destinationUrl + this.destinationPath + "test1/") , {headers: headers}).subscribe( res => { console.log(res); } @@ -358,7 +367,7 @@ export class EGIDataTransferComponent { deleteFolder(){ let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); - this.subscriptions.push(this.http.delete(this.APIURL + "/storage/folder?dest="+this.selectedDestination.id+"&seUrl="+encodeURIComponent(this.selectedDestination.url + this.destinationPath + "test1/") , {headers: headers}).subscribe( + this.subscriptions.push(this.http.delete(this.APIURL + "/storage/folder?dest="+this.selectedDestination.id+"&seUrl="+encodeURIComponent(this.destinationUrl + this.destinationPath + "test1/") , {headers: headers}).subscribe( res => { console.log(res); } From 50543311f2186435abd77c92ab920b7e37d710da Mon Sep 17 00:00:00 2001 From: "konstantina.galouni" Date: Wed, 4 Jan 2023 13:27:49 +0200 Subject: [PATCH 05/16] [Eosc Explore & Library | data-transfer-v2]: environment.ts: Updated eoscDataTransferDestinations to be like api response. | transferData.component: Updated destinationOptions and selectedDestination according to the updated eoscDataTransferDestinations. --- .../dataTransfer/transferData.component.html | 8 +++--- utils/dataTransfer/transferData.component.ts | 25 ++++++++++--------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/utils/dataTransfer/transferData.component.html b/utils/dataTransfer/transferData.component.html index 6e835e1b..5ebc6e2a 100644 --- a/utils/dataTransfer/transferData.component.html +++ b/utils/dataTransfer/transferData.component.html @@ -62,14 +62,14 @@ [validators]="URLValidators" class="">
      + *ngIf="selectedDestination.authType == 'password' || selectedDestination.authType == 'keys'">

      Provide authentication if needed:

      -
      -
      @@ -87,7 +87,7 @@
      - +

      Comming soon!

      diff --git a/utils/dataTransfer/transferData.component.ts b/utils/dataTransfer/transferData.component.ts index eacaa5aa..8bd841d9 100644 --- a/utils/dataTransfer/transferData.component.ts +++ b/utils/dataTransfer/transferData.component.ts @@ -43,8 +43,9 @@ export class EGIDataTransferComponent { destinationAuthUser = ""; destinationAuthPass = ""; destinationPath = ""; - destinationOptions = properties.eoscDataTransferDestinations; - selectedDestination:{label :string, id: string, auth: 'token' | 'password' | 'keys'} = null; + destinationOptions = properties.eoscDataTransferDestinations.map(dest => {return {"label": dest.destination, "value": dest}}); + selectedDestination:{ kind: string, destination: string, description: string, authType: 'token' | 'password' | 'keys', + canBrowse: boolean, transferWith: string} = null; folders = {}; files = {}; downloadElements = null; @@ -83,7 +84,7 @@ export class EGIDataTransferComponent { if(this.accessToken) { if (this.selectedDestinationId) { for (let option of this.destinationOptions) { - if (this.selectedDestinationId == option.value.id) { + if (this.selectedDestinationId == option.value.destination) { this.selectedDestination = option.value; } } @@ -167,7 +168,7 @@ export class EGIDataTransferComponent { // console.log(this.selectedDestination) this.status = "loading"; let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); - this.subscriptions.push(this.http.get(this.APIURL + "/user/info?dest="+this.selectedDestination.id, {headers: headers}).subscribe( + this.subscriptions.push(this.http.get(this.APIURL + "/user/info?dest="+this.selectedDestination.destination, {headers: headers}).subscribe( res => { // console.log(res) let body = { @@ -193,7 +194,7 @@ export class EGIDataTransferComponent { } let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); - if(this.selectedDestination.auth != "token" && this.destinationAuthPass.length > 0 && this.destinationAuthUser.length > 0){ + if(this.selectedDestination.authType != "token" && this.destinationAuthPass.length > 0 && this.destinationAuthUser.length > 0){ headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken, 'Authorization-Storage': btoa(this.destinationAuthUser + ':' + this.destinationAuthPass)}); } @@ -210,7 +211,7 @@ export class EGIDataTransferComponent { this.egiTransferModal.okButton = false; this.message = ` -
      Transfer of ` + this.downloadElements.length + ` files to `+this.selectedDestination.label+` has began.`; +
      Transfer of ` + this.downloadElements.length + ` files to `+this.selectedDestination.description+` has began.`; /*this.message += `
        `; @@ -264,7 +265,7 @@ export class EGIDataTransferComponent { this.jobStatus = res; this.message = ` -
        Transfer of ` + this.downloadElements.length + ` files to ` + this.selectedDestination.label+` has began.`; +
        Transfer of ` + this.downloadElements.length + ` files to ` + this.selectedDestination.description+` has began.`; /*this.message += `
          `; @@ -322,7 +323,7 @@ export class EGIDataTransferComponent { } hasBrowse(){ let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); - this.subscriptions.push(this.http.get(this.APIURL + "/storage/info?dest="+this.selectedDestination.id+"&seUrl="+encodeURIComponent(this.destinationUrl + this.destinationPath) , {headers: headers}).subscribe( + this.subscriptions.push(this.http.get(this.APIURL + "/storage/info?dest="+this.selectedDestination.destination+"&seUrl="+encodeURIComponent(this.destinationUrl + this.destinationPath) , {headers: headers}).subscribe( res => { console.log(res); } @@ -332,7 +333,7 @@ export class EGIDataTransferComponent { getFolder(folderPath){ //TODO is this necessary? let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); - this.subscriptions.push(this.http.get(this.APIURL + "/storage/folder?dest="+this.selectedDestination.id+"&seUrl="+encodeURIComponent(this.destinationUrl + folderPath) , {headers: headers}).subscribe( + this.subscriptions.push(this.http.get(this.APIURL + "/storage/folder?dest="+this.selectedDestination.destination+"&seUrl="+encodeURIComponent(this.destinationUrl + folderPath) , {headers: headers}).subscribe( res => { this.folders[folderPath]= res; this.folders[folderPath]['isOpen'] = true; @@ -347,7 +348,7 @@ export class EGIDataTransferComponent { } this.getFolder(folderPath); let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); - this.subscriptions.push(this.http.get(this.APIURL + "/storage/folder/list?dest="+this.selectedDestination.id+"&folderUrl="+encodeURIComponent(this.destinationUrl + folderPath) , {headers: headers}).subscribe( + this.subscriptions.push(this.http.get(this.APIURL + "/storage/folder/list?dest="+this.selectedDestination.destination+"&folderUrl="+encodeURIComponent(this.destinationUrl + folderPath) , {headers: headers}).subscribe( res => { this.files[folderPath]= res['elements']; } @@ -356,7 +357,7 @@ export class EGIDataTransferComponent { } createFolder(){ let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); - this.subscriptions.push(this.http.post(this.APIURL + "/storage/folder?dest="+this.selectedDestination.id+"&seUrl="+ + this.subscriptions.push(this.http.post(this.APIURL + "/storage/folder?dest="+this.selectedDestination.destination+"&seUrl="+ encodeURIComponent(this.destinationUrl + this.destinationPath + "test1/") , {headers: headers}).subscribe( res => { console.log(res); @@ -367,7 +368,7 @@ export class EGIDataTransferComponent { deleteFolder(){ let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); - this.subscriptions.push(this.http.delete(this.APIURL + "/storage/folder?dest="+this.selectedDestination.id+"&seUrl="+encodeURIComponent(this.destinationUrl + this.destinationPath + "test1/") , {headers: headers}).subscribe( + this.subscriptions.push(this.http.delete(this.APIURL + "/storage/folder?dest="+this.selectedDestination.destination+"&seUrl="+encodeURIComponent(this.destinationUrl + this.destinationPath + "test1/") , {headers: headers}).subscribe( res => { console.log(res); } From 3c20944aec78714d59265b1bfebea91b2cadbbb7 Mon Sep 17 00:00:00 2001 From: "konstantina.galouni" Date: Thu, 5 Jan 2023 19:14:26 +0200 Subject: [PATCH 06/16] [Library | data-transfer-v2]: transferData.component: Get destinationOptions from API (/storage/types). --- .../dataTransfer/transferData.component.html | 2 +- utils/dataTransfer/transferData.component.ts | 31 ++++++++++++------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/utils/dataTransfer/transferData.component.html b/utils/dataTransfer/transferData.component.html index 5ebc6e2a..972da1ae 100644 --- a/utils/dataTransfer/transferData.component.html +++ b/utils/dataTransfer/transferData.component.html @@ -43,7 +43,7 @@
        -
        +
        Testing:
        https://dcache-demo.desy.de:2443 diff --git a/utils/dataTransfer/transferData.component.ts b/utils/dataTransfer/transferData.component.ts index 8bd841d9..1070e809 100644 --- a/utils/dataTransfer/transferData.component.ts +++ b/utils/dataTransfer/transferData.component.ts @@ -43,14 +43,14 @@ export class EGIDataTransferComponent { destinationAuthUser = ""; destinationAuthPass = ""; destinationPath = ""; - destinationOptions = properties.eoscDataTransferDestinations.map(dest => {return {"label": dest.destination, "value": dest}}); + destinationOptions = null;//properties.eoscDataTransferDestinations.map(dest => {return {"label": dest.destination, "value": dest}}); selectedDestination:{ kind: string, destination: string, description: string, authType: 'token' | 'password' | 'keys', canBrowse: boolean, transferWith: string} = null; folders = {}; files = {}; downloadElements = null; @Input() isOpen = false; - @Input() selectedDestinationId = "dcache"; + // @Input() selectedDestinationId = "dcache"; @ViewChild('egiTransferModal') egiTransferModal; APIURL = properties.eoscDataTransferAPI; status: "loading" | "success" | "errorParser" | "errorUser" | "errorTransfer" | "init" | "canceled" = "init"; @@ -82,15 +82,24 @@ export class EGIDataTransferComponent { open(){ this.accessToken = COOKIE.getCookie("EGIAccessToken"); if(this.accessToken) { - if (this.selectedDestinationId) { - for (let option of this.destinationOptions) { - if (this.selectedDestinationId == option.value.destination) { - this.selectedDestination = option.value; - } + // if (this.selectedDestinationId) { + // for (let option of this.destinationOptions) { + // if (this.selectedDestinationId == option.value.destination) { + // this.selectedDestination = option.value; + // } + // } + // } else { + // this.selectedDestination = this.destinationOptions[0].value; + // } + + let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); + this.subscriptions.push(this.http.get(this.APIURL + "/storage/types", {headers: headers}).subscribe( + (res: Array) => { + this.destinationOptions = res.map(dest => {return {"label": dest.destination, "value": dest}}); + this.selectedDestination = res[0]; } - } else { - this.selectedDestination = this.destinationOptions[0].value; - } + )); + for (let doi of this.dois) { this.sourceUrls.push(this.doiPrefix + doi); @@ -129,7 +138,7 @@ export class EGIDataTransferComponent { } init(){ this.destinationPath = ""; - this.selectedDestination = this.destinationOptions[0].value; + // this.selectedDestination = this.destinationOptions[0].value; this.selectedSourceUrl = this.sourceUrls[0]; this.message = null; this.status = "init"; From 95a87dcefd5b40f729fecf5dcd2d9f3d241b48a7 Mon Sep 17 00:00:00 2001 From: "konstantina.galouni" Date: Mon, 13 Feb 2023 19:39:08 +0200 Subject: [PATCH 07/16] [Library | data-transfer-v2]: Use new transfer API to get destinations, do the transfer, request status of transfer | Updated messages and checks for buttons. --- .../dataTransfer/transferData.component.html | 61 +++--- utils/dataTransfer/transferData.component.ts | 207 ++++++++++++------ 2 files changed, 170 insertions(+), 98 deletions(-) diff --git a/utils/dataTransfer/transferData.component.html b/utils/dataTransfer/transferData.component.html index 972da1ae..96e524a7 100644 --- a/utils/dataTransfer/transferData.component.html +++ b/utils/dataTransfer/transferData.component.html @@ -9,8 +9,8 @@ -
        @@ -31,7 +31,7 @@

        Available DOI URLs:

        -
        +
        {{this.downloadElements.length}} files found:
          @@ -45,16 +45,16 @@
          - Testing:
          - https://dcache-demo.desy.de:2443 -
          - /Demonstrators/EOSC-Future/EGI/ -
          + + + + +

          Please select the Destination Storage technology:

          + [options]="destinationOptions" (valueChange)="folders = {}">

          Provide the corresponding storage destination url:

          @@ -69,7 +69,7 @@
          -
        @@ -79,8 +79,9 @@
        -

        or browse to +

        or browse to select a folder.

        @@ -93,29 +94,33 @@
        -
        -
        - - - + + +
        +
        + + + +
        +
        + + + +
        -
        -
        +
        -
        - -
        + + + +
        Transfer of ` + this.downloadElements.length + ` files to `+this.selectedDestination.description+` has began.`; @@ -237,27 +262,33 @@ export class EGIDataTransferComponent { this.message += `
        ` - // this.getStatus(true) + + this.cdr.detectChanges(); + HelperFunctions.scrollToId("transferAlert"); + + // this.getStatus(true) }, error => { - this.status = "errorTransfer"; - this.message = "Couldn't transfer files"; - UIkit.notification("Couldn't transfer files", { - status: 'error', - timeout: 6000, - pos: 'bottom-right' - }); + this.status = "failed"; + this.message = "Files could not be transfered."; + this.statusMessage = "danger"; + // UIkit.notification("Couldn't transfer files", { + // status: 'error', + // timeout: 6000, + // pos: 'bottom-right' + // }); } )); }, error => { this.status = "errorUser"; - this.message = "User can't be authenticated!"; - UIkit.notification("User can't be authenticated!", { - status: 'error', - timeout: 6000, - pos: 'bottom-right' - }); + this.message = "User cannot be authenticated."; + this.statusMessage = "danger"; + // UIkit.notification("User can't be authenticated!", { + // status: 'error', + // timeout: 6000, + // pos: 'bottom-right' + // }); } )); @@ -269,49 +300,82 @@ export class EGIDataTransferComponent { let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); let source = this.http.get(this.APIURL + "/transfer/" +this.jobId , {headers: headers}).pipe(delay(5000)); - this.subscriptions.push(source.pipe(repeat(3)).subscribe( - res => { - this.jobStatus = res; - this.message = ` - -
        Transfer of ` + this.downloadElements.length + ` files to ` + this.selectedDestination.description+` has began.`; - /*this.message += `
        -
          - `; - // TODO LATER we can call status for each file and see if the transfer has been complete - for(let element of this.downloadElements){ - // console.log(element) - // this.message += `
        • `+ element.name+ `
        • `; - this.message += `
        • `+ element.name+ `
        • `; - } - this.message += ` -
        -
        -
        `*/ - this.message += ` - -
        `; - console.log(res) - this.statusMessage = res['jobState'] + (res['reason']?(" :" + res['reason']):""); - UIkit.notification('got status! ', { - status: 'success', - timeout: 6000, - pos: 'bottom-right' - }); - + let source2 = interval(5000) // request status every 5 secs + .pipe( + startWith(2000), // first call after 2 secs + switchMap(() => this.http.get(this.APIURL + "/transfer/" +this.jobId , {headers: headers})) + ); + // this.subscriptions.push(source.pipe(repeat(3)).subscribe( + this.statusSub = source2.subscribe( + (res: any) => { + if(this.status != res.jobState) { + this.status = res.jobState; + this.jobStatus = res; + this.message = ` + +
        Transfer of ` + this.downloadElements.length + ` files to ` + this.selectedDestination.description + ` has began.`; + /*this.message += `
        +
          + `; + // TODO LATER we can call status for each file and see if the transfer has been complete + for(let element of this.downloadElements){ + // console.log(element) + // this.message += `
        • `+ element.name+ `
        • `; + this.message += `
        • `+ element.name+ `
        • `; + } + this.message += ` +
        +
        +
        `*/ + this.message += ` + +
        `; + this.statusMessage = "primary"; + this.statusMessage = res['jobState'] + (res['reason'] ? (" :" + res['reason']) : ""); + if(this.status == "succeeded") { + this.message = "Transfer successfully completed!"; + this.statusMessage = "success"; + this.statusSub.unsubscribe(); + // UIkit.notification('Transfer successfully completed! ', { + // status: 'success', + // timeout: 6000, + // pos: 'bottom-right' + // }); + } else if(this.status == "failed") { + this.message = "Transfer failed."; + this.statusMessage = "danger"; + this.statusSub.unsubscribe(); + // UIkit.notification('Transfer failed', { + // status: 'danger', + // timeout: 6000, + // pos: 'bottom-right' + // }); + } else if(this.status != "active") { + this.message = "Transfer completed with status: "+this.status+"."; + this.statusMessage = "warning"; + this.statusSub.unsubscribe(); + // UIkit.notification('Transfer completed with status: '+this.status, { + // status: 'warning', + // timeout: 6000, + // pos: 'bottom-right' + // }); + } + } }, error => { - this.status = "errorTransfer"; - this.message = "Couldn't get status "; - UIkit.notification("Couldn't get status", { - status: 'error', - timeout: 6000, - pos: 'bottom-right' - }); + this.status = "failed"; + this.message = "Status of the transfer could not be retrieved."; + this.statusMessage = "danger"; + this.statusSub.unsubscribe(); + // UIkit.notification("Couldn't get status", { + // status: 'error', + // timeout: 6000, + // pos: 'bottom-right' + // }); } - )); + ); } } @@ -321,7 +385,6 @@ export class EGIDataTransferComponent { let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); this.subscriptions.push(this.http.delete(this.APIURL + "/transfer/" +this.jobId , {headers: headers}).subscribe( res => { - console.log(res); this.jobStatus = res; this.statusMessage = res['jobState'] + (res['reason']?(" :" + res['reason']):""); this.jobId = null; @@ -401,4 +464,8 @@ export class EGIDataTransferComponent { return (this.destinationPath.length > 0 && this.destinationPath.match(exp1) != null) } + + validateDestinationUrl():boolean { + return (this.destinationUrl.length > 0 && StringUtils.isValidUrl(this.destinationUrl)); + } } From ed856076d4d3dc5d2430b49085dd915e373026c1 Mon Sep 17 00:00:00 2001 From: "konstantina.galouni" Date: Fri, 3 Mar 2023 15:12:26 +0200 Subject: [PATCH 08/16] [Library | data-transfer-v2]: transferData.component.ts: Check we are on client side to open the modal | [Bug fix] In error message. --- utils/dataTransfer/transferData.component.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/utils/dataTransfer/transferData.component.ts b/utils/dataTransfer/transferData.component.ts index 0418b214..1458a3b2 100644 --- a/utils/dataTransfer/transferData.component.ts +++ b/utils/dataTransfer/transferData.component.ts @@ -135,7 +135,9 @@ export class EGIDataTransferComponent { this.egiTransferModal.alertTitle = "EOSC data transfer service [demo]"; this.egiTransferModal.stayOpen = true; this.init(); - this.egiTransferModal.open(); + if(typeof document !== 'undefined') { + this.egiTransferModal.open(); + } } close(){ if(this.isOpen) { @@ -180,7 +182,7 @@ export class EGIDataTransferComponent { this.status = "init"; }, error => { this.status = "errorParser"; - this.message = error.error && error.error.id && error.error.id == 'doiNotSupported'?'DOI not supported.':( error.error && error.error.description && error.error.description? error.error.description+'.':'Error parsing information.') ; + this.message = error.error && error.error.id && error.error.id == 'doiNotSupported'?'DOI not supported.':( error.error && error.error.description && error.error.description? (error.error.description+'.'):'Error parsing information.') ; this.statusMessage = "danger"; /* UIkit.notification(this.message, { status: 'error', From cde97c09b928c619ca95341b00efcccaf664bc3f Mon Sep 17 00:00:00 2001 From: "konstantina.galouni" Date: Tue, 7 Mar 2023 13:17:36 +0200 Subject: [PATCH 09/16] [Library | data-transfer-v2]: transferData.component: Updated destination url check - for s3, protocol starts with s3://, not https://. --- utils/dataTransfer/transferData.component.html | 2 +- utils/dataTransfer/transferData.component.ts | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/utils/dataTransfer/transferData.component.html b/utils/dataTransfer/transferData.component.html index 96e524a7..afa70cc0 100644 --- a/utils/dataTransfer/transferData.component.html +++ b/utils/dataTransfer/transferData.component.html @@ -54,7 +54,7 @@

        Please select the Destination Storage technology:

        + [options]="destinationOptions" (valueChange)="folders = {}; sourceUrlValidators()">

        Provide the corresponding storage destination url:

        diff --git a/utils/dataTransfer/transferData.component.ts b/utils/dataTransfer/transferData.component.ts index 1458a3b2..7d41a003 100644 --- a/utils/dataTransfer/transferData.component.ts +++ b/utils/dataTransfer/transferData.component.ts @@ -110,6 +110,7 @@ export class EGIDataTransferComponent { (res: Array) => { this.destinationOptions = res.map(dest => {return {"label": dest.destination, "value": dest}}); this.selectedDestination = res[0]; + this.sourceUrlValidators(); } )); @@ -468,6 +469,18 @@ export class EGIDataTransferComponent { } validateDestinationUrl():boolean { + if(this.selectedDestination.destination == "s3") { + return (this.destinationUrl.length > 0 && new RegExp('s3:\/\/[a-zA-Z0-9]+').test(this.destinationUrl)); + } return (this.destinationUrl.length > 0 && StringUtils.isValidUrl(this.destinationUrl)); } + + public sourceUrlValidators() { + this.URLValidators = []; + if(this.selectedDestination.destination == 's3') { + this.URLValidators = [Validators.required, Validators.pattern('s3:\/\/[a-zA-Z0-9]+')]; + } else { + this.URLValidators = [Validators.required, StringUtils.urlValidator()]; + } + } } From 029db9f52eb0fb110429495d5669518e2ecef292 Mon Sep 17 00:00:00 2001 From: "konstantina.galouni" Date: Tue, 7 Mar 2023 15:43:49 +0200 Subject: [PATCH 10/16] [Library | data-transfer-v2]: transferData.component.ts: Scroll to message not only if transfer status was successful. --- utils/dataTransfer/transferData.component.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/utils/dataTransfer/transferData.component.ts b/utils/dataTransfer/transferData.component.ts index 7d41a003..2e979f7f 100644 --- a/utils/dataTransfer/transferData.component.ts +++ b/utils/dataTransfer/transferData.component.ts @@ -185,6 +185,8 @@ export class EGIDataTransferComponent { this.status = "errorParser"; this.message = error.error && error.error.id && error.error.id == 'doiNotSupported'?'DOI not supported.':( error.error && error.error.description && error.error.description? (error.error.description+'.'):'Error parsing information.') ; this.statusMessage = "danger"; + this.cdr.detectChanges(); + HelperFunctions.scrollToId("transferAlert"); /* UIkit.notification(this.message, { status: 'error', timeout: 3000, @@ -275,6 +277,8 @@ export class EGIDataTransferComponent { this.status = "failed"; this.message = "Files could not be transfered."; this.statusMessage = "danger"; + this.cdr.detectChanges(); + HelperFunctions.scrollToId("transferAlert"); // UIkit.notification("Couldn't transfer files", { // status: 'error', // timeout: 6000, @@ -287,6 +291,8 @@ export class EGIDataTransferComponent { this.status = "errorUser"; this.message = "User cannot be authenticated."; this.statusMessage = "danger"; + this.cdr.detectChanges(); + HelperFunctions.scrollToId("transferAlert"); // UIkit.notification("User can't be authenticated!", { // status: 'error', // timeout: 6000, From bb6707cc0d8486226415781861078ed0f67e2f28 Mon Sep 17 00:00:00 2001 From: "konstantina.galouni" Date: Fri, 10 Mar 2023 14:54:15 +0200 Subject: [PATCH 11/16] [Library | data-transfer-v2]: transferData.component.ts: Added class field "s3UrlRegex" and updated s3 regex to accept any url starting from s3://, https://, http://, www. --- utils/dataTransfer/transferData.component.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/utils/dataTransfer/transferData.component.ts b/utils/dataTransfer/transferData.component.ts index 2e979f7f..bb53b68e 100644 --- a/utils/dataTransfer/transferData.component.ts +++ b/utils/dataTransfer/transferData.component.ts @@ -71,6 +71,11 @@ export class EGIDataTransferComponent { jobId = null; statusMessage = null; jobStatus; + + public s3UrlRegex = 's3:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.' + + '[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|s3:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.' + + '[a-zA-Z0-9]+\.[^\s]{2,}' + constructor(private http: HttpClient, private location: Location, private _router: Router, private cdr: ChangeDetectorRef) { } @@ -476,7 +481,7 @@ export class EGIDataTransferComponent { validateDestinationUrl():boolean { if(this.selectedDestination.destination == "s3") { - return (this.destinationUrl.length > 0 && new RegExp('s3:\/\/[a-zA-Z0-9]+').test(this.destinationUrl)); + return (this.destinationUrl.length > 0 && new RegExp("("+this.s3UrlRegex+")|("+StringUtils.urlRegex+")").test(this.destinationUrl)); } return (this.destinationUrl.length > 0 && StringUtils.isValidUrl(this.destinationUrl)); } @@ -484,7 +489,9 @@ export class EGIDataTransferComponent { public sourceUrlValidators() { this.URLValidators = []; if(this.selectedDestination.destination == 's3') { - this.URLValidators = [Validators.required, Validators.pattern('s3:\/\/[a-zA-Z0-9]+')]; + this.URLValidators = [Validators.required, Validators.pattern("("+this.s3UrlRegex+")|("+StringUtils.urlRegex+")")]; + // this.URLValidators = [Validators.required, Validators.pattern(this.s3UrlRegex) || StringUtils.urlValidator]; + // this.URLValidators = [Validators.required, Validators.pattern(this.s3UrlRegex)]; } else { this.URLValidators = [Validators.required, StringUtils.urlValidator()]; } From 71b5964f2c241c60c100443838261c6047d84264 Mon Sep 17 00:00:00 2001 From: "konstantina.galouni" Date: Wed, 15 Mar 2023 10:53:19 +0200 Subject: [PATCH 12/16] [Library | data-transfer-v]: transferData.component: Updated input labels, added uk-grid-small for the two columns, destination url changed to destination system and protocol (https:// or s3://) is applied programmatically. --- .../dataTransfer/transferData.component.html | 19 ++++----- utils/dataTransfer/transferData.component.ts | 42 +++++++++---------- 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/utils/dataTransfer/transferData.component.html b/utils/dataTransfer/transferData.component.html index afa70cc0..94f3c27f 100644 --- a/utils/dataTransfer/transferData.component.html +++ b/utils/dataTransfer/transferData.component.html @@ -25,11 +25,11 @@
        You have requested to send the data corresponding to the DOI {{selectedSourceUrl.split(doiPrefix)[1]}} to a cloud storage using the EOSC Data Transfer service
        -
        +

        Available DOI URLs:

        -
        {{this.downloadElements.length}} files found:
        @@ -52,13 +52,12 @@

        Please select the - Destination Storage technology:

        -
        + Destination Storage type:

        +
        -

        Provide the - corresponding storage destination url:

        -
        Specify the destination system (e.g. hostname:8080):

        +
        -

        Provide the corresponding storage destination path:

        -
        Specify the destination path (e.g. /folder1/folder2):

        +

        or ) => { this.destinationOptions = res.map(dest => {return {"label": dest.destination, "value": dest}}); this.selectedDestination = res[0]; - this.sourceUrlValidators(); } )); @@ -138,7 +143,7 @@ export class EGIDataTransferComponent { this.egiTransferModal.cancelButton = false; this.egiTransferModal.okButton = true; this.egiTransferModal.okButtonText = ">> Transfer"; - this.egiTransferModal.alertTitle = "EOSC data transfer service [demo]"; + this.egiTransferModal.alertTitle = "EOSC data transfer [demo]"; this.egiTransferModal.stayOpen = true; this.init(); if(typeof document !== 'undefined') { @@ -208,6 +213,7 @@ export class EGIDataTransferComponent { this.status = "active"; this.message = ""; let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); + this.subscriptions.push(this.http.get(this.APIURL + "/user/info?dest="+this.selectedDestination.destination, {headers: headers}).subscribe( res => { // console.log(res) @@ -222,10 +228,9 @@ export class EGIDataTransferComponent { // console.log(this.selectedDestination) for (let element of this.downloadElements) { - let file = { "sources": [element['downloadUrl']], - "destinations": [this.destinationUrl + this.destinationPath + element.name], + "destinations": [(this.selectedDestination.destination == "s3" ? "s3://" : "https://") + this.destinationUrl + this.destinationPath + (this.destinationPath.endsWith("/") ? "" : "/") + element.name], }; //TODO priority? checksum? filesize? @@ -468,32 +473,23 @@ export class EGIDataTransferComponent { pathValidator(): ValidatorFn { return (control: AbstractControl): { [key: string]: string } | null => { if (!this.validatePath()) { - return {'error': 'Path should start and end with "/" e.g /path/'}; + return {'error': 'Path should start with "/" e.g /path'}; } return null; } } validatePath():boolean { - let exp1 = /^\/([A-z0-9-_+]+\/)*$/g; + let exp1 = /^\/([A-z0-9-_+])*$/g; return (this.destinationPath.length > 0 && this.destinationPath.match(exp1) != null) } validateDestinationUrl():boolean { - if(this.selectedDestination.destination == "s3") { - return (this.destinationUrl.length > 0 && new RegExp("("+this.s3UrlRegex+")|("+StringUtils.urlRegex+")").test(this.destinationUrl)); - } - return (this.destinationUrl.length > 0 && StringUtils.isValidUrl(this.destinationUrl)); + return (this.destinationUrl.length > 0 && new RegExp(this.hostnameRegex).test(this.destinationUrl)); } - public sourceUrlValidators() { - this.URLValidators = []; - if(this.selectedDestination.destination == 's3') { - this.URLValidators = [Validators.required, Validators.pattern("("+this.s3UrlRegex+")|("+StringUtils.urlRegex+")")]; - // this.URLValidators = [Validators.required, Validators.pattern(this.s3UrlRegex) || StringUtils.urlValidator]; - // this.URLValidators = [Validators.required, Validators.pattern(this.s3UrlRegex)]; - } else { - this.URLValidators = [Validators.required, StringUtils.urlValidator()]; - } - } + // public sourceUrlValidators() { + // this.URLValidators = []; + // this.URLValidators = [Validators.required, Validators.pattern(this.hostnameRegex)]; + // } } From aa5425d0910fd11a5b498760d2b04496be01cd36 Mon Sep 17 00:00:00 2001 From: "konstantina.galouni" Date: Thu, 16 Mar 2023 20:55:12 +0200 Subject: [PATCH 13/16] [Library | data-transfer-v2]: transferData.component.html: Updated labels - removed verbs & updated some checks based on new 'requests' field | transferData.component.ts: Get protocol from API for each storage & [Bug fix] in path validation & enhanced status values & updated how status request works - request max 10 times, expose always the status and after succeeding, failing or exceeding 10 requests, stop. --- .../dataTransfer/transferData.component.html | 18 ++- utils/dataTransfer/transferData.component.ts | 111 ++++++++++++++---- 2 files changed, 93 insertions(+), 36 deletions(-) diff --git a/utils/dataTransfer/transferData.component.html b/utils/dataTransfer/transferData.component.html index 94f3c27f..a92a4bd4 100644 --- a/utils/dataTransfer/transferData.component.html +++ b/utils/dataTransfer/transferData.component.html @@ -10,8 +10,8 @@ + || (requests > 0) || !validatePath() || !validateDestinationUrl() || (!this.downloadElements || this.downloadElements.length == 0)" + (alertOutput)="transfer()" (cancelOutput)="init()">

        In order to send data to a Cloud Storage, you would need to be authenticated, please login via EGI check-in. @@ -51,19 +51,17 @@ -

        Please select the - Destination Storage type:

        +

        Destination storage type:

        -

        Specify the destination system (e.g. hostname:8080):

        +

        Destination system (e.g. hostname:8080):

        -

        Provide - authentication if needed:

        +

        Authentication:

        -

        Specify the destination path (e.g. /folder1/folder2):

        +

        Destination path (e.g. /folder1/folder2):

        @@ -100,7 +98,7 @@ -
        - + (okEmitter)="transfer()" (cancelEmitter)="init()">
        -
        +
        In order to send data to a Cloud Storage, you would need to be authenticated, please login via EGI check-in.
        @@ -22,18 +22,18 @@
        -
        +
        You have requested to send the data corresponding to the DOI {{selectedSourceUrl.split(doiPrefix)[1]}} to a cloud storage using the EOSC Data Transfer service

        Available DOI URLs:

        -
        {{this.downloadElements.length}} files found:
        -
        +
        • {{ element.name}}
        • @@ -52,11 +52,11 @@

          Destination storage type:

          -

          Destination system (e.g. hostname:8080):

          -
          Authentication:

          Destination path (e.g. /folder1/folder2):

          -

          or browse to select a folder.

          -
          +
          @@ -88,12 +88,21 @@

          Comming soon!

          - + + +
        -
        +
        @@ -137,7 +146,7 @@ -->
        - + diff --git a/utils/dataTransfer/transferData.component.ts b/utils/dataTransfer/transferData.component.ts index 07378045..18876f96 100644 --- a/utils/dataTransfer/transferData.component.ts +++ b/utils/dataTransfer/transferData.component.ts @@ -9,6 +9,7 @@ import {properties} from "../../../../environments/environment"; import {delay, repeat, startWith, switchMap} from "rxjs/operators"; import {StringUtils} from "../string-utils.class"; import {HelperFunctions} from "../HelperFunctions.class"; +import {FullScreenModalComponent} from "../modal/full-screen-modal/full-screen-modal.component"; declare var UIkit; @Component({ @@ -54,7 +55,7 @@ export class EGIDataTransferComponent { downloadElements = null; @Input() isOpen = false; // @Input() selectedDestinationId = "dcache"; - @ViewChild('egiTransferModal') egiTransferModal; + @ViewChild('egiTransferModal') egiTransferModal: FullScreenModalComponent; APIURL = properties.eoscDataTransferAPI; // status: "loading" | "success" | "errorParser" | "errorUser" | "errorTransfer" | "init" | "canceled" = "init"; status: "unused" | "staging" | "submitted" | "active" | "succeeded" | "partial" | "failed" | "canceled" | "errorParser" | "errorUser" | "init" = "init"; @@ -122,7 +123,7 @@ export class EGIDataTransferComponent { let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); this.subscriptions.push(this.http.get(this.APIURL + "/storage/types", {headers: headers}).subscribe( (res: Array) => { - this.destinationOptions = res.map(dest => {return {"label": dest.destination, "value": dest}}); + this.destinationOptions = res.map(dest => {return {"label": dest.description, "value": dest}}); this.selectedDestination = res[0]; } )); @@ -143,11 +144,11 @@ export class EGIDataTransferComponent { this.parse(); } this.isOpen = true; + this.egiTransferModal.back = true; this.egiTransferModal.cancelButton = false; - this.egiTransferModal.okButton = true; + this.egiTransferModal.okButton = false; this.egiTransferModal.okButtonText = ">> Transfer"; - this.egiTransferModal.alertTitle = "EOSC Data Transfer [demo]"; - this.egiTransferModal.stayOpen = true; + this.egiTransferModal.title = "EOSC Data Transfer [demo]"; this.init(); if(typeof document !== 'undefined') { this.egiTransferModal.open(); @@ -241,7 +242,7 @@ export class EGIDataTransferComponent { for (let element of this.downloadElements) { let file = { "sources": [element['downloadUrl']], - "destinations": [(this.selectedDestination.protocol+"://") + this.destinationUrl + this.destinationPath + (this.destinationPath.endsWith("/") ? "" : "/") + element.name], + "destinations": [(this.selectedDestination.protocol+"://") + this.destinationUrl + this.destinationPath + (this.destinationPath.endsWith("/") ? "" : "/") + ((element.path && element.path != "/") ? element.path : "") + element.name], }; //TODO priority? checksum? filesize? diff --git a/utils/dataTransfer/transferData.module.ts b/utils/dataTransfer/transferData.module.ts index d78dd6d2..9267d368 100644 --- a/utils/dataTransfer/transferData.module.ts +++ b/utils/dataTransfer/transferData.module.ts @@ -4,10 +4,11 @@ import {FormsModule} from '@angular/forms'; import {EGIDataTransferComponent} from "./transferData.component"; import {InputModule} from "../../sharedComponents/input/input.module"; import {AlertModalModule} from "../modal/alertModal.module"; +import {FullScreenModalModule} from "../modal/full-screen-modal/full-screen-modal.module"; @NgModule({ imports: [ - CommonModule, FormsModule, InputModule, AlertModalModule + CommonModule, FormsModule, InputModule, AlertModalModule, FullScreenModalModule ], declarations: [ diff --git a/utils/modal/full-screen-modal/full-screen-modal.component.ts b/utils/modal/full-screen-modal/full-screen-modal.component.ts index 750286a0..07c542fb 100644 --- a/utils/modal/full-screen-modal/full-screen-modal.component.ts +++ b/utils/modal/full-screen-modal/full-screen-modal.component.ts @@ -31,12 +31,14 @@ declare var ResizeObserver; class="uk-width-expand uk-padding-small uk-padding-remove-vertical uk-flex uk-flex-center">

        {{title}}

        -
        +
        -
        @@ -58,6 +60,7 @@ export class FullScreenModalComponent implements AfterViewInit, OnDestroy { @Input() classBody: string = 'uk-container-large'; back: boolean = false; title: string; + cancelButton: boolean = true; okButton: boolean = false; okButtonText = 'OK'; @Input() From 806cec4043f9ecaa881c439f0c6c725766d91568 Mon Sep 17 00:00:00 2001 From: "konstantina.galouni" Date: Tue, 13 Jun 2023 16:10:06 +0300 Subject: [PATCH 15/16] Library | data-transfer-v2: transferData.component: Added checkbox in the form of accepting the data protection policy --- .../dataTransfer/transferData.component.html | 30 ++++++++++++------- utils/dataTransfer/transferData.component.ts | 2 ++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/utils/dataTransfer/transferData.component.html b/utils/dataTransfer/transferData.component.html index d73e67e8..8fd50ef7 100644 --- a/utils/dataTransfer/transferData.component.html +++ b/utils/dataTransfer/transferData.component.html @@ -64,12 +64,13 @@

        Authentication:

        +

        Destination path (e.g. /folder1/folder2):

        @@ -89,14 +90,23 @@

        Comming soon!

        - +
        + + + *I have read and accepted the data protection policy here. +
        + +
        + +
        diff --git a/utils/dataTransfer/transferData.component.ts b/utils/dataTransfer/transferData.component.ts index 3f2ee259..1062e910 100644 --- a/utils/dataTransfer/transferData.component.ts +++ b/utils/dataTransfer/transferData.component.ts @@ -75,6 +75,8 @@ export class EGIDataTransferComponent { statusMessage = null; jobStatus; + privacyAccepted: boolean = false; + public hostnameRegex = '[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|' + '[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|' + '[a-zA-Z0-9]+\.[^\s]{2,}|' + From 8a22f2a8ad357453335279d7404c950a734ee0ce Mon Sep 17 00:00:00 2001 From: "k.triantafyllou" Date: Wed, 14 Jun 2023 15:10:49 +0300 Subject: [PATCH 16/16] Add sources of number indicators in timeout_whitelist in order to avoid timeout error in these requests. --- timeout-interceptor.service.ts | 48 ++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/timeout-interceptor.service.ts b/timeout-interceptor.service.ts index d796a751..224e585e 100644 --- a/timeout-interceptor.service.ts +++ b/timeout-interceptor.service.ts @@ -1,7 +1,7 @@ import {Inject, Injectable, InjectionToken, PLATFORM_ID} from '@angular/core'; -import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { timeout } from 'rxjs/operators'; +import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http'; +import {Observable} from 'rxjs'; +import {timeout} from 'rxjs/operators'; import {isPlatformServer} from "@angular/common"; import {properties} from "../../environments/environment"; @@ -9,30 +9,32 @@ export const DEFAULT_TIMEOUT = new InjectionToken('defaultTimeout'); @Injectable() export class TimeoutInterceptor implements HttpInterceptor { - // timeout inside services for: properties.searchCrossrefAPIURL, properties.searchDataciteAPIURL - private static TIMEOUT_WHITELIST = [properties.csvAPIURL, properties.registryUrl, properties.claimsAPIURL, - properties.searchCrossrefAPIURL, properties.searchDataciteAPIURL]; - constructor(@Inject(DEFAULT_TIMEOUT) protected defaultTimeout: number, @Inject(PLATFORM_ID) private platformId: any) { - } + private static TIMEOUT_WHITELIST = [ + properties.csvAPIURL, properties.registryUrl, properties.claimsAPIURL, + properties.searchCrossrefAPIURL, properties.searchDataciteAPIURL, + properties.statisticsAPIURL, properties.searchAPIURLLAst, properties.monitorStatsFrameUrl]; - intercept(req: HttpRequest, next: HttpHandler): Observable> { - if (req.method !== 'GET' || this.isService(req, TimeoutInterceptor.TIMEOUT_WHITELIST)) { - return next.handle(req); + constructor(@Inject(DEFAULT_TIMEOUT) protected defaultTimeout: number, @Inject(PLATFORM_ID) private platformId: any) { } - let serverTime = properties.environment == "production" ? 3000 : 4000; - let clientTime = properties.environment == "production" ? 6000 : 12000; - const timeoutValue = isPlatformServer(this.platformId)?serverTime:clientTime;//req.headers.get('timeout') || this.defaultTimeout; - const timeoutValueNumeric = Number(timeoutValue); - return next.handle(req).pipe(timeout(timeoutValueNumeric)); - } + intercept(req: HttpRequest, next: HttpHandler): Observable> { + if (req.method !== 'GET' || this.isService(req, TimeoutInterceptor.TIMEOUT_WHITELIST)) { + return next.handle(req); + } - isService(req: HttpRequest, service: string | string[]):boolean { - if(Array.isArray(service)) { - return !!service.find(element => req.url.indexOf(element) !== -1); - } else { - return req.url.indexOf(service) !== -1; + let serverTime = properties.environment == "production" ? 3000 : 4000; + let clientTime = properties.environment == "production" ? 6000 : 12000; + const timeoutValue = isPlatformServer(this.platformId) ? serverTime : clientTime;//req.headers.get('timeout') || this.defaultTimeout; + const timeoutValueNumeric = Number(timeoutValue); + return next.handle(req).pipe(timeout(timeoutValueNumeric)); + } + + isService(req: HttpRequest, service: string | string[]): boolean { + if (Array.isArray(service)) { + return !!service.find(element => req.url.indexOf(element) !== -1); + } else { + return req.url.indexOf(service) !== -1; + } } - } }