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, User} 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 {HelperFunctions} from "../../openaireLibrary/utils/HelperFunctions.class";
16
import {UserManagementService} from "../../openaireLibrary/services/user-management.service";
17
import {Breadcrumb} from "../../openaireLibrary/utils/breadcrumbs/breadcrumbs.component";
18

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

    
55
  constructor (private route: ActivatedRoute,
56
               private _communitiesService: CommunitiesService,
57
               private _subscribeService: SubscribeService,
58
               private userManagementService: UserManagementService) {
59
    this.errorCodes = new ErrorCodes();
60
    this.errorMessages = new ErrorMessagesComponent();
61
    this.searchUtils.status = this.errorCodes.LOADING;
62
  }
63

    
64
  public ngOnInit() {
65
    this.route.data
66
        .subscribe((data: { envSpecific: EnvProperties }) => {
67
          this.properties = data.envSpecific;
68
          this.piwikSiteId = this.properties.piwikSiteId;
69
          this.baseUrl = data.envSpecific.searchLinkToCommunities;
70
        });
71
    this.sub =  this.route.queryParams.subscribe(params => {
72
      this.searchPage.resultsPerPage = 10;
73
      this.searchUtils.keyword = (params['keyword']?params['keyword']:'');
74
      this.searchUtils.page = (params['page'] === undefined) ? 1: + params['page'];
75
      this.searchUtils.sortBy = (params['sortBy'] === undefined)? '' : params['sortBy'];
76
      this.searchUtils.size = (params['size'] === undefined) ? this.searchPage.resultsPerPage: +params['size'];
77
      this.searchPage.searchUtils = this.searchUtils;
78
      if(this.searchUtils.size != 5 && this.searchUtils.size != 10 && this.searchUtils.size != 20 && this.searchUtils.size != 50) {
79
        this.searchUtils.size = this.searchPage.resultsPerPage;
80
      }
81
      if(this.searchUtils.sortBy && this.searchUtils.sortBy != "creationdate,descending" && this.searchUtils.sortBy != "creationdate,ascending") {
82
        this.searchUtils.sortBy = "";
83
      }
84
      this.searchPage.refineFields = this.refineFields;
85
      let queryParams = this.searchPage.getQueryParamsFromUrl(params);
86
      if(typeof document !== 'undefined') {
87
        this.userManagementService.getUserInfo().subscribe(user => {
88
          this.user = user;
89
          this.initCommunities(queryParams);
90
        });
91
      } else  {
92
        this.initCommunities(queryParams);
93
      }
94
    });
95
  }
96

    
97
  public ngOnDestroy() {
98
    if(this.sub){
99
      this.sub.unsubscribe();
100
    }
101
    if(this.subResults){
102
      this.subResults.unsubscribe();
103
    }
104
  }
105

    
106
  /**
107
   * Initialize communities from Communities APIs
108
   *
109
   * @param params
110
   */
111
  private initCommunities(params: Map<string, string>) {
112
    this.subResults = this._communitiesService.getCommunitiesState().subscribe(
113
        data => {
114
          if(!data){
115
            return;
116
          }
117
          for(let i = 0; i < data.length; i++) {
118
            this.totalResults[i] = data[i];
119
            this.totalResults[i].isManager = false;
120
            this.totalResults[i].isSubscribed = false;
121
            if(this.user) {
122
              this.totalResults[i].isManager = this.isCommunityManager(this.totalResults[i]);
123
            }
124
          }
125
          if(this.user) {
126
            this._subscribeService.getCommunitiesSubscribedTo(this.properties/*, this.user.email*/).subscribe(
127
              res => {
128
                for (let i = 0; i < this.totalResults.length; i++) {
129
                  this.totalResults[i].isSubscribed = (res.indexOf(this.totalResults[i].communityId) != -1);
130
                }
131
                this._getResults(params);
132
              }
133
            );
134
          }
135
          else {
136
            this._getResults(params);
137
          }
138
        },
139
        err => {
140
          this.handleError('Error getting communities', err);
141
          this.searchUtils.status = this.errorMessages.getErrorCode(err.status);
142
          this.disableForms = false;
143
          HelperFunctions.scroll();
144
        }
145
      );
146
  }
147

    
148

    
149
  /**
150
   * Get all communities from Communities API and apply permission access validator,
151
   * keyword searching, filter, paging and sorting.
152
   *
153
   * @param params, status
154
   * @private
155
   */
156
  private _getResults(params: Map<string, string>){
157
    this.searchUtils.status = this.errorCodes.LOADING;
158
    this.disableForms = true;
159
    this.results = this.totalResults;
160
    if(this.filters.length === 0) {
161
      this.filters = this.createFilters();
162
    }
163
    this.searchUtils.totalResults = 0;
164
    this.applyParams(params);
165
  }
