Project

General

Profile

1
import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core';
2
import {ActivatedRoute, Router} from '@angular/router';
3
import {AdvancedField, Filter} from './searchUtils/searchHelperClasses.class';
4
import {SearchResearchResultsService} from '../services/searchResearchResults.service';
5
import {ErrorCodes} from '../utils/properties/errorCodes';
6
import {ErrorMessagesComponent} from '../utils/errorMessages.component';
7
import {SearchFields} from '../utils/properties/searchFields';
8
import {SearchCustomFilter, SearchUtilsClass} from './searchUtils/searchUtils.class';
9
import {EnvProperties} from '../utils/properties/env-properties';
10
import {NewSearchPageComponent} from "./searchUtils/newSearchPage.component";
11
import {RangeFilter} from "../utils/rangeFilter/rangeFilterHelperClasses.class";
12
import {properties} from "../../../environments/environment";
13
import {ContextsService} from "../claims/claim-utils/service/contexts.service";
14

    
15
@Component({
16
  selector: 'search-research-results',
17
  template: `
18
    <new-search-page
19
        pageTitle="{{(simpleView?'':'Advanced ')}} Search for {{ getEntityName(resultType, true, true) | titlecase }}"
20
        [entityType]="resultType"
21
        [type]="getEntityName(resultType, true, true)"
22
        [results]="results"
23
        [searchUtils]="searchUtils"
24
        [sortedByChanged]="searchUtils.sortBy" [resultsPerPageChanged]="searchUtils.size"
25
        [fieldIds]="fieldIds" [fieldIdsMap]="fieldIdsMap" [selectedFields]="selectedFields"
26
        [csvParams]="csvParams" [csvPath]="getEntityName(resultType, true, false)"
27
        [simpleSearchLink]="simpleSearchLink" [advancedSearchLink]="advancedSearchLink"
28
        [disableForms]="disableForms"
29
        [disableRefineForms]="disableRefineForms"
30
        [loadPaging]="loadPaging"
31
        [oldTotalResults]="oldTotalResults"
32
        [openaireLink]=openaireLink
33
        [piwikSiteId]=piwikSiteId [hasPrefix]="hasPrefix"
34
        searchFormClass="publicationsSearchForm"
35
        [filters]="filters" [quickFilter]="quickFilter"
36
        [rangeFilters]="rangeFilters" [rangeFields]="rangeFields"
37
        [simpleView]="simpleView" formPlaceholderText="Search by title, author, abstract, DOI, orcid..."
38
        [includeOnlyResultsAndFilter]="includeOnlyResultsAndFilter" [showBreadcrumb]="showBreadcrumb"
39
        [showSwitchSearchLink]="showSwitchSearchLink"
40
        [stickyForm]="stickyForm"
41
    >
42
    </new-search-page>
43
  
44
  `
45
})
46

    
47
export class SearchResearchResultsComponent {
48
  @Input() resultType: string = "result";
49
  
50
  @Input() simpleSearchLink: string = "";
51
  advancedSearchLink: string = "";
52
  
53
  private errorCodes: ErrorCodes;
54
  private errorMessages: ErrorMessagesComponent;
55
  @Input() piwikSiteId = properties.piwikSiteId;
56
  @Input() hasPrefix: boolean = true;
57
  public results = [];
58
  public filters = [];
59
  public rangeFilters: RangeFilter[] = [];
60
  
61
  public searchUtils: SearchUtilsClass = new SearchUtilsClass();
62
  public searchFields: SearchFields = new SearchFields();
63
  
64
  public fieldIds: string[] = this.searchFields.RESULT_ADVANCED_FIELDS;
65
  public fieldIdsMap = this.searchFields.RESULT_FIELDS;
66
  public rangeFields: string[][] = this.searchFields.RESULT_RANGE_FIELDS;
67
  public selectedFields: AdvancedField[] = [];
68
  public resourcesQuery = "((oaftype exact result) and (resulttypeid exact " + this.resultType + "))";
69
  public csvParams: string;
70
  public disableForms: boolean = false;
71
  public disableRefineForms: boolean = false;
72
  public loadPaging: boolean = true;
73
  public oldTotalResults: number = 0;
74
  @Input() openaireLink: string;
75
  @Input() customFilter: SearchCustomFilter = null;
76
  public pagingLimit: number = 0;
77
  public isPiwikEnabled;
78
  properties: EnvProperties = properties;
79
  public refineFields: string[] = this.searchFields.RESULT_REFINE_FIELDS;
80
  @ViewChild(NewSearchPageComponent, { static: true }) searchPage: NewSearchPageComponent;
81
  @Input() simpleView: boolean = true;
82
  quickFilter: { filter: Filter, selected: boolean, filterId: string, value: string } = {
83
    filter: null,
84
    selected: true,
85
    filterId: "resultbestaccessright",
86
    value: "Open Access"
87
  };
88
  @Input() includeOnlyResultsAndFilter: boolean = false;
89
  @Input() showBreadcrumb: boolean = false;
90
  @Output() searchPageUpdates = new EventEmitter();
91
  @Input() showSwitchSearchLink: boolean = true;
92
  subs: any[] = [];
93
  searchResultsSub: any;
94
  searchFiltersSub: any;
95
  @Input() stickyForm:boolean = false;
96

    
97
  private timeoutId;
98
  private promise: Promise<boolean> = null;
99
  private publicCommunities = null;
100

    
101
  @Input() usedBy: string = "search";
102
  @Input() orcidQuery: string = "";
103
  @Input() identifiers: string[] = [];
104

    
105
  constructor(private route: ActivatedRoute, private _router: Router,
106
              private _searchResearchResultsService: SearchResearchResultsService,
107
              private _contextService: ContextsService) {
108
    this.results = [];
109
    this.errorCodes = new ErrorCodes();
110
    this.errorMessages = new ErrorMessagesComponent();
111
    this.searchUtils.status = this.errorCodes.LOADING;
112
    this.searchUtils.refineStatus = this.errorCodes.LOADING;
113
    this.getPublicCommunities();
114
  }
115

    
116
  getRoute(){
117
    return   this._router.url.split("?")[0];
118
  }
119
  
120
  ngOnInit() {
121
    //TODO add checks about which result types are enabled!
122
    this.pagingLimit = this.properties.pagingLimit;
123
    this.isPiwikEnabled = this.properties.enablePiwikTrack;
124
    
125
    if (!this.simpleSearchLink) {
126
      this.simpleSearchLink = this.properties.searchLinkToResults;
127
    }
128
    this.advancedSearchLink = this.properties.searchLinkToAdvancedResults;
129
    this.searchUtils.baseUrl = this.getRoute();//(this.simpleView) ? this.simpleSearchLink : this.advancedSearchLink;
130
    
131
    this.searchUtils.status = this.errorCodes.LOADING;
132
    var firstLoad = true;
133
    this.subs.push(this.route.queryParams.subscribe(params => {
134
      if(this.usedBy == "orcid"){
135
        this.searchPage.usedBy = "orcid";
136
      }
137

    
138
    //this.subs.push(this.route.queryParams.switchMap(params => {
139
      this.loadPaging = true;
140
      if (params['page'] && this.searchUtils.page != params['page']) {
141
        this.loadPaging = false;
142
        this.oldTotalResults = this.searchUtils.totalResults;
143
      }
144
      var refine = true;
145
      if(this.searchPage.searchUtils.refineStatus == this.errorCodes.DONE) {
146
        if (params['page'] != undefined && this.filters && !firstLoad && this.searchUtils.page != +params['page']) {
147
          refine = false;
148
        }
149

    
150
        if (params['sortBy'] != undefined && this.filters && !firstLoad && this.searchUtils.sortBy != params['sortBy']) {
151
          refine = false;
152
        }
153

    
154
        if (params['size'] != undefined && this.filters && !firstLoad && this.searchUtils.size != params['size']) {
155
          refine = false;
156
        }
157
      }
158

    
159
      let page = (params['page'] === undefined) ? 1 : +params['page'];
160
      this.searchUtils.page = (page <= 0) ? 1 : page;
161
      
162
      this.searchUtils.size = (params['size'] === undefined) ? 10 : +params['size'];
163
      if (this.searchUtils.size != 5 && this.searchUtils.size != 10 && this.searchUtils.size != 20 && this.searchUtils.size != 50) {
164
        this.searchUtils.size = 10;
165
      }
166
      this.searchUtils.sortBy = (params['sortBy']) ? params['sortBy'] : '';
167
      if (this.searchUtils.sortBy && this.searchUtils.sortBy != "resultdateofacceptance,descending" && this.searchUtils.sortBy != "resultdateofacceptance,ascending") {
168
        this.searchUtils.sortBy = "";
169
      }
170
      this.selectedFields = [];
171

    
172
      this.searchPage.prepareSearchPage(this.fieldIds, this.selectedFields, this.refineFields, this.rangeFields, this.fieldIdsMap,this.customFilter,params, this.resultType, this.quickFilter);
173
      if(refine) {
174
        this._getFilters(this.searchPage.getSearchAPIQueryForAdvancedSearhFields(), this.searchUtils.page, 0, "", true, this.searchPage.getSearchAPIQueryForRangeFields(params)+this.searchPage.getSearchAPIQueryForRefineFields(params, firstLoad));
175
      } else {
176
        this.searchUtils.refineStatus = this.errorCodes.DONE;
177
      }
178
      this._getResults(this.searchPage.getSearchAPIQueryForAdvancedSearhFields(), this.searchUtils.page, this.searchUtils.size, this.searchUtils.sortBy, refine, this.searchPage.getSearchAPIQueryForRangeFields(params) + this.searchPage.getSearchAPIQueryForRefineFields(params, firstLoad));
179
      firstLoad = false;
180
    }));
181
  }
182
  
183
  ngOnDestroy() {
184
    if(this.searchResultsSub) {
185
      this.searchResultsSub.unsubscribe();
186
    }
187
    if(this.searchFiltersSub) {
188
      this.searchFiltersSub.unsubscribe();
189
    }
190
    for (let sub of this.subs) {
191
      sub.unsubscribe();
192
    }
193
  }
194

    
195
  public getPublicCommunities() {
196
    this.promise = new Promise<any>(resolve => {
197
      this._contextService.getPublicCommunitiesByState().subscribe(
198
        data => {
199
          if(this.publicCommunities == null) {
200
            this.publicCommunities = data.map(value => value.id);
201
          }
202
          resolve();
203
        },
204
        error => {
205
          this.handleError("Error getting communities status", error);
206
          resolve();
207
        });
208
    });
209
  }
210

    
211
  racePromiseWithTimeout() {
212
    const timeoutPromise = new Promise((_, reject) => {
213
      this.timeoutId = setTimeout(() => {
214
        this.publicCommunities = [];
215
        reject(new Error('Request timed out'));
216
      }, 300);
217
    });
218

    
219
    return Promise.race([this.promise, timeoutPromise]);
220
  }
221

    
222

    
223
  public _getFilters(parameters: string, page: number, size: number, sortBy: string, refine: boolean, refineFieldsFilterQuery = null) {
224
    if(this.usedBy == "orcid" && this.orcidQuery) {
225
      parameters += (parameters ? ' and ' : '') + "(" + this.orcidQuery + ")";
226
    }
227
      if (page <= this.pagingLimit || this.searchUtils.refineStatus == this.errorCodes.LOADING) {
228
        this.searchUtils.refineStatus = this.errorCodes.LOADING;
229
        this.disableRefineForms = true;
230
        this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils});
231
        this.searchFiltersSub = this._searchResearchResultsService.advancedSearchResults(this.resultType, parameters, page, size, sortBy, this.properties, (refine) ? this.searchPage.getRefineFieldsQuery() : null, this.searchPage.getFields(), refineFieldsFilterQuery)
232
        // this.subs.push(this._searchResearchResultsService.advancedSearchResults(this.resultType, parameters, page, size, sortBy, this.properties, (refine) ? this.searchPage.getRefineFieldsQuery() : null, this.searchPage.getFields(), refineFieldsFilterQuery)
233
          //.switchMap(
234
          .subscribe(
235
            data => {
236
              let totalResults = data[0];
237
              let filters = data[2];
238

    
239
              // if (refine) {
240
              //   this.filters = this.searchPage.prepareFiltersToShow(filters, totalResults);
241
              //   this.rangeFilters = this.searchPage.prepareRangeFiltersToShow();
242
              // }
243
              //
244
              // this.searchUtils.refineStatus = this.errorCodes.DONE;
245
              //
246
              // this.disableRefineForms = false;
247
              this.filtersReturned(refine, filters, totalResults, page);
248
              this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils})
249
            },
