import {Component, Input, OnDestroy, OnInit, ViewChild} from '@angular/core'; import {Location} from '@angular/common'; import {ActivatedRoute, Router} from '@angular/router'; import {Subject, Subscriber} from 'rxjs'; import {debounceTime, distinctUntilChanged} from 'rxjs/operators'; import {ClaimsService} from '../service/claims.service'; import {User} from '../../../login/utils/helper.class'; import {EnvProperties} from '../../../utils/properties/env-properties'; import {SEOService} from '../../../sharedComponents/SEO/SEO.service'; import {IndexInfoService} from '../../../utils/indexInfo.service'; import {ClaimDBRecord} from '../claimHelper.class'; import {Dates} from '../../../utils/string-utils.class'; import {HelperService} from '../../../utils/helper/helper.service'; import {Meta, Title} from '@angular/platform-browser'; import {PiwikService} from '../../../utils/piwik/piwik.service'; import {properties} from '../../../../../environments/environment'; import {FormBuilder, FormGroup} from '@angular/forms'; import {Option} from '../../../sharedComponents/input/input.component'; import {OpenaireEntities} from "../../../utils/properties/searchFields"; import {HelperFunctions} from "../../../utils/HelperFunctions.class"; import {NotificationHandler} from "../../../utils/notification-handler"; import {DropdownFilterComponent} from "../../../utils/dropdown-filter/dropdown-filter.component"; @Component({ selector: 'displayClaims', templateUrl: 'displayClaims.component.html', styleUrls: ['displayClaims.component.less'] }) export class DisplayClaimsComponent implements OnInit, OnDestroy { @Input() pageTitle: string = ""; properties: EnvProperties; public searchTermStream = new Subject(); subscriptions: any = []; public subResults: any; //string because comes as input from component directive @Input() enableDelete: boolean = false; @Input() showUserEmail: boolean = true; @Input() myClaims: boolean = false; @Input() isAdmin: boolean = false; page: number = 1; size: number = 50; keyword: string; // the keyword string to give to the request as parameter types = ["All", "Project", "Context", "Result", "User"]; loading: boolean = false; @Input() fetchBy: string; @Input() fetchId: string; @Input() user: User; resultsNum: number = 0; claims: ClaimDBRecord[]; @Input() externalPortalUrl: string = null; @Input() claimsInfoURL: string;// ="https://www.openaire.eu/linking"; lastIndexDate = null; public filterForm: FormGroup; public entities: string[] = []; allOptions: Option[] = [ {label: OpenaireEntities.PUBLICATIONS, value: "publication"}, {label: OpenaireEntities.DATASETS, value: "dataset"}, {label: OpenaireEntities.SOFTWARE, value: "software"}, {label: OpenaireEntities.OTHER, value: "other"}, {label: OpenaireEntities.PROJECTS, value: "project"}, {label: OpenaireEntities.COMMUNITIES, value: "context"}]; sortOptions: Option[] = [ {label: "Date (recent) ", value: {sort: "date", descending: true}}, {label: "Date (oldest) ", value: {sort: "date", descending: false}}, {label: "Title (desc) ", value: {sort: "target", descending: true}}, {label: "Title (asc) ", value: {sort: "target", descending: false}}, ]; entityTypes: string[] = []; index: number; params; @ViewChild("deleteModal") deleteModal; claimsDeleted: number = 0; @Input() communityId: string = null; url = null; public pageContents = null; /* Sticky actions */ @Input() public actions: boolean = false; public offset: number; constructor(private _claimService: ClaimsService, private route: ActivatedRoute, private _router: Router, private location: Location, private _meta: Meta, private _title: Title, private _piwikService: PiwikService, private seoService: SEOService, private indexInfoService: IndexInfoService, private helper: HelperService, private _fb: FormBuilder) { } ngOnInit() { if (typeof document !== "undefined" && this.actions) { this.offset = Number.parseInt(getComputedStyle(document.documentElement).getPropertyValue('--header-height')); } this.entities = []; this.filterForm = this._fb.group({ keyword: [''], entities: this._fb.control(this.entities), sort: this._fb.control(this.sortOptions[0].value) }); this.properties = properties; this.url = properties.domain + properties.baseLink + this._router.url; if (!this.myClaims) { this.sortOptions.push({label: "User (desc) ", value: {sort: "user", descending: true}}); this.sortOptions.push({label: "User (asc) ", value: {sort: "user", descending: false}}) } var description = "Openaire, linking, claim, publication, research data, software, other research product, project, community"; this.updateTitle(this.pageTitle); this.updateDescription(description); this.updateUrl(this.url); this.subscriptions.push(this._piwikService.trackView(this.properties, this.pageTitle).subscribe()); if(properties.adminToolsPortalType !== "explore") { this.subscriptions.push(this.helper.getPageHelpContents(this.properties, this.communityId, this._router.url).subscribe(contents => { this.pageContents = contents; })); } this.subscriptions.push(this.indexInfoService.getLastIndexDate(this.properties).subscribe(res => { this.lastIndexDate = res; })); this.subscriptions.push(this.route.queryParams.subscribe(params => { this.seoService.createLinkForCanonicalURL(this.url, false); if (this.myClaims) { this.fetchBy = "User"; this.fetchId = this.user.email; } else { this.fetchBy = (this.fetchBy) ? this.fetchBy : params['fetchBy']; this.fetchBy = (this.types.indexOf(this.fetchBy) != -1) ? this.fetchBy : 'All'; this.fetchId = (this.fetchId) ? this.fetchId : params['fetchId']; this.fetchId = this.fetchId ? this.fetchId : ''; } let page = (params['page'] === undefined) ? 1 : +params['page']; this.keyword = (params['keyword'] ? params['keyword'] : ""); this.filterForm.get('keyword').setValue(this.keyword); this.page = (page <= 0) ? 1 : page; this.entityTypes = [];//(params['types']?params['types']:[]); this.setTypes(params['types']); // check the appropriate checkboxes this.setSortBy(params['sort']); this.getClaims(); this.subscriptions.push(this.searchTermStream .pipe(debounceTime(300), distinctUntilChanged()) .subscribe((term: string) => { this.keyword = term; this.page = 1; this.goTo(); })); this.subscriptions.push(this.filterForm.get('entities').valueChanges.subscribe(value => { this.goTo(); })); this.subscriptions.push(this.filterForm.get('sort').valueChanges.subscribe(value => { this.goTo(); })); })); } ngOnDestroy() { this.subscriptions.forEach(subscription => { if (subscription instanceof Subscriber) { subscription.unsubscribe(); } }); if (this.subResults) { this.subResults.unsubscribe(); } } getClaims() { let types = ''; for (let type of this.entities) { types += (types.length > 0 ? '&' : '') + "types=" + type; } this.loading = true; if (this.subResults) { this.subResults.unsubscribe(); } if (this.fetchBy == "Project") { this.subResults = this._claimService.getClaimsByProject(this.size, this.page, this.fetchId, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe( data => { this.manageAPIData(data); this.loading = false; }, err => { this.handleErrors(err, "Error getting claims for project with id: " + this.fetchId); } ); } else if (this.fetchBy == "User") { this.subResults = this._claimService.getClaimsByUser(this.size, this.page, this.fetchId, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe( data => { this.manageAPIData(data); this.loading = false; }, err => { this.handleErrors(err, "Error getting claims for user with id: " + this.fetchId); this.loading = false; } ); } else if (this.fetchBy == "Result") { this.subResults = this._claimService.getClaimsByResult(this.size, this.page, this.fetchId, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe( data => { this.manageAPIData(data); this.loading = false; }, err => { this.handleErrors(err, "Error getting claims for entity with id: " + this.fetchId); this.loading = false; } ); } else if (this.fetchBy == "Context") { this.subResults = this._claimService.getClaimsBycontext(this.size, this.page, this.fetchId, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe( data => { this.manageAPIData(data); this.loading = false; }, err => { this.handleErrors(err, "Error getting claims for context with id: " + this.fetchId); this.loading = false; } ); } else { this.subResults = this._claimService.getClaims(this.size, this.page, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe( data => { this.manageAPIData(data); this.loading = false; }, err => { this.handleErrors(err, "Error getting claims"); this.loading = false; } ); } } manageAPIData(data) { this.claims = data.data; this.resultsNum = +data.total; } handleErrors(err, message) { NotificationHandler.rise(message, "danger"); console.error("Display Claims (component): " + message + " " + (err && err.error ? err.error : '')); } goTo(page: number = 1) { this.page = page; this.location.go(location.pathname, this.getParametersString()); HelperFunctions.scroll(); this.getClaims(); } getParametersString() { let params = ''; params += (this.page == 1 ? "" : (params.length > 0 ? '&' : '') + "page=" + this.page); params += (this.size == 10 ? "" : (params.length > 0 ? '&' : '') + "size=" + this.size); let types = ""; for (let type of this.entities) { types += (types.length > 0 ? ',' : '') + type; } params += (this.entities.length > 0) ? (params.length > 0 ? '&' : '') + "types=" + types : ""; if (this.isAdmin) { params += (this.fetchBy == 'All' ? "" : (params.length > 0 ? '&' : '') + "fetchBy=" + this.fetchBy); params += (this.fetchId == '' ? "" : (params.length > 0 ? '&' : '') + "fetchId=" + this.fetchId); } params += (this.filterForm.get("sort").value.sort == 'date' && this.filterForm.get("sort").value.descending ? "" : (params.length > 0 ? '&' : '') + "sort=" + this.filterForm.get("sort").value.sort + "-" + this.filterForm.get("sort").value.descending); params += (this.keyword == '' ? "" : (params.length > 0 ? '&' : '') + "keyword=" + this.keyword); if (this.communityId != null) { params += "&communityId=" + this.communityId; } return params; } setSortBy(sortby: string) { let sort = "date"; let desc = "desc"; if (sortby && sortby.split("-").length == 2) { sort = sortby.split("-")[0]; desc = sortby.split("-")[1]; } let option = this.sortOptions.find(option => option.value.sort == sort && ((option.value.descending && desc == "desc") || (!option.value.descending && desc == "asc"))); this.filterForm.get("sort").setValue(option ? option.value : this.sortOptions[0].value); } setTypes(typesParam: string) { for (let type of typesParam ? typesParam.split(',') : []) { this.entities.push(type); } } changeKeyword() { if (this.filterForm.get("keyword") && (this.filterForm.get("keyword").value?.length >= 3 || this.filterForm.get("keyword").value?.length == 0)) { this.searchTermStream.next(this.filterForm.get("keyword").value); } } select(value: string, event, dropdownFilter: DropdownFilterComponent) { if(event.target instanceof HTMLInputElement) { dropdownFilter.closeDropdown(); if(event.target.checked && !this.entities.find(entity => value === entity)) { this.entities.push(value); } else if(!event.target.checked) { let index = this.entities.indexOf(value); if(index !== -1) { this.entities.splice(index, 1); } } this.filterForm.get('entities').setValue(this.entities); } } isSelected(value: string) { return this.filterForm && this.filterForm.get('entities').value.find(entity => entity === value) } deleteOpen(index: number) { this.index = index; this.deleteModal.alertTitle = 'Delete Confirmation'; this.deleteModal.message = 'Are you sure you want to delete this link?'; this.deleteModal.okButtonText = 'Yes'; this.deleteModal.open(); } delete() { this.subscriptions.push(this._claimService.deleteBulk([this.claims[this.index].id], this.properties.claimsAPIURL).subscribe( res => { this.claims.splice(this.index, 1); this.resultsNum = this.resultsNum - 1; NotificationHandler.rise('Link has been deleted successfully'); let goToPage = this.page; if (this.totalPages(this.resultsNum) < this.page && this.page > 0) { goToPage = this.page - 1; } this.goTo(goToPage); }, err => { this.handleErrors(err, "Error deleting claim with id: " + this.claims[this.index].id); })); } pageChange($event) { let page: number = +$event.value; this.goTo(page); } isClaimAvailable(claim: ClaimDBRecord): boolean { //claim.target.collectedFrom == "infrastruct_::openaire" && let lastUpdateDate = new Date((this.lastIndexDate != null) ? this.lastIndexDate : this.properties.lastIndexUpdate); let lastUpdateDateStr = Dates.getDateToString(lastUpdateDate); let claimDate = new Date(claim.date); let claimDateStr = Dates.getDateToString(claimDate); if (claimDateStr < lastUpdateDateStr) { return true; } else { return claim.target.collectedFrom != "infrastruct_::openaire" && claim.indexed; } } totalPages(totalResults: number): number { let totalPages: any = totalResults / (this.size); if (!(Number.isInteger(totalPages))) { totalPages = (parseInt(totalPages, 10) + 1); } return totalPages; } private updateDescription(description: string) { this._meta.updateTag({content: description}, "name='description'"); this._meta.updateTag({content: description}, "property='og:description'"); } private updateTitle(title: string) { var _prefix = ""; if (!this.communityId) { _prefix = "OpenAIRE | "; } var _title = _prefix + ((title.length > 50) ? title.substring(0, 50) : title); if (this.myClaims) { this._title.setTitle(_title); } this._meta.updateTag({content: _title}, "property='og:title'"); } private updateUrl(url: string) { this._meta.updateTag({content: url}, "property='og:url'"); } }