import {Component, OnInit} from '@angular/core'; import {DOI, Identifier} from "../openaireLibrary/utils/string-utils.class"; import {EnvProperties} from "../openaireLibrary/utils/properties/env-properties"; import {ErrorCodes} from "../openaireLibrary/utils/properties/errorCodes"; import {Subscriber, timer} from "rxjs"; import {properties} from "../../environments/environment"; import {SearchResearchResultsService} from "../openaireLibrary/services/searchResearchResults.service"; import {map} from "rxjs/operators"; import {Filter} from "../openaireLibrary/searchPages/searchUtils/searchHelperClasses.class"; @Component({ selector: 'upload-dois', templateUrl: './upload-dois.component.html', styleUrls:['./upload-dois.component.less'] }) export class UploadDoisComponent implements OnInit { page: number = 1; size: number = 100; properties: EnvProperties = properties; public errorCodes: ErrorCodes = new ErrorCodes(); public warningMessage = ""; public infoMessage = ""; subscriptions = []; filesToUpload: Array; public select: boolean = true; public results = []; public resultsToShow = []; allIds: string[] = []; foundIds: string[] = []; existedIds: string[] = []; duplicateIds: string[] = []; duplicateIdsRow: number[] = []; notFoundIds: string[] = []; notFoundIdsRow: number[] = []; noValidIds: string[] = []; noValidIdsRow: number[] = []; showReport: boolean = false; errorMessage = ""; enableUpload: boolean = true; exceedsLimit = false; fileLimit = 5; stats = { open: 0, closed: 0, embargo: 0, restricted: 0, green:0, gold:0, hybrid:0, bronze:0, diamond:0 } accessModeFilter:Filter = null; accessRouteFilter:Filter = null; /*filterByAccessRouteOptions = [ {label: "Green OA", value: "route-green"}, {label: "Published in OA Diamond", value: "route-diamond"}, ]*/ sortByTitleAsc = true; keyword = ""; loading = false; showFound = true; constructor(private _searchResearchResultsService: SearchResearchResultsService) { } ngOnInit() { } ngOnDestroy() { this.subscriptions.forEach(subscription => { if (subscription instanceof Subscriber) { subscription.unsubscribe(); } }); } upload() { this.loading = true; this.enableUpload = false; this.showReport = false; this.errorMessage = ""; this.results = []; this.resultsToShow = []; this.sortByTitleAsc = true; this.keyword = ""; this.showFound = true; if (this.filesToUpload.length == 0) { this.errorMessage = "There is no selected file to upload."; return; } else { if (this.filesToUpload[0].name.indexOf(".csv") == -1 || (this.filesToUpload[0].type != "text/csv" && this.filesToUpload[0].type != "application/vnd.ms-excel")) { this.errorMessage = "No valid file type. The required type is CSV"; return; } } this.makeFileRequest(this.properties.utilsService + '/upload', [], this.filesToUpload).then((result) => { const rows = (result as any).split('\n'); // I have used space, you can use any thing. this.exceedsLimit = false; let invalid_rows = 0; this.duplicateIds = []; this.existedIds = []; this.allIds = []; this.foundIds = []; this.noValidIds = []; // this.results.slice(0, this.results.length); this.notFoundIds = []; if (rows.length > this.fileLimit) { this.exceedsLimit = true; } for (let i = 0; i < (rows.length); i++) { if (rows[i] && rows[i] != null && rows[i] != "") { const values = rows[i].split(','); let id = this.removeDoubleQuotes(values[0]); if (DOI.isValidDOI(id)) { id = Identifier.getRawDOIValue(id); // console.log(id, id.split("\r")[0]); id = id.split("\r")[0] if (this.allIds.indexOf(id) > -1) { this.duplicateIds.push(id); this.duplicateIdsRow.push(i + 1); } else { this.allIds.push(id); } } else { this.noValidIds.push(id); this.noValidIdsRow.push(i + 1); } } else { invalid_rows++; } } this.enableUpload = true; this.fetchAllResults(); }, (error) => { this.enableUpload = true; this.errorMessage = "An error occured."; this.handleError("Error uploading file", error); }); } private removeDoubleQuotes(value) { if (value.indexOf('"') == 0) { value = value.substring(1, value.length); } const index = +value.indexOf('"'); if (index == (value.length - 1) || index == (value.length - 2)) { value = value.substring(0, index); } return value; } private validateAccessMode(value) { const accessModes = ["OPEN", "CLOSED", "EMBARGO"]; return accessModes.indexOf(value) > -1; } fileChangeEvent(fileInput: any) { this.filesToUpload = >fileInput.target.files; this.upload(); } makeFileRequest(url: string, params: Array, files: Array) { return new Promise((resolve, reject) => { const formData: any = new FormData(); const xhr = new XMLHttpRequest(); for (let i = 0; i < files.length; i++) { formData.append("uploads[]", files[i], files[i].name); } xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if (xhr.status == 200) { resolve(xhr.response); } else { reject(xhr.response); } } } xhr.open("POST", url, true); xhr.send(formData); }); } fetchAllResults() { let page = 1; let timerSubscription = timer(0, 1000).pipe( map(() => { if ((page - 1) * this.size <= this.allIds.length) { this.fetchResultsByPage(page); // load data contains the http request page += 1; } else { this.stopFetching(timerSubscription); } }) ).subscribe(); this.subscriptions.push(timerSubscription); } stopFetching(timerSubscription) { timerSubscription.unsubscribe(); this.loading = false; } fetchResultsByPage(page) { let dois = this.allIds.slice((page - 1) * this.size, page * this.size); if (dois.length == 0) { return; } this.subscriptions.push(this._searchResearchResultsService.fetchByDOIs(dois).subscribe(data => { for (let result of data[1]) { let matchingDOI = this.findMatchingDoi(result.DOIs, dois); this.foundIds.push(matchingDOI); let showRes = { doi: matchingDOI, title: result.title.name, accessMode: result.title.accessMode, accessRoute:"gold", //TODO update when we have the values green: false, //TODO update when we have the values diamond: false, //TODO update when we have the values }; this.results.push(showRes) this.addStatsPerResult(showRes) console.log(showRes, this.stats) this.initFilters(); } if (data[0] < dois.length) { for (let doi of dois) { if (this.foundIds.indexOf(doi) == -1) { this.notFoundIds.push(doi); // this.results.push({doi: doi, title: null, accessMode: null, green: false, openAccessColor:null, diamond: false, accessRoute: null, found: false}) } } } this.resultsToShow = [...this.results]; })); } findMatchingDoi(resultDois, requestedDois) { for (let doi of resultDois) { if (requestedDois.indexOf(doi) != -1) { return doi; } } return null; } private handleError(message: string, error) { console.error("Upload error: " + message, error); } addStatsPerResult(result) { if(result.accessMode) { if (result.accessMode == "Open Access") { this.stats.open++; } if (result.accessMode == "Closed Access") { this.stats.closed++; } if (result.accessMode == "Embargo") { this.stats.embargo++; } if (result.accessMode == "Restricted") { this.stats.restricted++; } } //TDO add access routes stats if(result.accessRoute) { if (result.accessRoute == "gold") { this.stats.gold++; } if (result.accessRoute == "hybrid") { this.stats.hybrid++; } if (result.accessRoute == "bronze") { this.stats.bronze++; } } } updatePage(page) { this.page = page; } updateKeyword(keyword){ this.keyword = keyword; this.updateView(); } updateView() { this.resultsToShow = [...this.results]; this.resultsToShow = this.filterResultsByAccessMode(); this.resultsToShow = this.filterResultsByAccessRoute(); if(this.keyword.length > 0){ this.resultsToShow = this.filterResultsByKeyword(); } this.resultsToShow= this.sortResults(); } filterResultsByAccessMode() { if (this.accessModeFilter.countSelectedValues > 0) { for (let value of this.accessModeFilter.values) { if (value.selected == true) { return this.resultsToShow.filter(res => { return res.accessMode == value.id; }); } } } return this.resultsToShow; } filterResultsByAccessRoute() { if (this.accessRouteFilter.countSelectedValues > 0) { for (let value of this.accessRouteFilter.values) { if (value.selected == true) { return this.resultsToShow.filter(res => { return res.accessRoute == value.id; }); } } } return this.resultsToShow; } /*filterResults() { return this.results.filter(res =>{ if(this.filterBy == "route-green") { return res.green; }else if(this.filterBy == "route-diamond") { return res.diamond; }else{ return true; } }) }*/ filterResultsByKeyword() { return this.resultsToShow.filter(res =>{ return (res.title && res.title.toLowerCase().indexOf(this.keyword.toLowerCase()) !=-1); }) } sortResults(){ this.sortByTitleAsc =! this.sortByTitleAsc; return this.resultsToShow.sort((n1, n2) => { if (n1.title && n2.title && ((!this.sortByTitleAsc && n1.title > n2.title) || (this.sortByTitleAsc && n1.title < n2.title))) { return 1; } if (n1.title && n2.title && ((this.sortByTitleAsc && n1.title > n2.title) || (!this.sortByTitleAsc && n1.title < n2.title))) { return -1; } return 0; }) } getercentage(number, foundIds = true){ if(!number){ return ""; } let from = foundIds?this.foundIds.length:this.allIds.length var num = new Number((number/from)*100); return num == 100?100:num.toPrecision(2); } initFilters(){ this.accessModeFilter = { countSelectedValues: 0, filterId: "access-mode", filterOperator: "or", filterType: "radio", originalFilterId: "", title: "Access Mode", valueIsExact: false, values:[ {name: "Open Access", id: "Open Access", selected:false, number:this.stats["open"]}, {name: "Embargo", id: "Embargo", selected:false, number:this.stats["embargo"]}, {name: "Restricted", id: "Restricted", selected:false, number:this.stats["restricted"]}, {name: "Closed", id: "Closed", selected:false, number:this.stats["closed"]} ]}; this.accessRouteFilter = { countSelectedValues: 0, filterId: "access-route", filterOperator: "or", filterType: "radio", originalFilterId: "", title: "Access Route", valueIsExact: false, values:[ {name: "Gold", id: "route-gold", selected:false, number:this.stats["gold"]}, {name: "Hybrid", id: "route-hybrid", selected:false, number:this.stats["hybrid"]}, {name: "Bronze", id: "route-bronze", selected:false, number:this.stats["bronze"]} ]}; } }