Project

General

Profile

1
import {Component, ViewChild} from "@angular/core";
2
import {SearchUtilsClass} from "../../openaireLibrary/searchPages/searchUtils/searchUtils.class";
3
import {ErrorMessagesComponent} from "../../openaireLibrary/utils/errorMessages.component";
4
import {ErrorCodes} from "../../openaireLibrary/utils/properties/errorCodes";
5
import {EnvProperties} from "../../openaireLibrary/utils/properties/env-properties";
6
import {SearchPageComponent} from "../../openaireLibrary/searchPages/searchUtils/searchPage.component";
7
import {ActivatedRoute} from "@angular/router";
8
import {Filter, Value} from "../../openaireLibrary/searchPages/searchUtils/searchHelperClasses.class";
9
import {SearchFields} from "../../openaireLibrary/utils/properties/searchFields";
10
import {CommunitiesService} from "../../openaireLibrary/connect/communities/communities.service";
11
import {Session} from "../../openaireLibrary/login/utils/helper.class";
12
import {CommunityInfo} from "../../openaireLibrary/connect/community/communityInfo";
13
import {SubscribeService} from "../../openaireLibrary/utils/subscribe/subscribe.service";
14
import {StringUtils} from "../../openaireLibrary/utils/string-utils.class";
15
import {PiwikService} from "../../openaireLibrary/utils/piwik/piwik.service";
16
import {HelperFunctions} from "../../openaireLibrary/utils/HelperFunctions.class";
17

    
18
@Component({
19
  selector: 'search-communities',
20
  template: `
21
      <search-page pageTitle="OpenAIRE-Connect | Search Communities"
22
                   [hasPrefix]=false searchFormClass="communitiesSearchForm"
23
                   formPlaceholderText="Search for Research Communities and Initiatives"
24
                   type="communities" entityType="community" [filters]="filters"
25
                   [results]="results" [searchUtils]="searchUtils"
26
                   [showResultCount]=true [baseUrl]="baseUrl"
27
                   [disableForms]="disableForms"
28
                   [lastIndex]=false [sort]=true>
29
      </search-page>
30
  `
31
})
32
export class SearchCommunitiesComponent {
33
  public piwiksub: any;
34
  private errorCodes: ErrorCodes;
35
  private errorMessages: ErrorMessagesComponent;
36
  public results: CommunityInfo[] = [];
37
  public totalResults: CommunityInfo[] = [];
38
  public sub: any; public subResults: any;
39
  public filters = [];
40
  public searchFields:SearchFields = new SearchFields();
41
  public searchUtils:SearchUtilsClass = new SearchUtilsClass();
42
  public disableForms: boolean = false;
43
  public baseUrl: string = null;
44
  public refineFields: string[] =  this.searchFields.COMMUNITIES_SEARCH_FIELDS;
45
  properties:EnvProperties;
46
  @ViewChild (SearchPageComponent) searchPage : SearchPageComponent ;
47

    
48
  constructor (private route: ActivatedRoute,
49
               private _communitiesService: CommunitiesService,
50
               private _subscribeService: SubscribeService,
51
               private _piwikService: PiwikService) {
52
    this.errorCodes = new ErrorCodes();
53
    this.errorMessages = new ErrorMessagesComponent();
54
    this.searchUtils.status = this.errorCodes.LOADING;
55
  }
56

    
57
  public ngOnInit() {
58
    this.route.data
59
        .subscribe((data: { envSpecific: EnvProperties }) => {
60
          this.properties = data.envSpecific;
61
          this.baseUrl = data.envSpecific.searchLinkToCommunities;
62
          if(this.properties.enablePiwikTrack && (typeof document !== 'undefined')){
63
            this.piwiksub = this._piwikService.trackView(this.properties, "OpenAIRE Connect|Search Communities", this.properties.piwikSiteId).subscribe();
64
          }
65
        });
66
    this.sub =  this.route.queryParams.subscribe(params => {
67
      this.searchPage.resultsPerPage = 5;
68
      this.searchUtils.keyword = (params['keyword']?params['keyword']:'');
69
      this.searchUtils.page = (params['page'] === undefined) ? 1: + params['page'];
70
      this.searchUtils.sortBy = (params['sortBy'] === undefined)? '' : params['sortBy'];
71
      this.searchUtils.size = (params['size'] === undefined) ? this.searchPage.resultsPerPage: +params['size'];
72
      this.searchPage.searchUtils = this.searchUtils;
73
      if(this.searchUtils.size != 5 && this.searchUtils.size != 10 && this.searchUtils.size != 20 && this.searchUtils.size != 50) {
74
        this.searchUtils.size = this.searchPage.resultsPerPage;
75
      }
76
      if(this.searchUtils.sortBy && this.searchUtils.sortBy != "creationdate,descending" && this.searchUtils.sortBy != "creationdate,ascending") {
77
        this.searchUtils.sortBy = "";
78
      }
79
      this.searchPage.refineFields = this.refineFields;
80
      let queryParams = this.searchPage.getQueryParamsFromUrl(params);
81
      this.filters = this.createFilters();
82

    
83
      this.initCommunities(queryParams);
84
    });
85
  }
86

    
87
  public ngOnDestroy() {
88
    if(this.sub){
89
      this.sub.unsubscribe();
90
    }
91
    if(this.subResults){
92
      this.subResults.unsubscribe();
93
    }
94
  }
95

    
96
  /**
97
   * Initialize communities from Communities APIs
98
   *
99
   * @param params
100
   */
101
  private initCommunities(params: Map<string, string>) {
102
    this.subResults = this._communitiesService.getCommunitiesState().subscribe(
103
        data => {
104
          for(let i = 0; i < data.length; i++) {
105
            this.totalResults[i] = data[i];
106
            this.totalResults[i].isManager = false;
107
            this.totalResults[i].isSubscribed = false;
108
            // For Test do not delete them.
109
            //this.results[i].description = "EGI is a federated e-Infrastructure set up to provide advanced computing services for research and innovation.EGI is a federated e-Infrastructure set up to provide advanced computing services for research and innovation.EGI is a federated e-Infrastructure set up to provide advanced computing services for research and innovation."
110
            //this.results[i].date = new Date(new Date(2012, 0, 1).getTime() + Math.random() * (new Date().getTime() - new Date(2012, 0, 1).getTime()));
111
            if(Session.isLoggedIn()) {
112
              this.totalResults[i].isManager = this.isCommunityManager(this.totalResults[i]);
113
            }
114
          }
115
          if(Session.isLoggedIn()) {
116
            this._subscribeService.getCommunitiesSubscribedTo(this.properties, Session.getUserEmail()).subscribe(
117
              res => {
118
                for (let i = 0; i < this.totalResults.length; i++) {
119
                  this.totalResults[i].isSubscribed = (res.indexOf(this.totalResults[i].communityId) != -1);
120
                }
121
                this._getResults(params);
122
              }
123
            );
124
          }
125
          else {
126
            this._getResults(params);
127
          }
128
        },
129
        err => {
130
          this.handleError('Error getting communities', err);
131
          this.searchUtils.status = this.errorMessages.getErrorCode(err.status);
132
          this.disableForms = false;
133
          HelperFunctions.scroll();
134
        }
135
      );
136
  }
137

    
138

    
139
  /**
140
   * Get all communities from Communities API and apply permission access validator,
141
   * keyword searching, filter, paging and sorting.
142
   *
143
   * @param params, status
144
   * @private
145
   */
146
  private _getResults(params: Map<string, string>){
147
    this.searchUtils.status = this.errorCodes.LOADING;
148
    this.disableForms = true;
149
    this.results = this.totalResults;
150
    this.searchUtils.totalResults = 0;
151
    this.applyParams(params);
152
  }
153

    
154
  /**
155
   * Return the communities in which user has permission to view or manage.
156
   */
157
  private showCommunities() {
158
    let ret: CommunityInfo[] = [];
159
    for(let result of this.results) {
160
      if (result.status == 'hidden') {
161
        continue;
162
      } else if (result.status == "manager") {
163
        let mail = Session.getUserEmail();
164
        if (mail == null) { // no user
165
          continue;
166
        } else if (Session.isCommunityCurator() || Session.isPortalAdministrator()) {
167
          ret.push(result);
168
        } else if (result.managers.indexOf(mail) != -1) {
169
          ret.push(result);
170
        }
171
        continue;
172
      }
173
      ret.push(result);
174
    }
175
    this.results = ret;
176
  }
177

    
178
  /**
179
   * Apply permission access validator,
180
   * keyword searching, filter, paging and sorting.
181
   *
182
   * @param params
183
   * @param status
184
   */
185
  public applyParams(params: Map<string, string>) {
186
    this.showCommunities();
187
    if(this.searchUtils.keyword && this.searchUtils.keyword != '') {
188
      this.searchForKeywords();
189
    }
190
    this.checkFilters(params);
191
    this.sort();
192
    this.searchUtils.totalResults = this.results.length;
193
    this.searchPage.checkSelectedFilters(this.filters);
194
    this.searchPage.updateBaseUrlWithParameters(this.filters);
195
    this.results = this.results.slice((this.searchUtils.page-1)*this.searchUtils.size, (this.searchUtils.page*this.searchUtils.size));
196
    this.searchUtils.status = this.errorCodes.DONE;
197
    if(this.searchUtils.totalResults == 0 ){
198
      this.searchUtils.status = this.errorCodes.NONE;
199
    }
200
    this.disableForms = false;
201
    if(this.searchUtils.status == this.errorCodes.DONE) {
202
      // Page out of limit!!!
203
      let totalPages:any = this.searchUtils.totalResults/(this.searchUtils.size);
204
      if(!(Number.isInteger(totalPages))) {
205
        totalPages = (parseInt(totalPages, 10) + 1);
206
      }
207
      if(totalPages < this.searchUtils.page) {
208
        this.searchUtils.totalResults = 0;
209
        this.searchUtils.status = this.errorCodes.OUT_OF_BOUND;
210
      }
211
    }
212
    HelperFunctions.scroll();
213
  }
214

    
215

    
216
  /**
217
   * Parse the given keywords into array and check if any of the requirements field of a community includes
218
   * one of the given words.
219
   */
220
  private searchForKeywords() {
221
      let ret: CommunityInfo[] = [];
222
      let keywords: string[] = this.searchUtils.keyword.split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
223
      for(let i = 0; i < this.results.length; i++) {
224
          for(let keyword of keywords) {
225
            keyword = keyword.toLowerCase();
226
            if (keyword != '' && (this.results[i].title.toLowerCase().includes(keyword) || this.results[i].shortTitle.toLowerCase().includes(keyword) ||
227
                this.results[i].communityId.toLowerCase().includes(keyword) || this.results[i].description.toLowerCase().includes(keyword))) {
228
                ret.push(this.results[i]);
229
                break;
230
            }
231
          }
232
      }
233
      this.results = ret;
234
  }
235

    
236
  /**
237
   * Check the current results if they satisfy the values of each filter category and
238
   * update the number of possible results in each value.
239
   *
240
   * @param params
241
   */
242
  private checkFilters(params: Map<string, string>) {
243
    let typeResults: CommunityInfo[] = this.applyFilter('type', params);
244
    let statusResults: CommunityInfo[] = this.results;
245
    let roleResults: CommunityInfo[] = this.results;
246
    if(Session.isLoggedIn()) {
247
      statusResults = this.applyFilter('status', params);
248
      roleResults = this.applyFilter('role', params);
249
      this.resetFilterNumbers('status');
250
      this.updateFilterNumbers(typeResults.filter(value => {
251
        return roleResults.includes(value);
252
      }), 'status');
253
      this.resetFilterNumbers('role');
254
      this.updateFilterNumbers(statusResults.filter(value => {
255
        return typeResults.includes(value);
256
      }), 'role');
257
    }
258
    this.resetFilterNumbers('type');
259
    this.updateFilterNumbers(statusResults.filter(value => {
260
      return roleResults.includes(value);
261
    }), 'type');
262
    this.results = statusResults.filter(value => {
263
      return typeResults.includes(value);
264
    })
265
    this.results = this.results.filter(value => {
266
      return roleResults.includes(value);
267
    });
268
  }
269

    
270
  /**
271
   * Apply filter with filterId and return the results
272
   *
273
   * @param filterId
274
   * @param params
275
   */
276
  private applyFilter(filterId: string, params: Map<string, string>): CommunityInfo[] {
277
    let results:CommunityInfo[] = [];
278
    let values: string[] = [];
279
    if(params.get(filterId) != undefined) {
280
      values = (StringUtils.URIDecode(params.get(filterId))).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
281
    }
282
    if(filterId == 'type') {
283
      for (let i = 0; i < this.results.length; i++) {
284
        if (values.length == 0) {
285
          results.push(this.results[i]);
286
        } else {
287
          for (let value of values) {
288
            if (this.results[i].type == value.replace(/["']/g, "")) {
289
              results.push(this.results[i]);
290
              break;
291
            }
292
          }
293
        }
294
      }
295
    }
296
    else if(filterId == 'status') {
297
      for (let i = 0; i < this.results.length; i++) {
298
        if (values.length == 0) {
299
          results.push(this.results[i]);
300
        } else {
301
          for (let value of values) {
302
            if (value.replace(/["']/g, "") == 'subscribed') {
303
              if (this.results[i].isSubscribed) {
304
                results.push(this.results[i]);
305
                break;
306
              }
307
            } else if (value.replace(/["']/g, "") == 'nonsubscribed') {
308
              if (!this.results[i].isSubscribed) {
309
                results.push(this.results[i]);
310
                break;
311
              }
312
            }
313
          }
314
        }
315
      }
316
    }
317
    else if(filterId == 'role') {
318
      for (let i = 0; i < this.results.length; i++) {
319
        if (values.length == 0) {
320
          results.push(this.results[i]);
321
        } else {
322
          for (let value of values) {
323
            if (value.replace(/["']/g, "") == 'manager') {
324
              if (this.results[i].isManager) {
325
                results.push(this.results[i]);
326
                break;
327
              }
328
            }
329
          }
330
        }
331
      }
332
    }
333
    return results;
334
  }
335

    
336
    /**
337
     * Reset the values of filter with id filterId with zero.
338
     *
339
     * @param filterId
340
     */
341
  private resetFilterNumbers(filterId: string) {
342
    for (let i = 0; i < this.filters.length; i++) {
343
      if(this.filters[i].filterId == filterId) {
344
        for (let j = 0; j < this.filters[i].values.length; j++) {
345
          this.filters[i].values[j].number = 0;
346
        }
347
        break;
348
      }
349
    }
350
  }
351

    
352
    /**
353
     * Update the values of filter with id filterId based on
354
     * results.
355
     *
356
     * @param results
357
     * @param filterId
358
     */
359
  private updateFilterNumbers(results: CommunityInfo[], filterId: string) {
360
    for(let k = 0; k < results.length; k++) {
361
      for (let i = 0; i < this.filters.length; i++) {
362
        if(this.filters[i].filterId == filterId) {
363
            if (this.filters[i].filterId == 'type') {
364
                for (let j = 0; j < this.filters[i].values.length; j++) {
365
                    if (results[k].type == this.filters[i].values[j].id) {
366
                        this.filters[i].values[j].number++;
367
                    }
368
                }
369
            }
370
            else if (this.filters[i].filterId == 'status') {
371
                if (results[k].isSubscribed) {
372
                    this.filters[i].values[0].number++;
373
                } else {
374
                    this.filters[i].values[1].number++;
375
                }
376
            }
377
            else if (this.filters[i].filterId == 'role') {
378
                if (results[k].isManager) {
379
                  this.filters[i].values[0].number++;
380
                }
381
            }
382
            break;
383
        }
384
      }
385
    }
386
  }
387

    
388
    /**
389
     * Sorting results based on sortBy.
390
     */
391
  private sort() {
392
    if(this.searchUtils.sortBy == '') {
393
      this.results.sort((left, right): number => {
394
        if (left.title > right.title) {
395
          return 1;
396
        } else if (left.title < right.title) {
397
          return -1;
398
        } else {
399
          return 0;
400
        }
401
      })
402
    } else if(this.searchUtils.sortBy == 'creationdate,descending') {
403
      this.results.sort((left, right): number => {
404
        if (!right.date || left.date > right.date) {
405
          return -1;
406
        } else if (!left.date || left.date < right.date) {
407
          return 1;
408
        } else {
409
          return 0;
410
        }
411
      })
412
    } else if(this.searchUtils.sortBy == 'creationdate,ascending') {
413
      this.results.sort((left, right): number => {
414
        if (!right.date || left.date > right.date) {
415
          return 1;
416
        } else if (!left.date || left.date < right.date) {
417
          return -1;
418
        } else {
419
          return 0;
420
        }
421
      })
422
    }
423
  }
424

    
425

    
426
  private isCommunityManager(community: CommunityInfo): boolean {
427
    return Session.isCommunityCurator() || community.managers.indexOf(Session.getUserEmail()) != -1;
428
  }
429

    
430
    /**
431
     * Create Search Communities filters.
432
     *
433
     */
434
  private createFilters(): Filter[] {
435
    let filter_names=["Type"];
436
    let filter_ids=["type"];
437
    let searchFields = new SearchFields();
438
    let filter_original_ids = searchFields.COMMUNITIES_SEARCH_FIELDS;
439
    let value_names = [
440
      [ "Research Communities", "Research Initiatives" ]
441
    ];
442
    let value_original_ids=[
443
      ["community","ri"]
444
    ];
445
    if(Session.isLoggedIn()) {
446
      filter_names[1] = "Status";
447
      filter_ids[1] = "status";
448
      value_names[1] = [ "Subscribed", "Non-subscribed"];
449
      value_original_ids[1] = ["subscribed", "nonsubscribed"];
450
      filter_names[2] = "Role";
451
      filter_ids[2] = "role";
452
      value_names[2] = [ "Manager" ];
453
      value_original_ids[2] = ["manager"];
454
    }
455
    let filters: Filter[] = [];
456
    for(let  i =0 ; i < filter_names.length; i++){
457
      let values: Value[] = [];
458
      for(let j =0 ; j < value_names[i].length; j++){
459
        let value: Value = {name: value_names[i][j], id: value_original_ids[i][j], number:0, selected:false};
460
        values.push(value);
461
      }
462
      let filter: Filter = {title: filter_names[i], filterId: filter_ids[i], originalFilterId:  filter_original_ids[i], values : values, countSelectedValues:0, "filterOperator": 'or', valueIsExact: true };
463
      filters.push(filter);
464
    }
465
    return filters;
466
  }
467

    
468
  private handleError(message: string, error) {
469
    console.error('Communities Search Page: ' + message, error);
470
  }
471

    
472
}
(2-2/3)