Project

General

Profile

1
import {Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild} from '@angular/core';
2
import {ActivatedRoute} 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
  constructor(private route: ActivatedRoute, private _searchResearchResultsService: SearchResearchResultsService,
102
              private _contextService: ContextsService) {
103
    this.results = [];
104
    this.errorCodes = new ErrorCodes();
105
    this.errorMessages = new ErrorMessagesComponent();
106
    this.searchUtils.status = this.errorCodes.LOADING;
107
    this.searchUtils.refineStatus = this.errorCodes.LOADING;
108
    this.getPublicCommunities();
109
  }
110
  
111
  ngOnInit() {
112
    //TODO add checks about which result types are enabled!
113
    this.pagingLimit = this.properties.pagingLimit;
114
    this.isPiwikEnabled = this.properties.enablePiwikTrack;
115
    
116
    if (!this.simpleSearchLink) {
117
      this.simpleSearchLink = this.properties.searchLinkToResults;
118
    }
119
    this.advancedSearchLink = this.properties.searchLinkToAdvancedResults;
120
    this.searchUtils.baseUrl = (this.simpleView) ? this.simpleSearchLink : this.advancedSearchLink;
121
    
122
    this.searchUtils.status = this.errorCodes.LOADING;
123
    var firstLoad = true;
124
    this.subs.push(this.route.queryParams.subscribe(params => {
125
    //this.subs.push(this.route.queryParams.switchMap(params => {
126
      this.loadPaging = true;
127
      if (params['page'] && this.searchUtils.page != params['page']) {
128
        this.loadPaging = false;
129
        this.oldTotalResults = this.searchUtils.totalResults;
130
      }
131
      var refine = true;
132
      if (params['page'] != undefined && this.filters && !firstLoad && this.searchUtils.page != +params['page']) {
133
        refine = false;
134
      }
135

    
136
      if (params['sortBy'] != undefined && this.filters && !firstLoad && this.searchUtils.sortBy != params['sortBy']) {
137
        refine = false;
138
      }
139

    
140
      if (params['size'] != undefined && this.filters && !firstLoad && this.searchUtils.size != params['size']) {
141
        refine = false;
142
      }
143

    
144
      let page = (params['page'] === undefined) ? 1 : +params['page'];
145
      this.searchUtils.page = (page <= 0) ? 1 : page;
146
      
147
      this.searchUtils.size = (params['size'] === undefined) ? 10 : +params['size'];
148
      if (this.searchUtils.size != 5 && this.searchUtils.size != 10 && this.searchUtils.size != 20 && this.searchUtils.size != 50) {
149
        this.searchUtils.size = 10;
150
      }
151
      this.searchUtils.sortBy = (params['sortBy']) ? params['sortBy'] : '';
152
      if (this.searchUtils.sortBy && this.searchUtils.sortBy != "resultdateofacceptance,descending" && this.searchUtils.sortBy != "resultdateofacceptance,ascending") {
153
        this.searchUtils.sortBy = "";
154
      }
155
      this.selectedFields = [];
156

    
157
      this.searchPage.prepareSearchPage(this.fieldIds, this.selectedFields, this.refineFields, this.rangeFields, this.fieldIdsMap,this.customFilter,params, this.resultType, this.quickFilter);
158
      if(refine) {
159
        this._getFilters(this.searchPage.getSearchAPIQueryForAdvancedSearhFields(), this.searchUtils.page, 0, "", true, this.searchPage.getSearchAPIQueryForRangeFields(params)+this.searchPage.getSearchAPIQueryForRefineFields(params, firstLoad));
160
      } else {
161
        this.searchUtils.refineStatus = this.errorCodes.DONE;
162
      }
163
      this._getResults(this.searchPage.getSearchAPIQueryForAdvancedSearhFields(), this.searchUtils.page, this.searchUtils.size, this.searchUtils.sortBy, refine, this.searchPage.getSearchAPIQueryForRangeFields(params) + this.searchPage.getSearchAPIQueryForRefineFields(params, firstLoad));
164
      firstLoad = false;
165
    }));
166
  }
