import {Component, Input, ViewChild} from '@angular/core'; import {Subscriber} from "rxjs"; import {HttpClient, HttpHeaders} from "@angular/common/http"; import {AbstractControl, ValidatorFn, Validators} from "@angular/forms"; import {Location} from '@angular/common'; import {COOKIE} from "../../login/utils/helper.class"; import {Router} from "@angular/router"; import {properties} from "../../../../environments/environment"; import {delay, repeat} from "rxjs/operators"; declare var UIkit; @Component({ selector: 'egi-transfer-data', templateUrl:'./transferData.component.html' , styles:[` /*Arrow*/ /*.source:first-child::after { 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; }*/ `] }) 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" sourceUrls = []; selectedSourceUrl = null; destinationPath = ""; destinationOptions = properties.eoscDataTransferDestinations; selectedDestination = null; folders = {}; files = {}; downloadElements = null; @Input() isOpen = false; @Input() selectedDestinationId = "dcache"; @ViewChild('egiTransferModal') egiTransferModal; APIURL = properties.eoscDataTransferAPI; status: "loading" | "success" | "errorParser" | "errorUser" | "errorTransfer" | "init" | "canceled" = "init"; message; doiPrefix = properties.doiURL; validators = [Validators.required, this.pathValidator() /*StringUtils.urlValidator()*/]; jobId = null; statusMessage = null; jobStatus; constructor(private http: HttpClient, private location: Location, private _router: Router) { } ngAfterViewInit() { if(this.isOpen && typeof document !== 'undefined'){ this.open(); } } ngOnDestroy() { this.subscriptions.forEach(subscription => { if (subscription instanceof Subscriber) { subscription.unsubscribe(); } }); } open(){ 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; } } } else { this.selectedDestination = this.destinationOptions[0].value; } for (let doi of this.dois) { if (doi.indexOf("zenodo.") != -1) { 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) { } this.selectedSourceUrl = this.sourceUrls[0]; this.parse(); } this.isOpen = true; this.egiTransferModal.cancelButton = false; this.egiTransferModal.okButton = true; this.egiTransferModal.okButtonText = ">> Transfer"; this.egiTransferModal.alertTitle = "EOSC data transfer service [demo]"; this.egiTransferModal.stayOpen = true; this.init(); this.egiTransferModal.open(); } close(){ if(this.isOpen) { this.isOpen = false; this.egiTransferModal.cancel(); } // this.downloadElements = []; this.init(); if(this._router.url.indexOf("&egiTransfer")){ this.location.go(this._router.url.split("&egiTransfer")[0]); } } init(){ this.destinationPath = ""; this.selectedDestination = this.destinationOptions[0].value; this.selectedSourceUrl = this.sourceUrls[0]; this.message = null; this.status = "init"; this.jobId = null; this.statusMessage = null; } checkin(){ window.location.href = this.loginURL+"?redirect="+ encodeURIComponent(window.location.href + (window.location.href.indexOf("&egiTransfer=t")!=-1?"":"&egiTransfer=t")); } parse(){ this.status = "loading"; this.message = null; this.downloadElements = []; this.subscriptions.push(this.http.get(this.APIURL + "/parser?doi=" + encodeURIComponent(this.selectedSourceUrl)).subscribe( res => { this.downloadElements= res['elements'] // console.log(this.downloadElements) 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", { status: 'error', timeout: 3000, pos: 'bottom-right' }); } )); } transfer() { // 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( res => { // console.log(res) let body = { "files": [], "params": { "priority": 0, "overwrite": true, "retry": 3 } }; // console.log(this.selectedDestination) for (let element of this.downloadElements) { let file = { "sources": [element['downloadUrl']], "destinations": [this.selectedDestination.url + this.destinationPath + element.name], }; //TODO priority? checksum? filesize? // "filesize": element['size'] body.files.push(file); } let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken}); this.subscriptions.push(this.http.post(this.APIURL + "/transfers" ,body, {headers: headers}).subscribe( res => { // console.log(res) UIkit.notification('Data transfer has began! ', { status: 'success', timeout: 6000, pos: 'bottom-right' }); this.jobId = res['jobId']; this.status = "success"; this.egiTransferModal.okButton = false; this.message = `
Transfer of ` + this.downloadElements.length + ` files to `+this.selectedDestination.label+` has began.`; /*this.message += `
`*/ this.message += ` ` // 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' }); } )); }, 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' }); } )); } getStatus(updateTransferMessage:boolean = false){ if(this.jobId){ 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.label+` has began.`; /*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' }); }, 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){ 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; this.status = "canceled"; } )); } } 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( res => { console.log(res); } )); } 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( 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); 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( res => { this.files[folderPath]= res['elements']; } )); } 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( res => { console.log(res); } )); } 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( res => { console.log(res); } )); } private parseFilename(url){ let filename = url.split("/")[url.split("/").length - 1]; return filename.split("?")[0]; } pathValidator(): ValidatorFn { return (control: AbstractControl): { [key: string]: string } | null => { if (!this.validatePath()) { return {'error': 'Path should start and end with "/" e.g /path/'}; } return null; } } validatePath():boolean { let exp1 = /^\/([A-z0-9-_+]+\/)*$/g; return (this.destinationPath.length > 0 && this.destinationPath.match(exp1) != null) } }