mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
Merge remote-tracking branch '4Science-bitbucket/CST-5307' into CST-5307
This commit is contained in:
@@ -28,4 +28,6 @@ export enum FeatureID {
|
||||
CanCreateVersion = 'canCreateVersion',
|
||||
CanViewUsageStatistics = 'canViewUsageStatistics',
|
||||
CanSendFeedback = 'canSendFeedback',
|
||||
ShowClaimItem = 'showClaimItem',
|
||||
CanClaimItem = 'canClaimItem',
|
||||
}
|
||||
|
@@ -156,84 +156,6 @@ export class ResearcherProfileService {
|
||||
return this.dataService.patch(researcherProfile, operations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given item is linked to an ORCID profile.
|
||||
*
|
||||
* @param item the item to check
|
||||
* @returns the check result
|
||||
*/
|
||||
isLinkedToOrcid(item: Item): boolean {
|
||||
return item.hasMetadata('cris.orcid.authenticated');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if only the admin users can disconnect a researcher profile from ORCID.
|
||||
*
|
||||
* @returns the check result
|
||||
*/
|
||||
onlyAdminCanDisconnectProfileFromOrcid(): Observable<boolean> {
|
||||
return this.getOrcidDisconnectionAllowedUsersConfiguration().pipe(
|
||||
map((property) => property.values.map( (value) => value.toLowerCase()).includes('only_admin'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the profile's owner can disconnect that profile from ORCID.
|
||||
*
|
||||
* @returns the check result
|
||||
*/
|
||||
ownerCanDisconnectProfileFromOrcid(): Observable<boolean> {
|
||||
return this.getOrcidDisconnectionAllowedUsersConfiguration().pipe(
|
||||
map((property) => {
|
||||
const values = property.values.map( (value) => value.toLowerCase());
|
||||
return values.includes('only_owner') || values.includes('admin_and_owner');
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the admin users can disconnect a researcher profile from ORCID.
|
||||
*
|
||||
* @returns the check result
|
||||
*/
|
||||
adminCanDisconnectProfileFromOrcid(): Observable<boolean> {
|
||||
return this.getOrcidDisconnectionAllowedUsersConfiguration().pipe(
|
||||
map((property) => {
|
||||
const values = property.values.map( (value) => value.toLowerCase());
|
||||
return values.includes('only_admin') || values.includes('admin_and_owner');
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the given item represents a profile unlink it from ORCID.
|
||||
*/
|
||||
unlinkOrcid(item: Item): Observable<RemoteData<ResearcherProfile>> {
|
||||
|
||||
const operations: RemoveOperation[] = [{
|
||||
path:'/orcid',
|
||||
op:'remove'
|
||||
}];
|
||||
|
||||
return this.findById(item.firstMetadata('cris.owner').authority).pipe(
|
||||
switchMap((profile) => this.patch(profile, operations)),
|
||||
getFinishedRemoteData()
|
||||
);
|
||||
}
|
||||
|
||||
getOrcidAuthorizeUrl(profile: Item): Observable<string> {
|
||||
return combineLatest([
|
||||
this.configurationService.findByPropertyName('orcid.authorize-url').pipe(getFirstSucceededRemoteDataPayload()),
|
||||
this.configurationService.findByPropertyName('orcid.application-client-id').pipe(getFirstSucceededRemoteDataPayload()),
|
||||
this.configurationService.findByPropertyName('orcid.scope').pipe(getFirstSucceededRemoteDataPayload())]
|
||||
).pipe(
|
||||
map(([authorizeUrl, clientId, scopes]) => {
|
||||
const redirectUri = environment.rest.baseUrl + '/api/cris/orcid/' + profile.id + '/?url=' + encodeURIComponent(this.router.url);
|
||||
return authorizeUrl.values[0] + '?client_id=' + clientId.values[0] + '&redirect_uri=' + redirectUri + '&response_type=code&scope='
|
||||
+ scopes.values.join(' ');
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a researcher profile starting from an external source URI
|
||||
* @param sourceUri URI of source item of researcher profile.
|
||||
@@ -258,10 +180,4 @@ export class ResearcherProfileService {
|
||||
return this.rdbService.buildFromRequestUUID(requestId);
|
||||
}
|
||||
|
||||
private getOrcidDisconnectionAllowedUsersConfiguration(): Observable<ConfigurationProperty> {
|
||||
return this.configurationService.findByPropertyName('orcid.disconnection.allowed-users').pipe(
|
||||
getFirstSucceededRemoteDataPayload()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@
|
||||
<div class="pl-2 space-children-mr">
|
||||
<ds-dso-page-edit-button [pageRoute]="itemPageRoute$ | async" [dso]="item"
|
||||
[tooltipMsg]="'item.page.edit'"></ds-dso-page-edit-button>
|
||||
<button class="edit-button btn btn-dark btn-sm" *ngIf="(isClaimable() | async)" (click)="claim()"> {{"item.page.claim.button" | translate }} </button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="simple-view-link my-3" *ngIf="!fromWfi">
|
||||
@@ -42,4 +43,4 @@
|
||||
</div>
|
||||
<ds-error *ngIf="itemRD?.hasFailed" message="{{'error.item' | translate}}"></ds-error>
|
||||
<ds-loading *ngIf="itemRD?.isLoading" message="{{'loading.item' | translate}}"></ds-loading>
|
||||
</div>
|
||||
</div>
|
@@ -16,6 +16,10 @@ import { hasValue } from '../../shared/empty.util';
|
||||
import { AuthService } from '../../core/auth/auth.service';
|
||||
import { Location } from '@angular/common';
|
||||
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { ResearcherProfileService } from '../../core/profile/researcher-profile.service';
|
||||
import { CollectionDataService } from '../../core/data/collection-data.service';
|
||||
|
||||
|
||||
/**
|
||||
@@ -48,8 +52,11 @@ export class FullItemPageComponent extends ItemPageComponent implements OnInit,
|
||||
items: ItemDataService,
|
||||
authService: AuthService,
|
||||
authorizationService: AuthorizationDataService,
|
||||
translate: TranslateService,
|
||||
notificationsService: NotificationsService,
|
||||
researcherProfileService: ResearcherProfileService,
|
||||
private _location: Location) {
|
||||
super(route, router, items, authService, authorizationService);
|
||||
super(route, router, items, authService, authorizationService, translate, notificationsService, researcherProfileService);
|
||||
}
|
||||
|
||||
/*** AoT inheritance fix, will hopefully be resolved in the near future **/
|
||||
|
@@ -1,20 +1,26 @@
|
||||
import { map } from 'rxjs/operators';
|
||||
import { map, mergeMap, take, tap } from 'rxjs/operators';
|
||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { ItemDataService } from '../../core/data/item-data.service';
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
|
||||
import { Item } from '../../core/shared/item.model';
|
||||
|
||||
import { fadeInOut } from '../../shared/animations/fade';
|
||||
import { getAllSucceededRemoteDataPayload, redirectOn4xx } from '../../core/shared/operators';
|
||||
import { getAllSucceededRemoteDataPayload, getFirstSucceededRemoteData, redirectOn4xx } from '../../core/shared/operators';
|
||||
import { ViewMode } from '../../core/shared/view-mode.model';
|
||||
import { AuthService } from '../../core/auth/auth.service';
|
||||
import { getItemPageRoute } from '../item-page-routing-paths';
|
||||
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
|
||||
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { ResearcherProfileService } from '../../core/profile/researcher-profile.service';
|
||||
import { ResearcherProfile } from '../../core/profile/model/researcher-profile.model';
|
||||
import { isNotUndefined } from '../../shared/empty.util';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
|
||||
|
||||
/**
|
||||
* This component renders a simple item page.
|
||||
@@ -55,13 +61,27 @@ export class ItemPageComponent implements OnInit {
|
||||
*/
|
||||
isAdmin$: Observable<boolean>;
|
||||
|
||||
itemUrl: string;
|
||||
|
||||
public claimable$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public isProcessing$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
|
||||
constructor(
|
||||
protected route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private items: ItemDataService,
|
||||
private authService: AuthService,
|
||||
private authorizationService: AuthorizationDataService
|
||||
) { }
|
||||
private authorizationService: AuthorizationDataService,
|
||||
private translate: TranslateService,
|
||||
private notificationsService: NotificationsService,
|
||||
private researcherProfileService: ResearcherProfileService
|
||||
) {
|
||||
this.route.data.pipe(
|
||||
map((data) => data.dso as RemoteData<Item>)
|
||||
).subscribe((data: RemoteData<Item>) => {
|
||||
this.itemUrl = data?.payload?.self
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
@@ -77,5 +97,56 @@ export class ItemPageComponent implements OnInit {
|
||||
);
|
||||
|
||||
this.isAdmin$ = this.authorizationService.isAuthorized(FeatureID.AdministratorOf);
|
||||
|
||||
this.authorizationService.isAuthorized(FeatureID.ShowClaimItem, this.itemUrl).pipe(
|
||||
take(1)
|
||||
).subscribe((isAuthorized: boolean) => {
|
||||
this.claimable$.next(isAuthorized)
|
||||
});
|
||||
}
|
||||
|
||||
claim() {
|
||||
this.isProcessing$.next(true);
|
||||
|
||||
this.authorizationService.isAuthorized(FeatureID.CanClaimItem, this.itemUrl).pipe(
|
||||
take(1)
|
||||
).subscribe((isAuthorized: boolean) => {
|
||||
if (!isAuthorized) {
|
||||
this.notificationsService.warning(this.translate.get('researcherprofile.claim.not-authorized'));
|
||||
this.isProcessing$.next(false);
|
||||
} else {
|
||||
this.createFromExternalSource();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
createFromExternalSource() {
|
||||
this.researcherProfileService.createFromExternalSource(this.itemUrl).pipe(
|
||||
tap((rd: any) => {
|
||||
if (!rd.hasSucceeded) {
|
||||
this.isProcessing$.next(false);
|
||||
}
|
||||
}),
|
||||
getFirstSucceededRemoteData(),
|
||||
mergeMap((rd: RemoteData<ResearcherProfile>) => {
|
||||
return this.researcherProfileService.findRelatedItemId(rd.payload);
|
||||
}))
|
||||
.subscribe((id: string) => {
|
||||
if (isNotUndefined(id)) {
|
||||
this.notificationsService.success(this.translate.get('researcherprofile.success.claim.title'),
|
||||
this.translate.get('researcherprofile.success.claim.body'));
|
||||
this.claimable$.next(false);
|
||||
this.isProcessing$.next(false);
|
||||
} else {
|
||||
this.notificationsService.error(
|
||||
this.translate.get('researcherprofile.error.claim.title'),
|
||||
this.translate.get('researcherprofile.error.claim.body'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
isClaimable(): Observable<boolean> {
|
||||
return this.claimable$;
|
||||
}
|
||||
}
|
||||
|
@@ -2130,6 +2130,8 @@
|
||||
|
||||
"item.page.version.hasDraft": "A new version cannot be created because there is an inprogress submission in the version history",
|
||||
|
||||
"item.page.claim.button": "Claim",
|
||||
|
||||
"item.preview.dc.identifier.uri": "Identifier:",
|
||||
|
||||
"item.preview.dc.contributor.author": "Authors:",
|
||||
|
Reference in New Issue
Block a user