167
  
168
  ngOnDestroy() {
169
    if(this.searchResultsSub) {
170
      this.searchResultsSub.unsubscribe();
171
    }
172
    if(this.searchFiltersSub) {
173
      this.searchFiltersSub.unsubscribe();
174
    }
175
    for (let sub of this.subs) {
176
      sub.unsubscribe();
177
    }
178
  }
179

    
180
  public getPublicCommunities() {
181
    this.promise = new Promise<any>(resolve => {
182
      this._contextService.getPublicCommunitiesByState().subscribe(
183
        data => {
184
          if(this.publicCommunities == null) {
185
            this.publicCommunities = data.map(value => value.id);
186
          }
187
          resolve();
188
        },
189
        error => {
190
          this.handleError("Error getting communities status", error);
191
          resolve();
192
        });
193
    });
194
  }
195

    
196
  racePromiseWithTimeout() {
197
    const timeoutPromise = new Promise((_, reject) => {
198
      this.timeoutId = setTimeout(() => {
199
        this.publicCommunities = [];
200
        reject(new Error('Request timed out'));
201
      }, 300);
202
    });
203

    
204
    return Promise.race([this.promise, timeoutPromise]);
205
  }
206

    
207

    
208
  public _getFilters(parameters: string, page: number, size: number, sortBy: string, refine: boolean, refineFieldsFilterQuery = null) {
209
      if (page <= this.pagingLimit || this.searchUtils.refineStatus == this.errorCodes.LOADING) {
210
        this.searchUtils.refineStatus = this.errorCodes.LOADING;
211
        this.disableRefineForms = true;
212
        this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils});
213
        this.searchFiltersSub = this._searchResearchResultsService.advancedSearchResults(this.resultType, parameters, page, size, sortBy, this.properties, (refine) ? this.searchPage.getRefineFieldsQuery() : null, this.searchPage.getFields(), refineFieldsFilterQuery)
214
        // this.subs.push(this._searchResearchResultsService.advancedSearchResults(this.resultType, parameters, page, size, sortBy, this.properties, (refine) ? this.searchPage.getRefineFieldsQuery() : null, this.searchPage.getFields(), refineFieldsFilterQuery)
215
          //.switchMap(
216
          .subscribe(
217
            data => {
218
              let totalResults = data[0];
219
              let filters = data[2];
220

    
221
              // if (refine) {
222
              //   this.filters = this.searchPage.prepareFiltersToShow(filters, totalResults);
223
              //   this.rangeFilters = this.searchPage.prepareRangeFiltersToShow();
224
              // }
225
              //
226
              // this.searchUtils.refineStatus = this.errorCodes.DONE;
227
              //
228
              // this.disableRefineForms = false;
229
              this.filtersReturned(refine, filters, totalResults, page);
230
              this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils})
231
            },
232
            err => {
233
              this.handleError("Error getting " + this.getEntityName(this.resultType, true, true), err);
234
              this.searchUtils.refineStatus = this.errorMessages.getErrorCode(err.status);
235

    
236
              this.disableRefineForms = false;
237
              this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils})
238
            }
239
          );//);
240
      }
241
  }