166

    
167
  /**
168
   * Return the communities in which user has permission to view or manage.
169
   */
170
  private showCommunities() {
171
    let ret: CommunityInfo[] = [];
172
    for(let result of this.results) {
173
      if (result.status == 'hidden') {
174
        continue;
175
      } else if (result.status == "manager") {
176
        let mail = (this.user)?this.user.email:null;
177
        if (mail == null) { // no user
178
          continue;
179
        } else if (Session.isCommunityCurator(this.user) || Session.isPortalAdministrator(this.user)) {
180
          ret.push(result);
181
        } else if (result.managers.indexOf(mail) != -1) {
182
          ret.push(result);
183
        }
184
        continue;
185
      }
186
      ret.push(result);
187
    }
188
    this.results = ret;
189
  }
190

    
191
  /**
192
   * Apply permission access validator,
193
   * keyword searching, filter, paging and sorting.
194
   *
195
   * @param params
196
   * @param status
197
   */
198
  public applyParams(params: Map<string, string>) {
199
    this.showCommunities();
200
    if(this.searchUtils.keyword && this.searchUtils.keyword != '') {
201
      this.searchForKeywords();
202
    }
203
    this.checkFilters(params);
204
    this.sort();
205
    this.searchUtils.totalResults = this.results.length;
206
    this.searchPage.checkSelectedFilters(this.filters);
207
    this.searchPage.updateBaseUrlWithParameters(this.filters);
208
    this.results = this.results.slice((this.searchUtils.page-1)*this.searchUtils.size, (this.searchUtils.page*this.searchUtils.size));
209
    this.searchUtils.status = this.errorCodes.DONE;
210
    if(this.searchUtils.totalResults == 0 ){
211
      this.searchUtils.status = this.errorCodes.NONE;
212
    }
213
    this.disableForms = false;
214
    if(this.searchUtils.status == this.errorCodes.DONE) {
215
      // Page out of limit!!!
216
      let totalPages:any = this.searchUtils.totalResults/(this.searchUtils.size);
217
      if(!(Number.isInteger(totalPages))) {
218
        totalPages = (parseInt(totalPages, 10) + 1);
219
      }
220
      if(totalPages < this.searchUtils.page) {
221
        this.searchUtils.totalResults = 0;
222
        this.searchUtils.status = this.errorCodes.OUT_OF_BOUND;
223
      }
224
    }
225
    HelperFunctions.scroll();
226
  }
227

    
228

    
229
  /**
230
   * Parse the given keywords into array and check if any of the requirements field of a community includes
231
   * one of the given words.
232
   */
233
  private searchForKeywords() {
234
      let ret: CommunityInfo[] = [];
235
      let keywords: string[] = this.searchUtils.keyword.split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,-1);
236
      for(let i = 0; i < this.results.length; i++) {
237
          for(let keyword of keywords) {
238
            keyword = keyword.toLowerCase();
239
            if (keyword != '' && (this.results[i].title.toLowerCase().includes(keyword) || this.results[i].shortTitle.toLowerCase().includes(keyword) ||
240
                this.results[i].communityId.toLowerCase().includes(keyword) || this.results[i].description.toLowerCase().includes(keyword))) {
241
                ret.push(this.results[i]);
242
                break;
243
            }
244
          }
245
      }
246
      this.results = ret;
247
  }
248

    
249
  /**
250
   * Check the current results if they satisfy the values of each filter category and
251
   * update the number of possible results in each value.
252
   *
253
   * @param params
254
   */
255
  private checkFilters(params: Map<string, string>) {
256
    let typeResults: CommunityInfo[] = this.applyFilter('type', params);
257
    let statusResults: CommunityInfo[] = this.results;
258
    let roleResults: CommunityInfo[] = this.results;
259
    if(this.user) {
260
      statusResults = this.applyFilter('status', params);
261
      roleResults = this.applyFilter('role', params);
262
      this.resetFilterNumbers('status');
263
      this.updateFilterNumbers(typeResults.filter(value => {
264
        return roleResults.includes(value);
265
      }), 'status');
266
      this.resetFilterNumbers('role');
267
      this.updateFilterNumbers(statusResults.filter(value => {
268
        return typeResults.includes(value);
269
      }), 'role');
270
    }
271
    this.resetFilterNumbers('type');
272
    this.updateFilterNumbers(statusResults.filter(value => {
273
      return roleResults.includes(value);
274
    }), 'type');
275
    this.results = statusResults.filter(value => {
276
      return typeResults.includes(value);
277
    })
278
    this.results = this.results.filter(value => {
279
      return roleResults.includes(value);
280
    });
281
  }
282

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

    
349
    /**
350
     * Reset the values of filter with id filterId with zero.
351
     *
352
     * @param filterId
353
     */
