mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
[DURACOM-133] Do not show edit/delete button
for observer
This commit is contained in:
@@ -7,7 +7,8 @@
|
|||||||
<i class="fa fa-info-circle"></i> {{"submission.workspace.generic.view" | translate}}
|
<i class="fa fa-info-circle"></i> {{"submission.workspace.generic.view" | translate}}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<a class="btn btn-primary mt-1 mb-3" id="{{'edit_' + object.id}}"
|
<a class="btn btn-primary mt-1 mb-3 edit-btn" id="{{'edit_' + object.id}}"
|
||||||
|
*ngIf="(isAdmin$ | async) || (canEditItem$ | async)"
|
||||||
ngbTooltip="{{'submission.workflow.generic.edit-help' | translate}}"
|
ngbTooltip="{{'submission.workflow.generic.edit-help' | translate}}"
|
||||||
[attr.aria-label]="'submission.workflow.generic.edit-help' | translate"
|
[attr.aria-label]="'submission.workflow.generic.edit-help' | translate"
|
||||||
[routerLink]="['/workspaceitems/' + object.id + '/edit']" role="button">
|
[routerLink]="['/workspaceitems/' + object.id + '/edit']" role="button">
|
||||||
@@ -15,6 +16,7 @@
|
|||||||
</a>
|
</a>
|
||||||
|
|
||||||
<button type="button" id="{{'delete_' + object.id}}" class="btn btn-danger mt-1 mb-3"
|
<button type="button" id="{{'delete_' + object.id}}" class="btn btn-danger mt-1 mb-3"
|
||||||
|
*ngIf="(isAdmin$ | async) || (canEditItem$ | async)"
|
||||||
ngbTooltip="{{'submission.workflow.generic.delete-help' | translate}}"
|
ngbTooltip="{{'submission.workflow.generic.delete-help' | translate}}"
|
||||||
[attr.aria-label]="'submission.workflow.generic.delete-help' | translate"
|
[attr.aria-label]="'submission.workflow.generic.delete-help' | translate"
|
||||||
(click)="$event.preventDefault();confirmDiscard(content)">
|
(click)="$event.preventDefault();confirmDiscard(content)">
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import { EPerson } from './../../../core/eperson/models/eperson.model';
|
||||||
import { ChangeDetectionStrategy, Injector, NO_ERRORS_SCHEMA } from '@angular/core';
|
import { ChangeDetectionStrategy, Injector, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
@@ -24,12 +25,16 @@ import { RequestService } from '../../../core/data/request.service';
|
|||||||
import { getMockRequestService } from '../../mocks/request.service.mock';
|
import { getMockRequestService } from '../../mocks/request.service.mock';
|
||||||
import { getMockSearchService } from '../../mocks/search-service.mock';
|
import { getMockSearchService } from '../../mocks/search-service.mock';
|
||||||
import { SearchService } from '../../../core/shared/search/search.service';
|
import { SearchService } from '../../../core/shared/search/search.service';
|
||||||
|
import { AuthService } from '../../../core/auth/auth.service';
|
||||||
|
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
|
|
||||||
let component: WorkspaceitemActionsComponent;
|
let component: WorkspaceitemActionsComponent;
|
||||||
let fixture: ComponentFixture<WorkspaceitemActionsComponent>;
|
let fixture: ComponentFixture<WorkspaceitemActionsComponent>;
|
||||||
|
|
||||||
let mockObject: WorkspaceItem;
|
let mockObject: WorkspaceItem;
|
||||||
let notificationsServiceStub: NotificationsServiceStub;
|
let notificationsServiceStub: NotificationsServiceStub;
|
||||||
|
let authorizationService;
|
||||||
|
let authService;
|
||||||
|
|
||||||
const mockDataService = jasmine.createSpyObj('WorkspaceitemDataService', {
|
const mockDataService = jasmine.createSpyObj('WorkspaceitemDataService', {
|
||||||
delete: jasmine.createSpy('delete')
|
delete: jasmine.createSpy('delete')
|
||||||
@@ -71,10 +76,88 @@ const item = Object.assign(new Item(), {
|
|||||||
const rd = createSuccessfulRemoteDataObject(item);
|
const rd = createSuccessfulRemoteDataObject(item);
|
||||||
mockObject = Object.assign(new WorkspaceItem(), { item: observableOf(rd), id: '1234', uuid: '1234' });
|
mockObject = Object.assign(new WorkspaceItem(), { item: observableOf(rd), id: '1234', uuid: '1234' });
|
||||||
|
|
||||||
describe('WorkspaceitemActionsComponent', () => {
|
const ePersonMock: EPerson = Object.assign(new EPerson(), {
|
||||||
beforeEach(waitForAsync(() => {
|
handle: null,
|
||||||
|
netid: null,
|
||||||
|
lastActive: '2023-04-27T12:15:57.054+00:00',
|
||||||
|
canLogIn: true,
|
||||||
|
email: 'dspacedemo+submit@gmail.com',
|
||||||
|
requireCertificate: false,
|
||||||
|
selfRegistered: false,
|
||||||
|
_name: 'dspacedemo+submit@gmail.com',
|
||||||
|
id: '914955b1-cf2e-4884-8af7-a166aa24cf73',
|
||||||
|
uuid: '914955b1-cf2e-4884-8af7-a166aa24cf73',
|
||||||
|
type: 'eperson',
|
||||||
|
metadata: {
|
||||||
|
'dspace.agreements.cookies': [
|
||||||
|
{
|
||||||
|
uuid: '0a53a0f2-e168-4ed9-b4af-cba9a2d267ca',
|
||||||
|
language: null,
|
||||||
|
value:
|
||||||
|
'{"authentication":true,"preferences":true,"acknowledgement":true,"google-analytics":true}',
|
||||||
|
place: 0,
|
||||||
|
authority: null,
|
||||||
|
confidence: -1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'dspace.agreements.end-user': [
|
||||||
|
{
|
||||||
|
uuid: '0879e571-6e4a-4efe-af9b-704c755166be',
|
||||||
|
language: null,
|
||||||
|
value: 'true',
|
||||||
|
place: 0,
|
||||||
|
authority: null,
|
||||||
|
confidence: -1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'eperson.firstname': [
|
||||||
|
{
|
||||||
|
uuid: '18052a3e-f19b-49ca-b9f9-ee4cf9c71b86',
|
||||||
|
language: null,
|
||||||
|
value: 'Demo',
|
||||||
|
place: 0,
|
||||||
|
authority: null,
|
||||||
|
confidence: -1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'eperson.language': [
|
||||||
|
{
|
||||||
|
uuid: '98c2abdb-6a6f-4b41-b455-896bcf333ca3',
|
||||||
|
language: null,
|
||||||
|
value: 'en',
|
||||||
|
place: 0,
|
||||||
|
authority: null,
|
||||||
|
confidence: -1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'eperson.lastname': [
|
||||||
|
{
|
||||||
|
uuid: 'df722e70-9497-468d-a92a-4038e7ef2586',
|
||||||
|
language: null,
|
||||||
|
value: 'Submitter',
|
||||||
|
place: 0,
|
||||||
|
authority: null,
|
||||||
|
confidence: -1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
_links: {
|
||||||
|
groups: {
|
||||||
|
href: 'http://localhost:8080/server/api/eperson/epersons/914955b1-cf2e-4884-8af7-a166aa24cf73/groups',
|
||||||
|
},
|
||||||
|
self: {
|
||||||
|
href: 'http://localhost:8080/server/api/eperson/epersons/914955b1-cf2e-4884-8af7-a166aa24cf73',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
authService = jasmine.createSpyObj('authService', {
|
||||||
|
getAuthenticatedUserFromStore: jasmine.createSpy('getAuthenticatedUserFromStore')
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('WorkspaceitemActionsComponent', () => {
|
||||||
|
beforeEach(waitForAsync(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
NgbModule,
|
NgbModule,
|
||||||
TranslateModule.forRoot({
|
TranslateModule.forRoot({
|
||||||
@@ -92,6 +175,8 @@ describe('WorkspaceitemActionsComponent', () => {
|
|||||||
{ provide: WorkspaceitemDataService, useValue: mockDataService },
|
{ provide: WorkspaceitemDataService, useValue: mockDataService },
|
||||||
{ provide: SearchService, useValue: searchService },
|
{ provide: SearchService, useValue: searchService },
|
||||||
{ provide: RequestService, useValue: requestServce },
|
{ provide: RequestService, useValue: requestServce },
|
||||||
|
{ provide: AuthService, useValue: authService },
|
||||||
|
{ provide: AuthorizationDataService, useValue: authorizationService},
|
||||||
NgbModal
|
NgbModal
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
@@ -105,6 +190,10 @@ describe('WorkspaceitemActionsComponent', () => {
|
|||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
component.object = mockObject;
|
component.object = mockObject;
|
||||||
notificationsServiceStub = TestBed.inject(NotificationsService as any);
|
notificationsServiceStub = TestBed.inject(NotificationsService as any);
|
||||||
|
authorizationService = jasmine.createSpyObj('authorizationService', {
|
||||||
|
isAuthorized: observableOf(true)
|
||||||
|
});
|
||||||
|
(authService.getAuthenticatedUserFromStore as jasmine.Spy).and.returnValue(observableOf(ePersonMock));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -150,7 +239,6 @@ describe('WorkspaceitemActionsComponent', () => {
|
|||||||
confirmBtn.click();
|
confirmBtn.click();
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@@ -1,7 +1,12 @@
|
|||||||
import { Component, Injector, Input } from '@angular/core';
|
import { EPerson } from './../../../core/eperson/models/eperson.model';
|
||||||
|
import { AuthorizationDataService } from 'src/app/core/data/feature-authorization/authorization-data.service';
|
||||||
|
import { AuthService } from './../../../core/auth/auth.service';
|
||||||
|
import { Item } from 'src/app/core/shared/item.model';
|
||||||
|
import { FeatureID } from './../../../core/data/feature-authorization/feature-id';
|
||||||
|
import { Component, Injector, Input, OnInit } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject, Observable, switchMap } from 'rxjs';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
@@ -11,7 +16,7 @@ import { WorkspaceitemDataService } from '../../../core/submission/workspaceitem
|
|||||||
import { NotificationsService } from '../../notifications/notifications.service';
|
import { NotificationsService } from '../../notifications/notifications.service';
|
||||||
import { RequestService } from '../../../core/data/request.service';
|
import { RequestService } from '../../../core/data/request.service';
|
||||||
import { SearchService } from '../../../core/shared/search/search.service';
|
import { SearchService } from '../../../core/shared/search/search.service';
|
||||||
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
|
import { getFirstCompletedRemoteData, getRemoteDataPayload } from '../../../core/shared/operators';
|
||||||
import { RemoteData } from '../../../core/data/remote-data';
|
import { RemoteData } from '../../../core/data/remote-data';
|
||||||
import { NoContent } from '../../../core/shared/NoContent.model';
|
import { NoContent } from '../../../core/shared/NoContent.model';
|
||||||
import { getWorkspaceItemViewRoute } from '../../../workspaceitems-edit-page/workspaceitems-edit-page-routing-paths';
|
import { getWorkspaceItemViewRoute } from '../../../workspaceitems-edit-page/workspaceitems-edit-page-routing-paths';
|
||||||
@@ -24,7 +29,7 @@ import { getWorkspaceItemViewRoute } from '../../../workspaceitems-edit-page/wor
|
|||||||
styleUrls: ['./workspaceitem-actions.component.scss'],
|
styleUrls: ['./workspaceitem-actions.component.scss'],
|
||||||
templateUrl: './workspaceitem-actions.component.html',
|
templateUrl: './workspaceitem-actions.component.html',
|
||||||
})
|
})
|
||||||
export class WorkspaceitemActionsComponent extends MyDSpaceActionsComponent<WorkspaceItem, WorkspaceitemDataService> {
|
export class WorkspaceitemActionsComponent extends MyDSpaceActionsComponent<WorkspaceItem, WorkspaceitemDataService> implements OnInit {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The workspaceitem object
|
* The workspaceitem object
|
||||||
@@ -37,6 +42,20 @@ export class WorkspaceitemActionsComponent extends MyDSpaceActionsComponent<Work
|
|||||||
*/
|
*/
|
||||||
public processingDelete$ = new BehaviorSubject<boolean>(false);
|
public processingDelete$ = new BehaviorSubject<boolean>(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if the user is an admin
|
||||||
|
* @type {Observable<boolean>}
|
||||||
|
*/
|
||||||
|
isAdmin$: Observable<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if the user can edit the item
|
||||||
|
* and therefore can delete it as well
|
||||||
|
* (since the user can discard the item also from the edit page)
|
||||||
|
* @type {Observable<boolean>}
|
||||||
|
*/
|
||||||
|
canEditItem$: Observable<boolean>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize instance variables
|
* Initialize instance variables
|
||||||
*
|
*
|
||||||
@@ -54,8 +73,12 @@ export class WorkspaceitemActionsComponent extends MyDSpaceActionsComponent<Work
|
|||||||
protected notificationsService: NotificationsService,
|
protected notificationsService: NotificationsService,
|
||||||
protected translate: TranslateService,
|
protected translate: TranslateService,
|
||||||
protected searchService: SearchService,
|
protected searchService: SearchService,
|
||||||
protected requestService: RequestService) {
|
protected requestService: RequestService,
|
||||||
|
private authService: AuthService,
|
||||||
|
public authorizationService: AuthorizationDataService,
|
||||||
|
) {
|
||||||
super(WorkspaceItem.type, injector, router, notificationsService, translate, searchService, requestService);
|
super(WorkspaceItem.type, injector, router, notificationsService, translate, searchService, requestService);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -77,6 +100,25 @@ export class WorkspaceitemActionsComponent extends MyDSpaceActionsComponent<Work
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
const activeEPerson$ = this.authService.getAuthenticatedUserFromStore();
|
||||||
|
|
||||||
|
this.isAdmin$ = activeEPerson$.pipe(
|
||||||
|
switchMap((user: EPerson) => this.authorizationService.isAuthorized(FeatureID.AdministratorOf, user.uuid)));
|
||||||
|
|
||||||
|
this.canEditItem$ = activeEPerson$.pipe(
|
||||||
|
switchMap((eperson) => {
|
||||||
|
return this.object?.item.pipe(
|
||||||
|
getFirstCompletedRemoteData(),
|
||||||
|
getRemoteDataPayload(),
|
||||||
|
switchMap((item: Item) => {
|
||||||
|
return this.authorizationService.isAuthorized(FeatureID.CanEditItem, item?._links?.self.href, eperson.uuid);
|
||||||
|
})
|
||||||
|
) as Observable<boolean>;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init the target object
|
* Init the target object
|
||||||
*
|
*
|
||||||
@@ -92,5 +134,4 @@ export class WorkspaceitemActionsComponent extends MyDSpaceActionsComponent<Work
|
|||||||
getWorkspaceItemViewRoute(workspaceItem: WorkspaceItem): string {
|
getWorkspaceItemViewRoute(workspaceItem: WorkspaceItem): string {
|
||||||
return getWorkspaceItemViewRoute(workspaceItem?.id);
|
return getWorkspaceItemViewRoute(workspaceItem?.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user