Project

General

Profile

1
import {Component, Input, ViewChild} from '@angular/core';
2
import {SearchCrossrefService} from '../../claim-utils/service/searchCrossref.service';
3
import {SearchDataciteService} from '../../claim-utils/service/searchDatacite.service';
4

    
5
import {ModalLoading} from '../../../utils/modal/loading.component';
6
import {Dates, DOI} from '../../../utils/string-utils.class';
7
import {EnvProperties} from '../../../utils/properties/env-properties';
8
import {ClaimEntity} from "../../claim-utils/claimHelper.class";
9

    
10
declare var UIkit: any;
11

    
12

    
13
@Component({
14
  selector: 'bulk-claim',
15
  template: `
16
    <div class="uk-animation uk-text-center" style=" ">
17
      <form class=" ">
18

    
19
        <div>
20
          <div>
21
            <!--div class="uk-text-lead">Upload a DOI csv file <helper  div="link-result-bulk" tooltip=true ></helper></div>
22
            <label for="exampleInputFile">Select a file: </label-->
23
            <div class="js-upload" uk-form-custom>
24
              <input id="exampleInputFile" class="uk-width-medium" type="file" (change)="fileChangeEvent($event)"/>
25
              <span class="uk-link " style="text-decoration: underline;">Upload a DOI's CSV file </span>
26
              <!--button class="uk-button  portal-button" type="button" tabindex="-1" [class.disabled]="!enableUpload" ><span class="uk-margin-small-right uk-icon"  >
27
              <svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <polyline fill="none" stroke="#000" points="5 8 9.5 3.5 14 8 "></polyline> <rect x="3" y="17" width="13" height="1"></rect>
28
               <line fill="none" stroke="#000" x1="9.5" y1="15" x2="9.5" y2="4"></line></svg></span> Select</button-->
29
              <!--helper  div="link-result-bulk" tooltip=true ></helper-->
30
            </div>
31

    
32

    
33
            <div *ngIf="showReport" uk-alert class="uk-alert uk-alert-primary" role="alert">
34
              <a class="uk-alert-close uk-icon uk-close">
35
                <svg width="14" height="14" viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"
36
                     data-svg="close-icon">
37
                  <line fill="none" stroke="#000" stroke-width="1.1" x1="1" y1="1" x2="13" y2="13"></line>
38
                  <line fill="none" stroke="#000" stroke-width="1.1" x1="13" y1="1" x2="1" y2="13"></line>
39
                </svg>
40
              </a>
41
              <div>Uploaded file contains <span
42
                class="uk-text-bold">{{allIds.length}} {{((allIds.length == 1) ? 'DOI' : 'DOIs')}}</span>.
43
                <span
44
                  *ngIf="exceedsLimit">
45
                  <div class="uk-text-danger">Basket exceeds  the size limit.</div>
46
                  <span *ngIf="allIds.length > 0 && foundIds.length > 0">Only </span>
47
                  <span *ngIf="allIds.length > 0 && foundIds.length == 0">No results added.</span>
48
                   </span>
49
                <span
50
                  *ngIf="allIds.length > 0 && foundIds.length > 0">{{foundIds.length}} {{((foundIds.length == 1) ? 'result was' : 'results were')}} succefully  fetched from 
51
                  <span class="uk-text-bold">CrossRef</span>{{ ' and ' }}<span
52
                    class="uk-text-bold">Datacite</span>.</span>
53

    
54
              </div>
55
              <div
56
                *ngIf="duplicateIds.length > 0">{{duplicateIds.length | number}} duplicate DOIs in {{((duplicateIds.length == 1) ? 'line' : 'lines')}} {{duplicateIdsRow}}.
57
              </div>
58
              <div *ngIf="notFoundIds.length > 0">Couldn't be fetched:
59
                <ul class="">
60
                  <li *ngFor="let id of notFoundIds; let i = index">"{{id}}" in line {{notFoundIdsRow[i]}}</li>
61
                </ul>
62
              </div>
63
              <div *ngIf="noValidIds.length > 0">No valid DOIs:
64
                <ul class="">
65
                  <li *ngFor="let id of noValidIds; let i = index">"{{id}}" in line {{noValidIdsRow[i]}}</li>
66
                </ul>
67
              </div>
68
              <div
69
                *ngIf="allIds.length == 0 || (foundIds.length == 0 && !exceedsLimit)"> Please make sure that the uploaded file, is a csv file with the proper format.
70
              </div>
71

    
72
            </div>
73
            <div *ngIf="errorMessage.length > 0 " class="uk-alert uk-alert-danger" role="alert">
74
              <a class="uk-alert-close uk-icon uk-close">
75
                <svg width="14" height="14" viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"
76
                     data-svg="close-icon">
77
                  <line fill="none" stroke="#000" stroke-width="1.1" x1="1" y1="1" x2="13" y2="13"></line>
78
                  <line fill="none" stroke="#000" stroke-width="1.1" x1="13" y1="1" x2="1" y2="13"></line>
79
                </svg>
80
              </a>
81
              {{errorMessage}}</div>
82

    
83
          </div>
84
          <!--helper  div="link-result-bulk" ></helper-->
85
        </div>
86
      </form>
87

    
88

    
89
    </div>
90
    <div class="uk-width-1-1">
91
      <modal-loading
92
        [message]="'Uploading, reading your documet and fetching results. Please give us a moment..'"></modal-loading>
93
    </div>
94
  `
95

    
96
})
97
export class BulkClaimComponent {
98
  filesToUpload: Array<File>;
99
  source: string = "crossref";
100
  type: string = "publication";
101
  @Input() public select: boolean = true;
102
  @Input() public results;
103
  @Input() public properties: EnvProperties;
104

    
105
  allIds: string[] = [];
106
  foundIds: string[] = [];
107
  existedIds: string[] = [];
108
  duplicateIds: string[] = [];
109
  duplicateIdsRow: number[] = [];
110
  notFoundIds: string[] = [];
111
  notFoundIdsRow: number[] = [];
112
  noValidIds: string[] = [];
113
  noValidIdsRow: number[] = [];
114
  showReport: boolean = false;
115
  @ViewChild(ModalLoading) loading: ModalLoading;
116
  errorMessage = "";
117
  enableUpload: boolean = true;
118
  @Input() localStoragePrefix: string = "";
119
  exceedsLimit = false;
120
  @Input() basketLimit ;
121

    
122
  constructor(private _searchCrossrefService: SearchCrossrefService, private _searchDataciteService: SearchDataciteService) {
123
    this.filesToUpload = [];
124
  }
125

    
126
  ngOnInit() {
127
  }
128

    
129
  upload() {
130
    this.enableUpload = false;
131
    this.showReport = false;
132
    this.errorMessage = "";
133
    console.log(this.filesToUpload);
134
    if (this.filesToUpload.length == 0) {
135
      this.errorMessage = "There is no selected file to upload.";
136
      return;
137
    } else {
138
      if (this.filesToUpload[0].name.indexOf(".csv") == -1 ||
139
        (this.filesToUpload[0].type != "text/csv" && this.filesToUpload[0].type != "application/vnd.ms-excel")) {
140
        this.errorMessage = "No valid file type. The required type is CSV";
141
        return;
142
      }
143
    }
144
    this.loading.open();
145

    
146
    this.makeFileRequest(this.properties.utilsService + '/upload', [], this.filesToUpload).then((result) => {
147
      const rows = (result as any).split('\n');  // I have used space, you can use any thing.
148
      this.exceedsLimit = false;
149
      let invalid_rows = 0;
150
      this.duplicateIds = [];
151
      this.existedIds = [];
152
      this.allIds = [];
153
      this.foundIds = [];
154
      this.noValidIds = [];
155
      this.results.slice(0, this.results.length);
156
      this.notFoundIds = [];
157
      if (rows.length + this.results.length > this.basketLimit) {
158
        this.exceedsLimit = true;
159

    
160
      }
161
      let currentLength = this.results.length;
162
      for (let i = 0; i < ( rows.length); i++) {
163
        if (rows[i] && rows[i] != null) {
164
          const values = rows[i].split(',');
165

    
166
          const id = BulkClaimComponent.removeDoubleQuotes(values[0]);
167
          if (DOI.isValidDOI(id)) {
168
            let accessMode = (values[1] != undefined) ? BulkClaimComponent.removeDoubleQuotes(values[1]) : "OPEN";
169
            accessMode = (BulkClaimComponent.validateAccessMode(accessMode) ? accessMode : "OPEN");
170
            let embargoDate = (values[2] != undefined) ? Dates.getDateFromString(BulkClaimComponent.removeDoubleQuotes(values[2])) : Dates.getDateToday();
171
            if (this.allIds.indexOf(id) > -1) {
172
              this.duplicateIds.push(id);
173
              this.duplicateIdsRow.push(i + 1);
174
            } else {
175
              this.allIds.push(id);
176
              if (currentLength < this.basketLimit){
177
                currentLength++;
178
                this.fetchResult(id, accessMode, Dates.getDateToString(embargoDate), i + 1);
179
              }
180
            }
181
          } else {
182
            this.noValidIds.push(id);
183
            this.noValidIdsRow.push(i + 1);
184
          }
185
        } else {
186
          invalid_rows++;
187
        }
188

    
189
      }
190
      if (rows.length == 0 || rows.length == invalid_rows || rows.length == (invalid_rows + this.noValidIds.length) || this.basketLimit <= this.results.length) {
191
        this.endOfFetching();
192
      }
193

    
194
    }, (error) => {
195
      this.enableUpload = true;
196
      this.loading.close();
197
      this.errorMessage = "An error occured.";
198
      BulkClaimComponent.handleError("Error uploading file", error);
199
    });
200
  }
201

    
202
  private static removeDoubleQuotes(value) {
203
    if (value.indexOf('"') == 0) {
204
      value = value.substring(1, value.length);
205
    }
206
    const index = +value.indexOf('"');
207
    if (index == (value.length - 1) || index == (value.length - 2)) {
208
      value = value.substring(0, index);
209
    }
210
    return value;
211
  }
212

    
213
  private static validateAccessMode(value) {
214
    const accessModes = ["OPEN", "CLOSED", "EMBARGO"];
215
    return accessModes.indexOf(value) > -1;
216
  }
217

    
218
  fileChangeEvent(fileInput: any) {
219
    this.filesToUpload = <Array<File>>fileInput.target.files;
220
    this.upload();
221
  }
222

    
223
  makeFileRequest(url: string, params: Array<string>, files: Array<File>) {
224
    return new Promise((resolve, reject) => {
225
      const formData: any = new FormData();
226
      const xhr = new XMLHttpRequest();
227
      for (let i = 0; i < files.length; i++) {
228
        formData.append("uploads[]", files[i], files[i].name);
229
      }
230
      xhr.onreadystatechange = function () {
231
        if (xhr.readyState == 4) {
232
          if (xhr.status == 200) {
233
            resolve(xhr.response);
234
          } else {
235
            reject(xhr.response);
236
          }
237
        }
238
      }
239
      xhr.open("POST", url, true);
240
      xhr.send(formData);
241
    });
242
  }
243

    
244
  fetchResult(id: string, accessMode: string, date: string, row: number) {
245
    this._searchCrossrefService.searchCrossrefByDOIs([id], this.properties.searchCrossrefAPIURL, true).subscribe(
246
      data => {
247

    
248
        const result:ClaimEntity = data[1][0];
249
        if (data[1].length > 0) {
250
          this.foundIds.push(id);
251
          result.result.accessRights = accessMode;
252
          result.result.embargoEndDate = date;
253
          if(!this.isSelected(result)){
254
            this.results.push(result);
255
          }else{
256
            this.existedIds.push(id);
257
          }
258
          this.endOfFetching();
259
        } else {
260
          this.searchInDatacite(id, accessMode, date, row);
261
          // this.notFoundIds.push(id);
262
        }
263
      },
264
      err => {
265
        //console.log(err);
266
        BulkClaimComponent.handleError("Error getting crossref by DOIs: " + id, err);
267
        this.notFoundIds.push(id);
268
        this.notFoundIdsRow.push(row);
269
        this.endOfFetching();
270
      }
271
    );
272
  }
273

    
274
  searchInDatacite(id: string, accessMode: string, date: string, row: number) {
275
    this._searchDataciteService.getDataciteResultByDOI(id, this.properties, true).subscribe(
276
      result => {
277

    
278
        if (result) {
279
          this.foundIds.push(id);
280
          result.result.accessRights = accessMode;
281
          result.result.embargoEndDate = date;
282
          if(!this.isSelected(result)){
283
            this.results.push(result);
284
          }else{
285
            this.existedIds.push(id);
286
          }
287
        } else {
288
          this.notFoundIds.push(id);
289
          this.notFoundIdsRow.push(row);
290
        }
291
        this.endOfFetching();
292
      },
293
      err => {
294
        //console.log(err);
295
        BulkClaimComponent.handleError("Error getting datacite resultentityI: " + id, err);
296
        this.notFoundIds.push(id);
297
        this.notFoundIdsRow.push(row);
298
        this.endOfFetching();
299
      }
300
    );
301
  }
302

    
303
  endOfFetching() {
304
    // if (this.basketLimit <= this.results.length) {
305
    //   this.enableUpload = true;
306
    //   this.loading.close();
307
    //   return;
308
    // }
309
    // console.log(this.allIds.length+" "+this.foundIds.length +" "+ this.notFoundIds.length+" "+this.existedIds.length + " " + this.results.length);
310
    if (this.allIds.length == this.foundIds.length + this.notFoundIds.length || this.basketLimit <= (this.results.length+this.existedIds.length+this.notFoundIds.length)) {
311
      this.showReport = true;
312
      this.enableUpload = true;
313
      this.loading.close();
314
      if (this.results != null) {
315
        localStorage.setItem(this.localStoragePrefix, JSON.stringify(this.results));
316
      }
317
    }
318

    
319
  }
320

    
321
  private static handleError(message: string, error) {
322
    console.error("Bulk Claim (component): " + message, error);
323
  }
324

    
325
  private isSelected(result: ClaimEntity) {
326

    
327
    let found: boolean = false;
328
    const id = result.id;
329
    for (let _i = 0; _i < this.results.length; _i++) {
330
      let item = this.results[_i];
331
      if (item.id && item.id == id) {
332
        found = true;
333
        break;
334
      }
335
    }
336
    return found;
337
    // indexOf doesn't work when results came from
338
    // return this.selectedResults.indexOf(entity)!=-1;
339
  }
340
}
(1-1/2)