250
            err => {
251
              this.filters = this.searchPage.prepareFiltersToShow([], 0);
252
              this.rangeFilters = this.searchPage.prepareRangeFiltersToShow();
253

    
254
              this.handleError("Error getting refine filters for " + this.getEntityName(this.resultType, true, true), err);
255
              this.searchUtils.refineStatus = this.errorMessages.getErrorCode(err.status);
256

    
257
              this.disableRefineForms = false;
258
              this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils})
259
            }
260
          );//);
261
      }
262
  }
263

    
264
    public async filtersReturned(refine: boolean, filters: Filter[], totalResults, page: number) {
265
      if(!this.timeoutId) {
266
        try {
267
          await this.racePromiseWithTimeout();
268
        } catch (error) {
269
          this.handleError("Getting communities status was over 300ms - timeout", error);
270
        } finally {
271
          clearTimeout(this.timeoutId);
272
        }
273
      }
274

    
275
      let communitiesFilter = filters.find(filters => filters.filterId == "community");
276
      if(communitiesFilter && this.publicCommunities && this.publicCommunities.length > 0) {
277
        communitiesFilter.values = communitiesFilter.values.filter(value => {
278
          let valueId = "";
279
          if(value.id) {
280
            let idArray = value.id.split("||");
281
            if(idArray) {
282
              valueId = idArray[0];
283
            }
284
          }
285
          //for(let publicCom of this.publicCommunities) {
286
            //if(valueId && publicCom['id'] == valueId) {
287
          if(valueId && this.publicCommunities.includes(valueId)) {
288
              return true;
289
            //}
290
          }
291
        });
292
      }
293

    
294
      if (refine) {
295
        this.filters = this.searchPage.prepareFiltersToShow(filters, totalResults);
296
        this.rangeFilters = this.searchPage.prepareRangeFiltersToShow();
297
      }
298

    
299
      this.searchUtils.refineStatus = this.errorCodes.DONE;
300
      if(totalResults == 0) {
301
        this.searchUtils.refineStatus = this.errorCodes.NONE;
302
      }
303

    
304
      if (this.searchUtils.refineStatus == this.errorCodes.DONE) {
305
        // Page out of limit!!!
306
        let totalPages: any = totalResults / (this.searchUtils.size);
307
        if (!(Number.isInteger(totalPages))) {
308
          totalPages = (parseInt(totalPages, 10) + 1);
309
        }
310
        if (totalPages < page) {
311
          this.searchUtils.refineStatus = this.errorCodes.OUT_OF_BOUND;
312
        }
313
      }
314

    
315
      if(this.searchUtils.refineStatus != this.errorCodes.DONE && this.searchUtils.status != this.searchUtils.refineStatus) {
316
        if (this.searchResultsSub) {
317
          this.searchResultsSub.unsubscribe();
318
        }
319
        this.resultsReturned(refine, [], totalResults, page);
320
      }
321

    
322
      this.disableRefineForms = false;
323
    }