354
  private resetFilterNumbers(filterId: string) {
355
    for (let i = 0; i < this.filters.length; i++) {
356
      if(this.filters[i].filterId == filterId) {
357
        for (let j = 0; j < this.filters[i].values.length; j++) {
358
          this.filters[i].values[j].number = 0;
359
        }
360
        break;
361
      }
362
    }
363
  }
364

    
365
    /**
366
     * Update the values of filter with id filterId based on
367
     * results.
368
     *
369
     * @param results
370
     * @param filterId
371
     */
372
  private updateFilterNumbers(results: CommunityInfo[], filterId: string) {
373
    for(let k = 0; k < results.length; k++) {
374
      for (let i = 0; i < this.filters.length; i++) {
375
        if(this.filters[i].filterId == filterId) {
376
            if (this.filters[i].filterId == 'type') {
377
                for (let j = 0; j < this.filters[i].values.length; j++) {
378
                    if (results[k].type == this.filters[i].values[j].id) {
379
                        this.filters[i].values[j].number++;
380
                    }
381
                }
382
            }
383
            else if (this.filters[i].filterId == 'status') {
384
                if (results[k].isSubscribed) {
385
                    this.filters[i].values[0].number++;
386
                } else {
387
                    this.filters[i].values[1].number++;
388
                }
389
            }
390
            else if (this.filters[i].filterId == 'role') {
391
                if (results[k].isManager) {
392
                  this.filters[i].values[0].number++;
393
                }
394
            }
395
            break;
396
        }
397
      }
398
    }
399
  }
400

    
401
    /**
402
     * Sorting results based on sortBy.
403
     */
404
  private sort() {
405
    if(this.searchUtils.sortBy == '') {
406
      this.results.sort((left, right): number => {
407
        if (left.title > right.title) {
408
          return 1;
409
        } else if (left.title < right.title) {
410
          return -1;
411
        } else {
412
          return 0;
413
        }
414
      })
415
    } else if(this.searchUtils.sortBy == 'creationdate,descending') {
416
      this.results.sort((left, right): number => {
417
        if (!right.date || left.date > right.date) {
418
          return -1;
419
        } else if (!left.date || left.date < right.date) {
420
          return 1;
421
        } else {
422
          return 0;
423
        }
424
      })
425
    } else if(this.searchUtils.sortBy == 'creationdate,ascending') {
426
      this.results.sort((left, right): number => {
427
        if (!right.date || left.date > right.date) {
428
          return 1;
429
        } else if (!left.date || left.date < right.date) {
430
          return -1;
431
        } else {
432
          return 0;
433
        }
434
      })
435
    }
436
  }
437

    
438

    
439
  private isCommunityManager(community: CommunityInfo): boolean {
440
    return Session.isCommunityCurator(this.user) || community.managers.indexOf(this.user.email) != -1;
441
  }
442

    
443
    /**
444
     * Create Search Communities filters.
445
     *
446
     */
447
  private createFilters(): Filter[] {
448
    let filter_names = [];
449
    let filter_ids = [];
450
    let searchFields = new SearchFields();
451
    let filter_original_ids = searchFields.COMMUNITIES_SEARCH_FIELDS;
452
    let value_names = [];
453
    let value_original_ids=[];
454
    this.showType = this.results.filter(community => community.type === 'ri').length > 0;
455
    if(this.showType) {
456
      filter_names.push("Type");
457
      filter_ids.push("type");
458
      value_names.push([ "Research Communities", "Research Initiatives" ]);
459
      value_original_ids.push(["community","ri"]);
460
    } else {
461
      filter_original_ids = searchFields.COMMUNITIES_SEARCH_FIELDS.splice(0, 1);
462
    }
463
    if(this.user) {
464
      filter_names.push("Status");
465
      filter_ids.push("status");
466
      value_names.push([ "Subscribed", "Non-subscribed"]);
467
      value_original_ids.push(["subscribed", "nonsubscribed"]);
468
      filter_names.push("Role");
469
      filter_ids.push("role");
470
      value_names.push([ "Manager"]);
471
      value_original_ids.push(["manager"]);
472
    }
473
    let filters: Filter[] = [];
474
    for(let  i =0 ; i < filter_names.length; i++){
475
      let values: Value[] = [];
476
      for(let j =0 ; j < value_names[i].length; j++){
477
        let value: Value = {name: value_names[i][j], id: value_original_ids[i][j], number:0, selected:false};
478
        values.push(value);
479
      }
480
      let filter: Filter = {title: filter_names[i], filterId: filter_ids[i], originalFilterId:  filter_original_ids[i], values : values, countSelectedValues:0, "filterOperator": 'or', valueIsExact: true , filterType: "checkbox"};
481
      filters.push(filter);
482
    }
483
    return filters;
484
  }
485

    
486
  private handleError(message: string, error) {
487
    console.error('Communities Search Page: ' + message, error);
488
  }
489

    
490
}
(2-2/3)