Project

General

Profile

1
import {Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, 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) 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 (params['page'] != undefined && this.filters && !firstLoad && this.searchUtils.page != +params['page']) {
146
        refine = false;
147
      }
148

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

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

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

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

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

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

    
217
    return Promise.race([this.promise, timeoutPromise]);
218
  }
219

    
220

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

    
237
              // if (refine) {
238
              //   this.filters = this.searchPage.prepareFiltersToShow(filters, totalResults);
239
              //   this.rangeFilters = this.searchPage.prepareRangeFiltersToShow();
240
              // }
241
              //
242
              // this.searchUtils.refineStatus = this.errorCodes.DONE;
243
              //
244
              // this.disableRefineForms = false;
245
              this.filtersReturned(refine, filters, totalResults, page);
246
              this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils})
247
            },
248
            err => {
249
              this.handleError("Error getting " + this.getEntityName(this.resultType, true, true), err);
250
              this.searchUtils.refineStatus = this.errorMessages.getErrorCode(err.status);
251

    
252
              this.disableRefineForms = false;
253
              this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils})
254
            }
255
          );//);
256
      }
257
  }
258

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

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

    
289
      if (refine) {
290
        this.filters = this.searchPage.prepareFiltersToShow(filters, totalResults);
291
        this.rangeFilters = this.searchPage.prepareRangeFiltersToShow();
292
      }
293

    
294
      this.searchUtils.refineStatus = this.errorCodes.DONE;
295
      if(totalResults == 0) {
296
        this.searchUtils.refineStatus = this.errorCodes.NONE;
297
      }
298

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

    
310
      if(this.searchUtils.refineStatus != this.errorCodes.DONE && this.searchUtils.status != this.searchUtils.refineStatus) {
311
        if (this.searchResultsSub) {
312
          this.searchResultsSub.unsubscribe();
313
        }
314
        this.resultsReturned(refine, [], totalResults, page);
315
      }
316

    
317
      this.disableRefineForms = false;
318
    }
319

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

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

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

    
386
          //this.searchPage.closeLoading();
387
          this.disableForms = false;
388
          this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils})
389
          this.searchPage.hideFilters = false;
390
        }
391
      );
392
    }
393
  }
394

    
395
  public resultsReturned(refine: boolean, results: any, totalResults, page: number) {
396
    this.searchUtils.totalResults = totalResults;
397
    this.results = results;
398
    if(!refine) {
399
      this.searchPage.buildPageURLParameters(this.filters, this.rangeFilters, false);
400
    }
401

    
402
    this.searchPage.hideFilters = false;
403

    
404
    this.searchUtils.status = this.errorCodes.DONE;
405
    if (this.searchUtils.totalResults == 0) {
406
      this.searchUtils.status = this.errorCodes.NONE;
407
    }
408

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

    
421
    if(this.searchUtils.status != this.errorCodes.DONE && this.searchUtils.refineStatus != this.searchUtils.status) {
422
      if(this.searchFiltersSub) {
423
        this.searchFiltersSub.unsubscribe();
424
      }
425
      this.filtersReturned(refine, [], totalResults, page);
426
    }
427

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