324

    
325
  public _getResults(parameters: string, page: number, size: number, sortBy: string, refine: boolean, refineFieldsFilterQuery = null) {
326
    if(this.usedBy == "orcid" && this.orcidQuery) {
327
      parameters += (parameters ? ' and ' : '') + "(" + this.orcidQuery + ")";
328
    }
329
    if (page > this.pagingLimit) {
330
      size = 0;
331
    }
332
    if (page <= this.pagingLimit || this.searchUtils.status == this.errorCodes.LOADING) {
333
      // if (parameters != null && parameters != '') {
334
      //   this.csvParams = "&fq=(" + this.resourcesQuery + " and (" + parameters + "))";
335
      // } else {
336
      //   this.csvParams = "&fq=" + this.resourcesQuery;
337
      // }
338
      this.csvParams = (parameters ? ("&fq=(" + parameters) : "") + (parameters ? ")" : "");
339
      this.csvParams += (refineFieldsFilterQuery ? refineFieldsFilterQuery : "");
340
      
341
      this.searchUtils.status = this.errorCodes.LOADING;
342
      this.disableForms = true;
343
      this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils});
344
      this.results = [];
345
      this.searchUtils.totalResults = 0;
346
      //this.subs.push(this._searchResearchResultsService.advancedSearchResults(this.resultType, parameters, page, size, sortBy, this.properties, (refine) ? this.searchPage.getRefineFieldsQuery() : null, this.searchPage.getFields(), refineFieldsFilterQuery)
