Project

General

Profile

1
import {Component, Input, ViewChild} from '@angular/core';
2
import {Location} from '@angular/common';
3
import {ActivatedRoute, Router} from '@angular/router';
4
import {Subject, Subscriber} from 'rxjs';
5
import {debounceTime, distinctUntilChanged} from 'rxjs/operators';
6
import {ClaimsService} from '../service/claims.service';
7
import {ModalLoading} from '../../../utils/modal/loading.component';
8
import {AlertModal} from '../../../utils/modal/alert';
9
import {Session, User} from '../../../login/utils/helper.class';
10
import {EnvProperties} from '../../../utils/properties/env-properties';
11
import {LoginErrorCodes} from '../../../login/utils/guardHelper.class';
12
import {SEOService} from '../../../sharedComponents/SEO/SEO.service';
13
import {IndexInfoService} from '../../../utils/indexInfo.service';
14
import {ClaimDBRecord} from '../claimHelper.class';
15
import {Dates} from '../../../utils/string-utils.class';
16
import {HelperService} from '../../../utils/helper/helper.service';
17
import {Meta, Title} from '@angular/platform-browser';
18
import {PiwikService} from '../../../utils/piwik/piwik.service';
19
import {properties} from '../../../../../environments/environment';
20
import {FormArray, FormBuilder, FormGroup} from '@angular/forms';
21
import {Option} from '../../../sharedComponents/input/input.component';
22
import {SearchInputComponent} from '../../../sharedComponents/search-input/search-input.component';
23

    
24
declare var UIkit;
25
@Component({
26
  selector: 'displayClaims',
27
  templateUrl: 'displayClaims.component.html',
28
  // providers: [ClaimsService]
29

    
30
})
31
export class DisplayClaimsComponent {
32
  @Input() piwikSiteId = null;
33
  @Input() pageTitle: string = "";
34
  properties: EnvProperties;
35
  public searchTermStream = new Subject<string>();
36
  subscriptions: any = [];
37
  public subResults: any;
38
  //string because comes as input from component directive
39
  @Input() enableDelete: boolean = false;
40
  @Input() showUserEmail: boolean = true;
41
  @Input() myClaims: boolean = false;
42
  @Input() isAdmin: boolean = false;
43
  page: number = 1;
44
  size: number = 50;
45
  defaultSize:number = 50;
46
  sizes = [10, 20, 30, 50];
47
  keyword: string; // the keyword string to give to the request as parameter
48
  inputkeyword: string; // the string written in the input field (keyword=inputkeyword when its length is bigger than 3 and the user stops typing)
49
  @ViewChild('searchInputComponent') searchInputComponent: SearchInputComponent;
50
  types = ["All", "Project", "Context", "Result", "User"];
51
  pageLoading:boolean = false;
52
  @Input() fetchBy: string;
53
  @Input() fetchId: string;
54
  @Input() user: User;
55
  resultsNum: number;
56
  claims: ClaimDBRecord[];
57
  @Input() externalPortalUrl: string = null;
58
  @Input() claimsInfoURL: string;// ="https://www.openaire.eu/linking";
59
  lastIndexDate = null;
60

    
61
  @ViewChild(ModalLoading) loading: ModalLoading;
62
  public filterForm: FormGroup;
63
  public entitiesCtrl: FormArray;
64

    
65
  allOptions: Option[] = [{label: "Projects", value: {id:"project", label: "Projects"}},{label: "Publications", value:{id:"publication", label: "Publications"}},{label: "Research data", value: {id:"dataset", label: "Research data"}},
66
    {label: "Software", value:  {id:"software", label: "Software"}},{label: "Other reserch products", value: {id:"other", label: "Other reserch products"}},{label: "Communities", value: {id:"context", label: "Communities"}}];
67

    
68
  sortOptions: Option[] = [
69
    {label:"Date (recent) ", value:{ sort: "date", descending: true }}, {label:"Date (oldest) ", value:{ sort: "date",descending:false }},
70
    // {label:"User (desc) ", value:{ sort: "user",descending: true }}, {label:"User (asc) ", value:{ sort: "user",descending:false }},
71
    // {label:"Title (desc) ", value:{ sort: "source",descending: true }}, {label:"Title (asc) ", value:{ sort: "source",descending:false }},
72
    {label:"Title (desc) ", value:{ sort: "target",descending: true }}, {label:"Title (asc) ", value: { sort: "target",descending:false }},
73
  ];
74

    
75
  entityTypes: string[] = [];
76

    
77
  // descending = true;
78
  // sortby = "date";
79

    
80
  selected = [];
81
  // deleteMessage: string = "";
82
  showErrorMessage: boolean = false;
83
  showForbiddenMessage: boolean = false;
84
  userValidMessage: string = "";
85

    
86
  //params for pagingFormatter to use when navigate to page
87
  params;
88
  @ViewChild(AlertModal) alert;
89

    
90
  claimsDeleted: number = 0;
91
  @Input() communityId: string = null;
92

    
93
  url = null;
94
  public pageContents = null;
95

    
96
  constructor(private _claimService: ClaimsService, private route: ActivatedRoute, private _router: Router, private location: Location,
97
              private _meta: Meta, private _title: Title, private _piwikService: PiwikService,
98
              private seoService: SEOService, private indexInfoService: IndexInfoService, private helper: HelperService, private _fb: FormBuilder) {
99
  }
100

    
101
  ngOnInit() {
102
    this.entitiesCtrl = this._fb.array([]);
103
    this.filterForm = this._fb.group({
104
      keyword: [''],
105
      entities: this.entitiesCtrl,
106
      sort: this._fb.control(this.sortOptions[0].value)
107
    });
108

    
109
    this.properties = properties;
110
    this.url = properties.domain + properties.baseLink + this._router.url;
111
    if(!this.myClaims){
112
      this.sortOptions.push({label:"User (desc) ", value:{ sort: "user",descending: true }});
113
      this.sortOptions.push( {label:"User (asc) ", value:{ sort: "user",descending:false }})
114
    }
115
    var description = "Openaire, linking, claim, publication, research data, software, other research product, project, community";
116
    this.updateTitle(this.pageTitle);
117
    this.updateDescription(description);
118
    this.updateUrl(this.url);
119
    if (this.properties.enablePiwikTrack && (typeof document !== 'undefined')) {
120
      this.subscriptions.push(this._piwikService.trackView(this.properties, this.pageTitle, this.piwikSiteId).subscribe());
121
    }
122

    
123
    this.subscriptions.push(this.helper.getPageHelpContents(this.properties, this.communityId, this._router.url).subscribe(contents => {
124
      this.pageContents = contents;
125
    }));
126
    this.subscriptions.push(this.indexInfoService.getLastIndexDate(this.properties).subscribe(res => {
127
      this.lastIndexDate = res;
128
    }));
129
    this.subscriptions.push(this.route.queryParams.subscribe(params => {
130
      this.seoService.createLinkForCanonicalURL(this.url, false);
131

    
132
      if (this.myClaims) {
133
        this.fetchBy = "User";
134
        this.fetchId = this.user.email;
135
      } else {
136
        this.fetchBy = (this.fetchBy) ? this.fetchBy : params['fetchBy'];
137
        this.fetchBy = (this.types.indexOf(this.fetchBy) != -1) ? this.fetchBy : 'All';
138
        this.fetchId = (this.fetchId) ? this.fetchId : params['fetchId'];
139
        this.fetchId = this.fetchId ? this.fetchId : '';
140
      }
141

    
142
      let page = (params['page'] === undefined) ? 1 : +params['page'];
143
      let size = (params['size'] === undefined) ? this.defaultSize : +params['size'];
144

    
145
      this.keyword = (params['keyword'] ? params['keyword'] : "");
146
      this.filterForm.get('keyword').setValue(this.keyword);
147
      this.inputkeyword = this.keyword;
148
      this.page = (page <= 0) ? 1 : page;
149
      this.size = (size <= 0) ? this.defaultSize : size;
150
      this.entityTypes = [];//(params['types']?params['types']:[]);
151
      // this.setTypes(params['types']); // check the appropriate checkboxes
152
      this.setSortby(params['sort']);
153
      this.getClaims();
154
      this.subscriptions.push(this.searchTermStream
155
        .pipe(debounceTime(300), distinctUntilChanged())
156
        .subscribe((term: string) => {
157
          this.keyword = term;
158
          this.page = 1;
159
          this.goTo();
160
        }));
161
      this.subscriptions.push(this.filterForm.get('entities').valueChanges.subscribe(value => {
162
        this.goTo();
163
      }));
164
      this.subscriptions.push(this.filterForm.get('keyword').valueChanges.subscribe(value => {
165
        this.changekeyword();
166
      }));
167
      this.subscriptions.push(this.filterForm.get('sort').valueChanges.subscribe(value => {
168
        this.goTo();
169
      }));
170
    }));
171
  }
172

    
173
  ngOnDestroy() {
174
    this.subscriptions.forEach(subscription => {
175
      if (subscription instanceof Subscriber) {
176
        subscription.unsubscribe();
177
      }
178
    });
179
    if(this.subResults){
180
      this.subResults.unsubscribe();
181
    }
182
  }
183

    
184
  getClaims() {
185
    if (!Session.isLoggedIn()) {
186
      this.userValidMessage = "User session has expired. Please login again.";
187
      this._router.navigate(['/user-info'], {
188
        queryParams: {
189
          "errorCode": LoginErrorCodes.NOT_VALID,
190
          "redirectUrl": this._router.url
191
        }
192
      });
193
    } else {
194
      this.selected = [];
195
      let types = '';
196
      this.showErrorMessage = false;
197
      this.showForbiddenMessage = false;
198
      for (let type of this.entitiesCtrl.getRawValue()) {
199
        types += (this.entitiesCtrl.getRawValue().length > 0 ? '&' : '') + "types=" + type.id;
200
      }
201
      this.pageLoading = true;
202
      if(this.subResults){
203
        this.subResults.unsubscribe();
204
      }
205
      if (this.fetchBy == "Project") {
206
        this.subResults = this._claimService.getClaimsByProject(this.size, this.page, this.fetchId, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe(
207
          data => {
208
            this.manageAPIData(data);
209
            this.pageLoading = false;
210
          },
211
          err => {
212
            this.handleErrors(err, "Error getting claims for project with id: " + this.fetchId);
213
          }
214
        );
215
      } else if (this.fetchBy == "User") {
216
        this.subResults = this._claimService.getClaimsByUser(this.size, this.page, this.fetchId, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe(
217
          data => {
218
            this.manageAPIData(data);
219
            this.pageLoading = false;
220
          },
221
          err => {
222
            this.handleErrors(err, "Error getting claims for user with id: " + this.fetchId);
223
            this.pageLoading = false;
224
          }
225
        );
226
      } else if (this.fetchBy == "Result") {
227
        this.subResults = this._claimService.getClaimsByResult(this.size, this.page, this.fetchId, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe(
228
          data => {
229
            this.manageAPIData(data);
230
            this.pageLoading = false;
231
          },
232
          err => {
233
            this.handleErrors(err, "Error getting claims for entity with id: " + this.fetchId);
234
            this.pageLoading = false;
235
          }
236
        );
237
      } else if (this.fetchBy == "Context") {
238
        this.subResults = this._claimService.getClaimsBycontext(this.size, this.page, this.fetchId, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe(
239
          data => {
240
            this.manageAPIData(data);
241
            this.pageLoading = false;
242
          },
243
          err => {
244
            this.handleErrors(err, "Error getting claims for context with id: " + this.fetchId);
245
            this.pageLoading = false;
246
          }
247
        );
248
      } else {
249
        this.subResults = this._claimService.getClaims(this.size, this.page, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe(
250
          data => {
251
              this.manageAPIData(data);
252
              this.pageLoading = false;
253
          },
254
          err => {
255
            this.handleErrors(err, "Error getting claims");
256
            this.pageLoading = false;
257
          }
258
        );
259
      }
260
    }
261
  }
262

    
263
  manageAPIData(data) {
264
    this.claims = data.data;
265
    this.resultsNum = data.total;
266

    
267

    
268
  }
269

    
270
  handleErrors(err, message) {
271

    
272
    this.showErrorMessage = true;
273
    console.error("Dispaly Claims (component): " + message +" " + (err && err.error?err.error:''));
274
    try {
275
      let error = err && err.error?err.error:err;
276
      if (error.code && error.code == 403) {
277
        this.showErrorMessage = false;
278
        this.showForbiddenMessage = true;
279
        if(!Session.isLoggedIn()) {
280

    
281
          this._router.navigate(['/user-info'], {
282
            queryParams: {
283
              "errorCode": LoginErrorCodes.NOT_VALID,
284
              "redirectUrl": this._router.url
285
            }
286
          });
287
        }
288

    
289
      }
290
    } catch (e) {
291

    
292
    }
293

    
294
  }
295

    
296
  goTo(page: number = 1) {
297
    this.page = page;
298
    this.location.go(location.pathname, this.getParametersString());
299
    this.getClaims();
300
  }
301

    
302
  getParametersString() {
303
    let params = '';
304
    params += (this.page == 1 ? "" : (params.length > 0 ? '&' : '') + "page=" + this.page);
305
    params += (this.size == 10 ? "" : (params.length > 0 ? '&' : '') + "size=" + this.size);
306
    let types = "";
307
    for (let type of this.entitiesCtrl.getRawValue()) {
308
      types += (this.entitiesCtrl.getRawValue().length > 0 ? ',' : '') + type.id;
309
    }
310
    params += (this.entitiesCtrl.getRawValue().length > 0) ? (params.length > 0 ? '&' : '') + "types=" + types : "";
311
    if (this.isAdmin) {
312
      params += (this.fetchBy == 'All' ? "" : (params.length > 0 ? '&' : '') + "fetchBy=" + this.fetchBy);
313
      params += (this.fetchId == '' ? "" : (params.length > 0 ? '&' : '') + "fetchId=" + this.fetchId);
314
    }
315
    params += (this.filterForm.get("sort").value.sort == 'date' && this.filterForm.get("sort").value.descending ? "" : (params.length > 0 ? '&' : '') + "sort=" +this.filterForm.get("sort").value.sort + "-" + this.filterForm.get("sort").value.descending);
316
    params += (this.keyword == '' ? "" : (params.length > 0 ? '&' : '') + "keyword=" + this.keyword);
317
    if (this.communityId != null) {
318
      params += "&communityId=" + this.communityId;
319
    }
320
    return params;
321
  }
322

    
323
  setSortby(sortby: string) {
324
    let sort = "date";
325
    let desc = "desc";
326
    if(sortby && sortby.split("-").length == 2){
327
      sort = sortby.split("-")[0];
328
      desc = sortby.split("-")[1];
329
    }
330

    
331
    let option = this.sortOptions.find( option => option.value.sort == sort && ((option.value.descending && desc=="desc") || (!option.value.descending && desc=="asc")));
332
    this.filterForm.get("sort").setValue(option?option.value:this.sortOptions[0].value);
333
  }
334

    
335
  changekeyword() {
336

    
337
    if (this.filterForm.get("keyword").value.length >= 3 || this.filterForm.get("keyword").value.length == 0) {
338
      this.searchTermStream.next(this.filterForm.get("keyword").value);
339
    }
340
  }
341

    
342
  select(item: any, event) {
343
    let value = event.currentTarget.checked;
344
    if (value) {
345
      this.selected.push(item);
346
    } else {
347
      for (var _i = 0; _i < this.selected.length; _i++) {
348
        let claim = this.selected[_i];
349
        if (claim['id'] == item.id) {
350
          this.selected.splice(_i, 1);
351
        }
352
      }
353

    
354

    
355
    }
356
  }
357

    
358
  selectAll(event) {
359
    let value = event.currentTarget.checked;
360
    if (value) {
361
      this.selected = [];
362
      for (let _i = 0; _i < this.claims.length; _i++) {
363
        let claim = this.claims[_i];
364
        this.selected.push(claim);
365
      }
366
    } else {
367
      this.selected = [];
368
    }
369
  }
370

    
371
  isSelected(id: string) {
372
    for (let _i = 0; _i < this.selected.length; _i++) {
373
      let claim = this.selected[_i];
374
      if (claim['id'] == id) {
375
        return true;
376
      }
377
    }
378
    return false;
379
  }
380

    
381

    
382
  confirmOpen() {
383
    if (this.selected.length <= 0) {
384

    
385
    } else {
386
      this.alert.cancelButton = true;
387
      this.alert.okButton = true;
388
      this.alert.alertTitle = "";// "Delete " + this.selected.length + " links(s)";
389
      this.alert.okButtonLeft = false;
390
      // this.alert.message = this.selected.length + " links will be deleted. Do you want to proceed? ";
391
      this.alert.okButtonText = "Delete";
392
      this.alert.cancelButtonText = "Cancel";
393
      this.alert.open();
394
    }
395
  }
396

    
397
  confirmClose() {
398
    this.delete();
399
  }
400

    
401
  delete() {
402
    this.loading.open();
403
    this.claimsDeleted = 0;
404
    let ids = [];
405
    for (let i = 0; i < this.selected.length; i++) {
406
      let id = this.selected[i].id;
407
      ids.push(id);
408

    
409
    }
410
    this.batchDeleteById(ids);
411
  }
412

    
413
  batchDeleteById(ids: string[]) {
414
    if (!this.user) {
415
      this.userValidMessage = "User session has expired. Please login again.";
416
      this._router.navigate(['/user-info'], {
417
        queryParams: {
418
          "errorCode": LoginErrorCodes.NOT_VALID,
419
          "redirectUrl": this._router.url
420
        }
421
      });
422
    } else {
423
      //console.warn("Deleting claim with ids:"+ids);
424
      this.subscriptions.push(this._claimService.deleteBulk(ids, this.properties.claimsAPIURL).subscribe(
425
        res => {
426
          //console.info('Delete response'+res.code );
427
          //console.warn("Deleted ids:"+ res.deletedIds);
428
          //console.warn("Not found ids:"+ res.notFoundIds);
429
          //remove this claim from the
430
          let newClaims = this.claims;
431
          for (let id of res.deletedIds) {
432
            for (let _i = 0; _i < this.claims.length; _i++) {
433
              let claim = this.claims[_i];
434
              if (claim['id'] == id) {
435
                newClaims.splice(_i, 1);
436
              }
437
            }
438
            for (let _i = 0; _i < this.selected.length; _i++) {
439
              let claim = this.selected[_i];
440
              if (claim['id'] == id) {
441
                this.selected.splice(_i, 1);
442
              }
443
            }
444
          }
445
          this.claims = newClaims;
446
          this.resultsNum = this.resultsNum - res.deletedIds.length;
447
          this.loading.close();
448
          if (res.deletedIds.length > 0) {
449
            UIkit.notification('<div class = " " >' + res.deletedIds.length + ' link(s) successfully deleted.</div>', {
450
              status: 'success',
451
              timeout: 6000,
452
              pos: 'bottom-right'
453
            });
454
          }
455
          if (res.notFoundIds.length > 0) {
456
            UIkit.notification('<div class = " " >' + res.notFoundIds.length + ' link(s) couldn\'t be deleted.</div>', {
457
              status: 'danger',
458
              timeout: 6000,
459
              pos: 'bottom-right'
460
            });
461
          }
462

    
463
          let goToPage = this.page;
464
          if (this.totalPages(this.resultsNum) < this.page && this.page > 0) {
465
            goToPage = this.page - 1;
466
          }
467
          this.goTo(goToPage);
468
        }, err => {
469
          //console.log(err);
470
          this.handleErrors(err,"Error deleting claims with ids: " + ids);
471
          this.showErrorMessage = true;
472
          this.loading.close();
473

    
474
        }));
475
    }
476
  }
477

    
478
  pageChange($event) {
479
    let page: number = +$event.value;
480
    this.goTo(page);
481
  }
482

    
483
  isClaimAvailable(claim: ClaimDBRecord): boolean {
484
    //claim.target.collectedFrom == "infrastruct_::openaire" &&
485
    let lastUpdateDate = new Date((this.lastIndexDate != null) ? this.lastIndexDate : this.properties.lastIndexUpdate);
486
    let lastUpdateDateStr = Dates.getDateToString(lastUpdateDate);
487
    let claimDate = new Date(claim.date);
488
    let claimDateStr = Dates.getDateToString(claimDate);
489
    if (claimDateStr < lastUpdateDateStr) {
490
      return true;
491
    } else {
492
      if (claim.target.collectedFrom != "infrastruct_::openaire" && claim.indexed) {
493
        //  check if direct index succeded
494
        return true
495
      }
496
    }
497
    return false;
498
  }
499

    
500
  totalPages(totalResults: number): number {
501
    let totalPages: any = totalResults / (this.size);
502
    if (!(Number.isInteger(totalPages))) {
503
      totalPages = (parseInt(totalPages, 10) + 1);
504
    }
505
    return totalPages;
506
  }
507

    
508
  private updateDescription(description: string) {
509
    this._meta.updateTag({content: description}, "name='description'");
510
    this._meta.updateTag({content: description}, "property='og:description'");
511
  }
512

    
513
  private updateTitle(title: string) {
514
    var _prefix = "";
515
    if (!this.communityId) {
516
      _prefix = "OpenAIRE | ";
517
    }
518
    var _title = _prefix + ((title.length > 50) ? title.substring(0, 50) : title);
519
    if(this.myClaims) {
520
      this._title.setTitle(_title);
521
    }
522
    this._meta.updateTag({content: _title}, "property='og:title'");
523
  }
524

    
525
  private updateUrl(url: string) {
526
    this._meta.updateTag({content: url}, "property='og:url'");
527
  }
528
  public onSearchClose() {
529
    this.inputkeyword = this.filterForm.get('keyword').value;
530
  }
531

    
532
  public resetInput() {
533
    this.inputkeyword = null;
534
    this.searchInputComponent.reset()
535
  }
536
}
(2-2/3)