import {Component, ViewChild} from "@angular/core"; import {SearchUtilsClass} from "../openaireLibrary/searchPages/searchUtils/searchUtils.class"; import {ErrorMessagesComponent} from "../openaireLibrary/utils/errorMessages.component"; import {ErrorCodes} from "../openaireLibrary/utils/properties/errorCodes"; import {EnvProperties} from "../openaireLibrary/utils/properties/env-properties"; import {ActivatedRoute} from "@angular/router"; import {AdvancedField, Filter, Value} from "../openaireLibrary/searchPages/searchUtils/searchHelperClasses.class"; import {SearchFields} from "../openaireLibrary/utils/properties/searchFields"; import {Session, User} from "../openaireLibrary/login/utils/helper.class"; import {StringUtils} from "../openaireLibrary/utils/string-utils.class"; import {HelperFunctions} from "../openaireLibrary/utils/HelperFunctions.class"; import {UserManagementService} from "../openaireLibrary/services/user-management.service"; import {StakeholderService} from "../openaireLibrary/monitor/services/stakeholder.service"; import {NewSearchPageComponent} from "../openaireLibrary/searchPages/searchUtils/newSearchPage.component"; import {StakeholderInfo} from "../openaireLibrary/monitor/entities/stakeholder"; import {properties} from "../../environments/environment"; import {Subscriber} from "rxjs"; @Component({ selector: 'search-stakeholders', template: ` ` }) export class SearchStakeholdersComponent { public piwikSiteId = null; private errorCodes: ErrorCodes; private errorMessages: ErrorMessagesComponent; public results: StakeholderInfo[] = []; public totalResults: StakeholderInfo[] = []; public subscriptions = []; public filters = []; public searchFields: SearchFields = new SearchFields(); public searchUtils: SearchUtilsClass = new SearchUtilsClass(); public selectedFields: AdvancedField[] = []; public disableForms: boolean = false; public baseUrl: string = null; public fieldIds: string[] = ["q"]; public refineFields: string[] = this.searchFields.STAKEHOLDER_SEARCH_FIELDS; public fieldIdsMap = { ["q"]: { name: "All fields", type: "keyword", param: "q", operator: "op", equalityOperator: "=", filterType: null } }; public keyword = ""; public searchLink; properties: EnvProperties = properties; @ViewChild(NewSearchPageComponent, { static: true }) searchPage: NewSearchPageComponent; private user: User; private userFilterLoaded: boolean = false; constructor(private route: ActivatedRoute, private _stakeholderService: StakeholderService, private userManagementService: UserManagementService) { this.errorCodes = new ErrorCodes(); this.errorMessages = new ErrorMessagesComponent(); this.searchUtils.status = this.errorCodes.LOADING; } public ngOnInit() { this.piwikSiteId = this.properties.piwikSiteId; this.baseUrl = this.properties.searchLinkToStakeholders; this.subscriptions.push(this.route.queryParams.subscribe(params => { this.searchPage.resultsPerPage = 10; this.keyword = (params['fv0'] ? params['fv0'] : ''); this.keyword = StringUtils.URIDecode(this.keyword); this.searchUtils.page = (params['page'] === undefined) ? 1 : +params['page']; this.searchUtils.sortBy = (params['sortBy'] === undefined) ? '' : params['sortBy']; this.searchUtils.size = (params['size'] === undefined) ? this.searchPage.resultsPerPage : +params['size']; this.searchUtils.baseUrl = this.baseUrl; this.searchPage.searchUtils = this.searchUtils; if (this.searchUtils.size != 5 && this.searchUtils.size != 10 && this.searchUtils.size != 20 && this.searchUtils.size != 50) { this.searchUtils.size = this.searchPage.resultsPerPage; } if (this.searchUtils.sortBy && this.searchUtils.sortBy != "creationdate,descending" && this.searchUtils.sortBy != "creationdate,ascending") { this.searchUtils.sortBy = ""; } this.searchPage.refineFields = this.refineFields; this.searchLink = this.properties.searchLinkToStakeholders; this.selectedFields = []; this.searchPage.prepareSearchPage(this.fieldIds, this.selectedFields, this.refineFields, [], this.fieldIdsMap, null, params, "stakeholder", null); let queryParams = params;//this.searchPage.getQueryParamsFromUrl(params); if (typeof document !== 'undefined') { this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => { this.user = user; this.initFunders(queryParams); })); } else { this.initFunders(queryParams); } })); } ngOnDestroy() { this.subscriptions.forEach(subscription => { if (subscription instanceof Subscriber) { subscription.unsubscribe(); } }); } /** * Initialize stakeholders from Communities APIs * * @param params */ private initFunders(params) { this.subscriptions.push(this._stakeholderService.getStakeholders(this.properties.monitorServiceAPIURL).subscribe( data => { if (!data) { return; } data = data.filter(stakeholder => stakeholder.visibility !== 'PRIVATE'); for (let i = 0; i < data.length; i++) { this.totalResults[i] = data[i]; this.totalResults[i].isManager = this.isStakeholderManager(data[i]); this.totalResults[i].isMember = this.isStakeholderMember(data[i]); } this._getResults(params); }, err => { this.handleError('Error getting stakeholders', err); this.searchUtils.status = this.errorMessages.getErrorCode(err.status); this.disableForms = false; } )); } /** * Get all stakeholders from mock API and apply permission access validator, * keyword searching, filter, paging and sorting. * * @param params, status * @private */ private _getResults(params) { this.searchUtils.status = this.errorCodes.LOADING; this.disableForms = true; this.results = this.totalResults; this.filters = this.createFilters(); this.searchUtils.totalResults = 0; this.applyParams(params); } /** * Return the stakeholders in which user has permission to view or manage. */ private showFunders() { let ret = []; for (let result of this.results) { if(result.visibility === 'PUBLIC' || (result.visibility === 'RESTRICTED' && this.isStakeholderMember(result)) ) { ret.push(result); } } this.results = ret; } /** * Apply permission access validator, * keyword searching, filter, paging and sorting. * * @param params * @param status */ public applyParams(params) { this.showFunders(); if (this.keyword && this.keyword != '') { this.searchForKeywords(); } this.checkFilters(params); this.sort(); this.searchUtils.totalResults = this.results.length; this.filters = this.searchPage.prepareFiltersToShow(this.filters, this.searchUtils.totalResults); this.results = this.results.slice((this.searchUtils.page - 1) * this.searchUtils.size, (this.searchUtils.page * this.searchUtils.size)); this.searchUtils.status = this.errorCodes.DONE; if (this.searchUtils.totalResults == 0) { this.searchUtils.status = this.errorCodes.NONE; } this.disableForms = false; if (this.searchUtils.status == this.errorCodes.DONE) { // Page out of limit!!! let totalPages: any = this.searchUtils.totalResults / (this.searchUtils.size); if (!(Number.isInteger(totalPages))) { totalPages = (parseInt(totalPages, 10) + 1); } if (totalPages < this.searchUtils.page) { this.searchUtils.totalResults = 0; this.searchUtils.status = this.errorCodes.OUT_OF_BOUND; } } } /** * Parse the given keywords into array and check if any of the requirements field of a funder includes * one of the given words. */ private searchForKeywords() { let ret = []; let keywords: string[] = this.keyword.split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/, -1); for (let i = 0; i < this.results.length; i++) { for (let keyword of keywords) { keyword = keyword.toLowerCase(); if (keyword != '' && (StringUtils.containsWord(this.results[i].name, keyword) || StringUtils.containsWord(this.results[i].index_shortName, keyword) || StringUtils.containsWord(this.results[i].alias, keyword) || StringUtils.containsWord(this.results[i].description, keyword))) { ret.push(this.results[i]); break; } } } this.results = ret; } /** * Check the current results if they satisfy the values of each filter category and * update the number of possible results in each value. * * @param params */ private checkFilters(params) { let typeResults: StakeholderInfo[] = this.applyFilter('type', params); let accessResults: StakeholderInfo[] = this.results; let roleResults: StakeholderInfo[] = this.results; if (this.user) { accessResults = this.applyFilter('access', params); roleResults = this.applyFilter('role', params); this.resetFilterNumbers('access'); this.updateFilterNumbers(typeResults.filter(value => { return roleResults.includes(value); }), 'access'); this.resetFilterNumbers('role'); this.updateFilterNumbers(accessResults.filter(value => { return typeResults.includes(value); }), 'role'); } this.resetFilterNumbers('type'); this.updateFilterNumbers(accessResults.filter(value => { return roleResults.includes(value); }), 'type'); this.results = accessResults.filter(value => { return typeResults.includes(value); }) this.results = this.results.filter(value => { return roleResults.includes(value); }); } /** * Apply filter with filterId and return the results * * @param filterId * @param params */ private applyFilter(filterId: string, params): StakeholderInfo[] { let results = []; let values: string[] = []; if (params[filterId]) { values = (StringUtils.URIDecode(params[filterId])).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/, -1); } if (filterId == 'type') { for (let i = 0; i < this.results.length; i++) { if (values.length == 0) { results.push(this.results[i]); } else { for (let value of values) { if (this.results[i].type == value.replace(/["']/g, "")) { results.push(this.results[i]); break; } } } } } else if (filterId == 'access') { for (let i = 0; i < this.results.length; i++) { if (values.length == 0) { results.push(this.results[i]); } else { for (let value of values) { if (value.replace(/["']/g, "") == 'public') { if (this.results[i].visibility === 'PUBLIC') { results.push(this.results[i]); break; } } else if (value.replace(/["']/g, "") == 'restricted') { if (this.results[i].visibility === 'RESTRICTED') { results.push(this.results[i]); break; } } /*else if (value.replace(/["']/g, "") == 'private') { if (this.results[i].visibility === 'PRIVATE') { results.push(this.results[i]); break; } }*/ } } } } else if (filterId == 'role') { for (let i = 0; i < this.results.length; i++) { if (values.length == 0) { results.push(this.results[i]); } else { for (let value of values) { if (value.replace(/["']/g, "") == 'manager') { if (this.results[i].isManager) { results.push(this.results[i]); break; } } if (value.replace(/["']/g, "") == 'member') { if (this.results[i].isMember) { results.push(this.results[i]); break; } } } } } } return results; } /** * Reset the values of filter with id filterId with zero. * * @param filterId */ private resetFilterNumbers(filterId: string) { for (let i = 0; i < this.filters.length; i++) { if (this.filters[i].filterId == filterId) { for (let j = 0; j < this.filters[i].values.length; j++) { this.filters[i].values[j].number = 0; } break; } } } /** * Update the values of filter with id filterId based on * results. * * @param results * @param filterId */ private updateFilterNumbers(results: StakeholderInfo[], filterId: string) { for (let k = 0; k < results.length; k++) { for (let i = 0; i < this.filters.length; i++) { if (this.filters[i].filterId == filterId) { if (this.filters[i].filterId == 'type') { for (let j = 0; j < this.filters[i].values.length; j++) { if (results[k].type == this.filters[i].values[j].id) { this.filters[i].values[j].number++; } } } else if (this.filters[i].filterId == 'access') { if (results[k].visibility === 'PUBLIC') { this.filters[i].values[0].number++; } else if (results[k].visibility === 'RESTRICTED') { this.filters[i].values[1].number++; } else { this.filters[i].values[2].number++; } } else if (this.filters[i].filterId == 'role') { if (results[k].isManager) { this.filters[i].values[0].number++; } if (results[k].isMember) { this.filters[i].values[1].number++; } } break; } } } } /** * Sorting results based on sortBy. */ private sort() { if (this.searchUtils.sortBy == '') { this.results.sort((left, right): number => { if (left.name > right.name) { return 1; } else if (left.name < right.name) { return -1; } else { return 0; } }) } else if (this.searchUtils.sortBy == 'creationdate,descending') { this.results.sort((left, right): number => { if (!right.creationDate || left.creationDate > right.creationDate) { return -1; } else if (!left.creationDate || left.creationDate < right.creationDate) { return 1; } else { return 0; } }) } else if (this.searchUtils.sortBy == 'creationdate,ascending') { this.results.sort((left, right): number => { if (!right.creationDate || left.creationDate > right.creationDate) { return 1; } else if (!left.creationDate || left.creationDate < right.creationDate) { return -1; } else { return 0; } }) } } private isStakeholderManager(stakeholder) { return Session.isPortalAdministrator(this.user) || Session.isMonitorCurator(this.user) || Session.isCommunityCurator(this.user) || Session.isManager(stakeholder.type, stakeholder.alias, this.user); } private isStakeholderMember(stakeholder) { return this.isStakeholderManager(stakeholder) || Session.isSubscribedTo(stakeholder.type, stakeholder.alias, this.user); } /** * Create Search Stakeholder filters. * */ private createFilters(): Filter[] { let filter_names = []; let filter_ids = []; let value_names = []; let value_original_ids = []; filter_names.push("Type"); filter_ids.push("type"); value_names.push(["Funders", "Research Initiatives", "Organizations"]); value_original_ids.push(["funder", "ri", "organization"]); if (this.user) { filter_names.push("Accessibility"); filter_ids.push("access"); value_names.push(["Public", "Restricted"]); value_original_ids.push(["public", "restricted"]); filter_names.push("Role"); filter_ids.push("role"); value_names.push(["Manager", "Member"]); value_original_ids.push(["manager", "member"]); this.userFilterLoaded = true; } let filters: Filter[] = []; for (let i = 0; i < filter_names.length; i++) { let values: Value[] = []; for (let j = 0; j < value_names[i].length; j++) { let value: Value = {name: value_names[i][j], id: value_original_ids[i][j], number: 0, selected: false}; values.push(value); } let filter: Filter = { title: filter_names[i], filterId: filter_ids[i], originalFilterId: this.refineFields[i], values: values, countSelectedValues: 0, "filterOperator": 'or', valueIsExact: true, filterType: "checkbox" }; filters.push(filter); } return filters; } private handleError(message: string, error) { console.error('Communities Search Page: ' + message, error); } }