347
      this.searchResultsSub = this._searchResearchResultsService.advancedSearchResults(this.resultType, parameters, page, size, sortBy, this.properties, null, this.searchPage.getFields(), refineFieldsFilterQuery)
348
      //this.subs.push(this._searchResearchResultsService.advancedSearchResults(this.resultType, parameters, page, size, sortBy, this.properties, null, this.searchPage.getFields(), refineFieldsFilterQuery)
349
        .subscribe(
350
        data => {
351
          let totalResults = data[0];
352
          let results = data[1];
353

    
354
          // this.searchUtils.totalResults = totalResults;
355
          // this.results = results;
356
          // // if (refine) {
357
          // //   this.filters = this.searchPage.prepareFiltersToShow(data[2],this.searchUtils.totalResults);
358
          // //   this.rangeFilters = this.searchPage.prepareRangeFiltersToShow();
359
          // // } else {
360
          // if(!refine) {
361
          //   this.searchPage.buildPageURLParameters(this.filters, this.rangeFilters, false);
362
          // }
363
          //
364
          // this.searchPage.hideFilters = false;
365
          //
366
          // this.searchUtils.status = this.errorCodes.DONE;
367
          // if (this.searchUtils.totalResults == 0) {
368
          //   this.searchUtils.status = this.errorCodes.NONE;
369
          // }
370
          // this.disableForms = false;
371
          this.resultsReturned(refine, results, totalResults, page);
372
        },
373
        err => {
374
          this.handleError("Error getting " + this.getEntityName(this.resultType, true, true), err);
375
          this.searchUtils.status = this.errorMessages.getErrorCode(err.status);
376

    
377
          //TODO check erros (service not available, bad request)
378
          // if( ){
379
          //   this.searchUtils.status = ErrorCodes.ERROR;
380
          // }
381
          //var errorCodes:ErrorCodes = new ErrorCodes();
382
          //this.searchUtils.status = errorCodes.NOT_AVAILABLE;
383
          /*if(err.status == '404') {
384
            this.searchUtils.status = this.errorCodes.NOT_FOUND;
385
          } else if(err.status == '500') {
386
            this.searchUtils.status = this.errorCodes.ERROR;
387
          } else {
388
            this.searchUtils.status = this.errorCodes.NOT_AVAILABLE;
389
          }*/
390

    
391
          //this.searchPage.closeLoading();
392
          this.disableForms = false;
393
          this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils})
