2022-05-25 11:52:00 +02:00
import { Component , Input , ViewChild } from '@angular/core' ;
2022-05-19 11:15:52 +02:00
import { Subscriber } from "rxjs" ;
import { HttpClient , HttpHeaders } from "@angular/common/http" ;
2022-05-24 13:24:54 +02:00
import { AbstractControl , ValidatorFn , Validators } from "@angular/forms" ;
2022-05-19 11:15:52 +02:00
import { Location } from '@angular/common' ;
import { COOKIE } from "../../login/utils/helper.class" ;
import { Router } from "@angular/router" ;
2022-05-23 11:54:34 +02:00
import { properties } from "../../../../environments/environment" ;
2022-09-21 16:29:46 +02:00
import { delay , repeat } from "rxjs/operators" ;
2022-05-19 11:15:52 +02:00
declare var UIkit ;
@Component ( {
selector : 'egi-transfer-data' ,
2022-10-17 11:42:01 +02:00
templateUrl : './transferData.component.html' ,
styles : [ `
/*Arrow*/
/ * . s o u r c e : f i r s t - c h i l d : : a f t e r {
content : "" ;
font - size : 20px ;
font - weight : 600 ;
text - align : center ;
padding - bottom : 5 % ;
position : absolute ;
background - image : url ( '/assets/arrow.svg' ) ;
right : - 16 % ;
top : 33 % ;
width : 20 % ;
background - size : contain ;
background - repeat : no - repeat ;
background - position : bottom ;
} * /
` ]
2022-05-19 11:15:52 +02:00
} )
export class EGIDataTransferComponent {
subscriptions = [ ] ;
2022-10-14 12:32:11 +02:00
accessToken = null ;
2022-05-19 11:15:52 +02:00
@Input ( ) dois ;
2022-11-11 10:20:02 +01:00
loginURL = properties . eoscDataTransferLoginUrl ;
2022-10-05 15:52:04 +02:00
sourceUrls = [ ] ;
2022-05-19 11:15:52 +02:00
selectedSourceUrl = null ;
2022-10-05 15:52:04 +02:00
destinationPath = "" ;
destinationOptions = properties . eoscDataTransferDestinations ;
2022-05-19 11:15:52 +02:00
selectedDestination = null ;
2022-10-05 15:52:04 +02:00
folders = { } ;
files = { } ;
2022-05-19 11:15:52 +02:00
downloadElements = null ;
@Input ( ) isOpen = false ;
2022-10-05 15:52:04 +02:00
@Input ( ) selectedDestinationId = "dcache" ;
2022-05-25 11:52:00 +02:00
@ViewChild ( 'egiTransferModal' ) egiTransferModal ;
2022-10-05 15:52:04 +02:00
APIURL = properties . eoscDataTransferAPI ;
2022-09-21 16:29:46 +02:00
status : "loading" | "success" | "errorParser" | "errorUser" | "errorTransfer" | "init" | "canceled" = "init" ;
2022-05-19 11:15:52 +02:00
message ;
2022-05-23 11:54:34 +02:00
doiPrefix = properties . doiURL ;
2022-05-24 13:24:54 +02:00
validators = [ Validators . required , this . pathValidator ( ) /*StringUtils.urlValidator()*/ ] ;
2022-09-21 16:29:46 +02:00
jobId = null ;
statusMessage = null ;
jobStatus ;
2022-05-19 11:15:52 +02:00
constructor ( private http : HttpClient , private location : Location , private _router : Router ) {
}
2022-05-25 11:52:00 +02:00
ngAfterViewInit() {
2022-05-19 11:15:52 +02:00
if ( this . isOpen ) {
this . open ( ) ;
}
}
ngOnDestroy() {
this . subscriptions . forEach ( subscription = > {
if ( subscription instanceof Subscriber ) {
subscription . unsubscribe ( ) ;
}
} ) ;
}
open ( ) {
2022-10-14 12:32:11 +02:00
this . accessToken = COOKIE . getCookie ( "EGIAccessToken" ) ;
if ( this . accessToken ) {
if ( this . selectedDestinationId ) {
for ( let option of this . destinationOptions ) {
if ( this . selectedDestinationId == option . value . id ) {
this . selectedDestination = option . value ;
}
2022-05-23 11:54:34 +02:00
}
2022-10-14 12:32:11 +02:00
} else {
this . selectedDestination = this . destinationOptions [ 0 ] . value ;
2022-05-19 11:15:52 +02:00
}
2022-10-14 12:32:11 +02:00
for ( let doi of this . dois ) {
this . sourceUrls . push ( this . doiPrefix + doi ) ;
}
try {
this . sourceUrls . sort ( function ( a , b ) {
return Number ( b . split ( "zenodo." ) [ 1 ] ) - Number ( a . split ( "zenodo." ) [ 1 ] ) ;
} ) ;
} catch ( e ) {
2022-10-05 15:52:04 +02:00
}
2022-10-14 12:32:11 +02:00
this . selectedSourceUrl = this . sourceUrls [ 0 ] ;
2022-10-05 15:52:04 +02:00
2022-10-14 12:32:11 +02:00
this . parse ( ) ;
}
2022-05-19 11:15:52 +02:00
this . isOpen = true ;
2022-05-25 11:52:00 +02:00
this . egiTransferModal . cancelButton = false ;
2022-10-17 11:42:01 +02:00
this . egiTransferModal . okButton = true ;
this . egiTransferModal . okButtonText = ">> Transfer" ;
2022-05-25 16:56:00 +02:00
this . egiTransferModal . alertTitle = "EOSC data transfer service [demo]" ;
2022-11-11 10:04:52 +01:00
this . egiTransferModal . stayOpen = true ;
2022-09-21 16:29:46 +02:00
this . init ( ) ;
2022-05-25 11:52:00 +02:00
this . egiTransferModal . open ( ) ;
2022-05-19 11:15:52 +02:00
}
close ( ) {
2022-05-25 11:52:00 +02:00
if ( this . isOpen ) {
this . isOpen = false ;
this . egiTransferModal . cancel ( ) ;
}
2022-05-19 11:15:52 +02:00
// this.downloadElements = [];
2022-09-21 16:29:46 +02:00
this . init ( ) ;
if ( this . _router . url . indexOf ( "&egiTransfer" ) ) {
this . location . go ( this . _router . url . split ( "&egiTransfer" ) [ 0 ] ) ;
}
}
init ( ) {
2022-05-19 11:15:52 +02:00
this . destinationPath = "" ;
this . selectedDestination = this . destinationOptions [ 0 ] . value ;
this . selectedSourceUrl = this . sourceUrls [ 0 ] ;
this . message = null ;
this . status = "init" ;
2022-09-21 16:29:46 +02:00
this . jobId = null ;
this . statusMessage = null ;
2022-05-19 11:15:52 +02:00
}
checkin ( ) {
2022-05-30 12:56:14 +02:00
window . location . href = this . loginURL + "?redirect=" + encodeURIComponent ( window . location . href + ( window . location . href . indexOf ( "&egiTransfer=t" ) != - 1 ? "" : "&egiTransfer=t" ) ) ;
2022-05-19 11:15:52 +02:00
}
parse ( ) {
2022-05-23 11:54:34 +02:00
this . status = "loading" ;
this . message = null ;
this . downloadElements = [ ] ;
2022-08-08 11:47:14 +02:00
this . subscriptions . push ( this . http . get ( this . APIURL + "/parser?doi=" + encodeURIComponent ( this . selectedSourceUrl ) ) . subscribe (
2022-05-19 11:15:52 +02:00
res = > {
2022-05-24 13:24:54 +02:00
this . downloadElements = res [ 'elements' ]
2022-05-23 11:54:34 +02:00
// console.log(this.downloadElements)
this . status = "init" ;
2022-05-19 11:15:52 +02:00
} , error = > {
this . status = "errorParser" ;
2022-11-11 10:55:15 +01:00
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 , {
2022-05-19 11:15:52 +02:00
status : 'error' ,
2022-05-23 11:54:34 +02:00
timeout : 3000 ,
2022-05-19 11:15:52 +02:00
pos : 'bottom-right'
} ) ;
}
) ) ;
}
transfer() {
2022-05-25 11:52:00 +02:00
// console.log(this.selectedDestination)
2022-05-19 11:15:52 +02:00
this . status = "loading" ;
2022-10-14 12:32:11 +02:00
let headers = new HttpHeaders ( { 'Authorization' : 'Bearer ' + this . accessToken } ) ;
2022-09-07 13:39:54 +02:00
this . subscriptions . push ( this . http . get ( this . APIURL + "/user/info?dest=" + this . selectedDestination . id , { headers : headers } ) . subscribe (
2022-05-19 11:15:52 +02:00
res = > {
2022-05-23 11:54:34 +02:00
// console.log(res)
2022-05-19 11:15:52 +02:00
let body = {
"files" : [ ] ,
"params" : {
"priority" : 0 ,
"overwrite" : true ,
"retry" : 3
}
} ;
2022-05-23 11:54:34 +02:00
// console.log(this.selectedDestination)
2022-05-19 11:15:52 +02:00
for ( let element of this . downloadElements ) {
let file = {
2022-05-23 11:54:34 +02:00
"sources" : [ element [ 'downloadUrl' ] ] ,
"destinations" : [ this . selectedDestination . url + this . destinationPath + element . name ] ,
2022-05-19 11:15:52 +02:00
} ;
2022-05-23 11:54:34 +02:00
//TODO priority? checksum? filesize?
// "filesize": element['size']
2022-05-19 11:15:52 +02:00
body . files . push ( file ) ;
}
2022-10-14 12:32:11 +02:00
let headers = new HttpHeaders ( { 'Authorization' : 'Bearer ' + this . accessToken } ) ;
2022-08-08 11:47:14 +02:00
this . subscriptions . push ( this . http . post ( this . APIURL + "/transfers" , body , { headers : headers } ) . subscribe (
2022-05-19 11:15:52 +02:00
res = > {
2022-05-23 11:54:34 +02:00
// console.log(res)
2022-05-19 11:15:52 +02:00
UIkit . notification ( 'Data transfer has began! ' , {
status : 'success' ,
timeout : 6000 ,
pos : 'bottom-right'
} ) ;
2022-09-21 16:29:46 +02:00
this . jobId = res [ 'jobId' ] ;
this . status = "success" ;
2022-11-11 10:04:52 +01:00
this . egiTransferModal . okButton = false ;
2022-05-19 11:15:52 +02:00
this . message = `
2022-08-08 11:47:14 +02:00
<!-- div class = "uk-text-large uk-margin-bottom" > Data transfer has began ! < / d i v - - >
< div > Transfer of ` + this.downloadElements.length + ` files to < a href = "`+ this.selectedDestination.webpage + `" target = _blank > ` +this.selectedDestination.label+ ` < / a > has began . ` ;
/ * t h i s . m e s s a g e + = ` < d i v c l a s s = " u k - o v e r f l o w - a u t o u k - h e i g h t - x s m a l l " >
2022-05-19 11:15:52 +02:00
< ul >
` ;
// TODO LATER we can call status for each file and see if the transfer has been complete
for ( let element of this . downloadElements ) {
2022-05-23 11:54:34 +02:00
// console.log(element)
// this.message += ` <li> <a href="`+ this.selectedDestination.webpage + this.destinationPath + element.name + `" target="_blank">`+ element.name+ `</a></li> `;
this . message += ` <li> ` + element . name + ` </li> ` ;
2022-05-19 11:15:52 +02:00
}
this . message += `
< / ul >
2022-05-24 13:24:54 +02:00
< / div >
2022-08-08 11:47:14 +02:00
< / div > ` */
this . message += `
2022-05-19 11:15:52 +02:00
< / div > `
2022-09-21 16:29:46 +02:00
// this.getStatus(true)
2022-05-19 11:15:52 +02:00
} , error = > {
this . status = "errorTransfer" ;
this . message = "Couldn't transfer files" ;
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'
} ) ;
}
) ) ;
}
2022-09-21 16:29:46 +02:00
getStatus ( updateTransferMessage :boolean = false ) {
if ( this . jobId ) {
2022-10-14 12:32:11 +02:00
let headers = new HttpHeaders ( { 'Authorization' : 'Bearer ' + this . accessToken } ) ;
2022-09-21 16:29:46 +02:00
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 = `
<!-- div class = "uk-text-large uk-margin-bottom" > Data transfer has began ! < / d i v - - >
< div > Transfer of ` + this.downloadElements.length + ` files to < a href = "`+ this.selectedDestination.webpage + `" target = _blank > ` +this.selectedDestination.label+ ` < / a > has began . ` ;
/ * t h i s . m e s s a g e + = ` < d i v c l a s s = " u k - o v e r f l o w - a u t o u k - h e i g h t - x s m a l l " >
< ul >
` ;
// 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 += ` <li> <a href="`+ this.selectedDestination.webpage + this.destinationPath + element.name + `" target="_blank">`+ element.name+ `</a></li> `;
this . message += ` <li> ` + element . name + ` </li> ` ;
}
this . message += `
< / ul >
< / div >
< / div > ` */
this . message += `
< / div > ` ;
console . log ( res )
this . statusMessage = res [ 'jobState' ] + ( res [ 'reason' ] ? ( " :" + res [ 'reason' ] ) : "" ) ;
UIkit . notification ( 'got status! ' , {
status : 'success' ,
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'
} ) ;
}
) ) ;
}
}
cancel ( ) {
if ( this . jobId ) {
2022-10-14 12:32:11 +02:00
let headers = new HttpHeaders ( { 'Authorization' : 'Bearer ' + this . accessToken } ) ;
2022-09-21 16:29:46 +02:00
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 ;
this . status = "canceled" ;
}
) ) ;
}
}
2022-10-05 15:52:04 +02:00
hasBrowse ( ) {
2022-10-14 12:32:11 +02:00
let headers = new HttpHeaders ( { 'Authorization' : 'Bearer ' + this . accessToken } ) ;
2022-10-05 15:52:04 +02:00
this . subscriptions . push ( this . http . get ( this . APIURL + "/storage/info?dest=" + this . selectedDestination . id + "&seUrl=" + encodeURIComponent ( this . selectedDestination . url + this . destinationPath ) , { headers : headers } ) . subscribe (
2022-09-21 16:29:46 +02:00
res = > {
console . log ( res ) ;
}
) ) ;
2022-10-05 15:52:04 +02:00
}
getFolder ( folderPath ) {
2022-10-14 12:32:11 +02:00
//TODO is this necessary?
let headers = new HttpHeaders ( { 'Authorization' : 'Bearer ' + this . accessToken } ) ;
2022-10-05 15:52:04 +02:00
this . subscriptions . push ( this . http . get ( this . APIURL + "/storage/folder?dest=" + this . selectedDestination . id + "&seUrl=" + encodeURIComponent ( this . selectedDestination . url + folderPath ) , { headers : headers } ) . subscribe (
res = > {
this . folders [ folderPath ] = res ;
this . folders [ folderPath ] [ 'isOpen' ] = true ;
}
) ) ;
}
browseFolder ( folderPath ) {
if ( this . folders [ folderPath ] ) {
this . folders [ folderPath ] . isOpen = ! this . folders [ folderPath ] . isOpen ;
return ;
}
this . getFolder ( folderPath ) ;
2022-10-14 12:32:11 +02:00
let headers = new HttpHeaders ( { 'Authorization' : 'Bearer ' + this . accessToken } ) ;
2022-10-05 15:52:04 +02:00
this . subscriptions . push ( this . http . get ( this . APIURL + "/storage/folder/list?dest=" + this . selectedDestination . id + "&folderUrl=" + encodeURIComponent ( this . selectedDestination . url + folderPath ) , { headers : headers } ) . subscribe (
res = > {
this . files [ folderPath ] = res [ 'elements' ] ;
}
) ) ;
}
createFolder ( ) {
2022-10-14 12:32:11 +02:00
let headers = new HttpHeaders ( { 'Authorization' : 'Bearer ' + this . accessToken } ) ;
2022-10-05 15:52:04 +02:00
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 (
res = > {
console . log ( res ) ;
}
) ) ;
}
deleteFolder ( ) {
2022-10-14 12:32:11 +02:00
let headers = new HttpHeaders ( { 'Authorization' : 'Bearer ' + this . accessToken } ) ;
2022-10-05 15:52:04 +02:00
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 (
res = > {
console . log ( res ) ;
}
) ) ;
2022-09-21 16:29:46 +02:00
}
2022-05-19 11:15:52 +02:00
private parseFilename ( url ) {
let filename = url . split ( "/" ) [ url . split ( "/" ) . length - 1 ] ;
return filename . split ( "?" ) [ 0 ] ;
}
2022-05-25 16:56:00 +02:00
pathValidator ( ) : ValidatorFn {
2022-05-24 13:24:54 +02:00
return ( control : AbstractControl ) : { [ key : string ] : string } | null = > {
2022-05-25 16:56:00 +02:00
if ( ! this . validatePath ( ) ) {
2022-05-24 13:24:54 +02:00
return { 'error' : 'Path should start and end with "/" e.g /path/' } ;
}
return null ;
}
}
2022-05-25 16:56:00 +02:00
validatePath ( ) : boolean {
let exp1 = /^\/([A-z0-9-_+]+\/)*$/g ;
return ( this . destinationPath . length > 0 && this . destinationPath . match ( exp1 ) != null )
}
2022-05-19 11:15:52 +02:00
}