242

    
243
    public async filtersReturned(refine: boolean, filters: Filter[], totalResults, page: number) {
244
      if(!this.timeoutId) {
245
        try {
246
          await this.racePromiseWithTimeout();
247
        } catch (error) {
248
          this.handleError("Getting communities status was over 300ms - timeout", error);
249
        } finally {
250
          clearTimeout(this.timeoutId);
251
        }
252
      }
253

    
254
      let communitiesFilter = filters.find(filters => filters.filterId == "community");
255
      if(communitiesFilter && this.publicCommunities && this.publicCommunities.length > 0) {
256
        communitiesFilter.values = communitiesFilter.values.filter(value => {
257
          let valueId = "";
258
          if(value.id) {
259
            let idArray = value.id.split("||");
260
            if(idArray) {
261
              valueId = idArray[0];
262
            }
263
          }
264
          //for(let publicCom of this.publicCommunities) {
265
            //if(valueId && publicCom['id'] == valueId) {
266
          if(valueId && this.publicCommunities.includes(valueId)) {
267
              return true;
268
            //}
269
          }
270
        });
271
      }
272

    
273
      if (refine) {
274
        this.filters = this.searchPage.prepareFiltersToShow(filters, totalResults);
275
        this.rangeFilters = this.searchPage.prepareRangeFiltersToShow();
276
      }
277

    
278
      this.searchUtils.refineStatus = this.errorCodes.DONE;
279
      if(totalResults == 0) {
280
        this.searchUtils.refineStatus = this.errorCodes.NONE;
281
      }
282

    
283
      if (this.searchUtils.refineStatus == this.errorCodes.DONE) {
284
        // Page out of limit!!!
285
        let totalPages: any = totalResults / (this.searchUtils.size);
286
        if (!(Number.isInteger(totalPages))) {
287
          totalPages = (parseInt(totalPages, 10) + 1);
288
        }
289
        if (totalPages < page) {
290
          this.searchUtils.refineStatus = this.errorCodes.OUT_OF_BOUND;
291
        }
292
      }
293

    
294
      if(this.searchUtils.refineStatus != this.errorCodes.DONE && this.searchUtils.status != this.searchUtils.refineStatus) {
295
        if (this.searchResultsSub) {
296
          this.searchResultsSub.unsubscribe();
297
        }
298
        this.resultsReturned(refine, [], totalResults, page);
299
      }
300

    
301
      this.disableRefineForms = false;
302
    }
303

    
304
  public _getResults(parameters: string, page: number, size: number, sortBy: string, refine: boolean, refineFieldsFilterQuery = null) {
305
    if (page > this.pagingLimit) {
306
      size = 0;
307
    }
308
    if (page <= this.pagingLimit || this.searchUtils.status == this.errorCodes.LOADING) {
309
      // if (parameters != null && parameters != '') {
310
      //   this.csvParams = "&fq=(" + this.resourcesQuery + " and (" + parameters + "))";
311
      // } else {
312
      //   this.csvParams = "&fq=" + this.resourcesQuery;
313
      // }
314
      this.csvParams = (parameters ? ("&fq=(" + parameters) : "") + (parameters ? ")" : "");
315
      this.csvParams += (refineFieldsFilterQuery ? refineFieldsFilterQuery : "");
316
      
317
      this.searchUtils.status = this.errorCodes.LOADING;
318
      this.disableForms = true;
319
      this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils});
320
      this.results = [];
321
      this.searchUtils.totalResults = 0;
322
      //this.subs.push(this._searchResearchResultsService.advancedSearchResults(this.resultType, parameters, page, size, sortBy, this.properties, (refine) ? this.searchPage.getRefineFieldsQuery() : null, this.searchPage.getFields(), refineFieldsFilterQuery)
323
      this.searchResultsSub = this._searchResearchResultsService.advancedSearchResults(this.resultType, parameters, page, size, sortBy, this.properties, null, this.searchPage.getFields(), refineFieldsFilterQuery)
324
      //this.subs.push(this._searchResearchResultsService.advancedSearchResults(this.resultType, parameters, page, size, sortBy, this.properties, null, this.searchPage.getFields(), refineFieldsFilterQuery)