394
          this.searchPage.hideFilters = false;
395
        }
396
      );
397
    }
398
  }
399

    
400
  public resultsReturned(refine: boolean, results: any, totalResults, page: number) {
401
    this.searchUtils.totalResults = totalResults;
402
    this.results = results;
403
    if(!refine) {
404
      this.searchPage.buildPageURLParameters(this.filters, this.rangeFilters, false);
405
    }
406

    
407
    this.searchPage.hideFilters = false;
408

    
409
    this.searchUtils.status = this.errorCodes.DONE;
410
    if (this.searchUtils.totalResults == 0) {
411
      this.searchUtils.status = this.errorCodes.NONE;
412
    }
413

    
414
    if (this.searchUtils.status == this.errorCodes.DONE) {
415
      // Page out of limit!!!
416
      let totalPages: any = this.searchUtils.totalResults / (this.searchUtils.size);
417
      if (!(Number.isInteger(totalPages))) {
418
        totalPages = (parseInt(totalPages, 10) + 1);
419
      }
420
      if (totalPages < page) {
421
        this.searchUtils.totalResults = 0;
422
        this.searchUtils.status = this.errorCodes.OUT_OF_BOUND;
423
      }
424
    }
425

    
426
    if(this.searchUtils.status != this.errorCodes.DONE && this.searchUtils.refineStatus != this.searchUtils.status) {
427
      if(this.searchFiltersSub) {
428
        this.searchFiltersSub.unsubscribe();
429
      }
430
      this.filtersReturned(refine, [], totalResults, page);
431
    }
432

    
433
    this.disableForms = false;
434
    this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils});
435
  }
436
  
437
  private handleError(message: string, error) {
438
    console.error(this.getEntityName(this.resultType, true, true) + " advanced Search Page: " + message, error);
439
  }
440
  
441
  public getEntityName(entityType: string, plural: boolean, full: boolean): string {
442
    if (entityType == "publication") {
443
      return "publication" + (plural ? "s" : "");
444
    } else if (entityType == "dataset") {
445
      return (full ? "research data" : ("dataset" + (plural ? "s" : "")));
446
    } else if (entityType == "software") {
447
      return "software";
448
    } else if (entityType == "other") {
449
      return (full ? ("other research product" + (plural ? "s" : "")) : "other");
450
    } else if (entityType == "result") {
451
      return (full ? ("research outcome" + (plural ? "s" : "")) : "result");
452
    }
453
  }
454
}
(7-7/8)