325
        .subscribe(
326
        data => {
327
          let totalResults = data[0];
328
          let results = data[1];
329

    
330
          // this.searchUtils.totalResults = totalResults;
331
          // this.results = results;
332
          // // if (refine) {
333
          // //   this.filters = this.searchPage.prepareFiltersToShow(data[2],this.searchUtils.totalResults);
334
          // //   this.rangeFilters = this.searchPage.prepareRangeFiltersToShow();
335
          // // } else {
336
          // if(!refine) {
337
          //   this.searchPage.buildPageURLParameters(this.filters, this.rangeFilters, false);
338
          // }
339
          //
340
          // this.searchPage.hideFilters = false;
341
          //
342
          // this.searchUtils.status = this.errorCodes.DONE;
343
          // if (this.searchUtils.totalResults == 0) {
344
          //   this.searchUtils.status = this.errorCodes.NONE;
345
          // }
346
          // this.disableForms = false;
347
          this.resultsReturned(refine, results, totalResults, page);
348
        },
349
        err => {
350
          this.handleError("Error getting " + this.getEntityName(this.resultType, true, true), err);
351
          this.searchUtils.status = this.errorMessages.getErrorCode(err.status);
352

    
353
          //TODO check erros (service not available, bad request)
354
          // if( ){
355
          //   this.searchUtils.status = ErrorCodes.ERROR;
356
          // }
357
          //var errorCodes:ErrorCodes = new ErrorCodes();
358
          //this.searchUtils.status = errorCodes.NOT_AVAILABLE;
359
          /*if(err.status == '404') {
360
            this.searchUtils.status = this.errorCodes.NOT_FOUND;
361
          } else if(err.status == '500') {
362
            this.searchUtils.status = this.errorCodes.ERROR;
363
          } else {
364
            this.searchUtils.status = this.errorCodes.NOT_AVAILABLE;
365
          }*/
366

    
367
          //this.searchPage.closeLoading();
368
          this.disableForms = false;
369
          this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils})
370
          this.searchPage.hideFilters = false;
371
        }
372
      );
373
    }
374
  }
375

    
376
  public resultsReturned(refine: boolean, results: any, totalResults, page: number) {
377
    this.searchUtils.totalResults = totalResults;
378
    this.results = results;
379
    if(!refine) {
380
      this.searchPage.buildPageURLParameters(this.filters, this.rangeFilters, false);
381
    }
382

    
383
    this.searchPage.hideFilters = false;
384

    
385
    this.searchUtils.status = this.errorCodes.DONE;
386
    if (this.searchUtils.totalResults == 0) {
387
      this.searchUtils.status = this.errorCodes.NONE;
388
    }
389

    
390
    if (this.searchUtils.status == this.errorCodes.DONE) {
391
      // Page out of limit!!!
392
      let totalPages: any = this.searchUtils.totalResults / (this.searchUtils.size);
393
      if (!(Number.isInteger(totalPages))) {
394
        totalPages = (parseInt(totalPages, 10) + 1);
395
      }
396
      if (totalPages < page) {
397
        this.searchUtils.totalResults = 0;
398
        this.searchUtils.status = this.errorCodes.OUT_OF_BOUND;
399
      }
400
    }
401

    
402
    if(this.searchUtils.status != this.errorCodes.DONE && this.searchUtils.refineStatus != this.searchUtils.status) {
403
      if(this.searchFiltersSub) {
404
        this.searchFiltersSub.unsubscribe();
405
      }
406
      this.filtersReturned(refine, [], totalResults, page);
407
    }
408

    
409
    this.disableForms = false;
410
    this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils});
411
  }
412
  
413
  private handleError(message: string, error) {
414
    console.error(this.getEntityName(this.resultType, true, true) + " advanced Search Page: " + message, error);
415
  }
416
  
417
  public getEntityName(entityType: string, plural: boolean, full: boolean): string {
418
    if (entityType == "publication") {
419
      return "publication" + (plural ? "s" : "");
420
    } else if (entityType == "dataset") {
421
      return (full ? "research data" : ("dataset" + (plural ? "s" : "")));
422
    } else if (entityType == "software") {
423
      return "software";
424
    } else if (entityType == "other") {
425
      return (full ? ("other research product" + (plural ? "s" : "")) : "other");
426
    } else if (entityType == "result") {
427
      return (full ? ("research outcome" + (plural ? "s" : "")) : "result");
428
    }
429
  }
430
}
(7-7/8)