Skip to content

Commit 6632ce3

Browse files
Merged dspace-cris-7 into DSC-1328-fix-show-community-collection
2 parents 19eb92c + f5553ef commit 6632ce3

12 files changed

Lines changed: 210 additions & 31 deletions

File tree

server.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import { createCertificate } from 'pem';
3434
import { createServer } from 'https';
3535
import { json } from 'body-parser';
3636

37-
import { existsSync, readFileSync } from 'fs';
37+
import { readFileSync } from 'fs';
3838
import { join } from 'path';
3939

4040
import { enableProdMode } from '@angular/core';
@@ -213,6 +213,11 @@ export function app() {
213213
*/
214214
server.get('/app/health', healthCheck);
215215

216+
/**
217+
* Checking client status
218+
*/
219+
server.get('/app/client/health', clientHealthCheck);
220+
216221
/**
217222
* Default sending all incoming requests to ngApp() function, after first checking for a cached
218223
* copy of the page (see cacheCheck())
@@ -545,6 +550,16 @@ function start() {
545550
}
546551
}
547552

553+
/*
554+
* The callback function to serve client health check requests
555+
*/
556+
function clientHealthCheck(req, res) {
557+
const isServerHealthy = true;
558+
if (isServerHealthy) {
559+
res.status(200).json({ status: 'UP' });
560+
}
561+
}
562+
548563
/*
549564
* The callback function to serve health check requests
550565
*/

src/app/audit-page/object-audit-overview/object-audit-overview.component.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ <h2 class="flex-grow-1">{{'audit.object.overview.title' | translate}}</h2>
44
</div>
55

66
<ng-container *ngIf="object">
7-
<h4 class="mt-4 mb-4">{{ object.name }} (<em>{{object.type}})</em></h4>
7+
<h4 class="mt-4 mb-4">{{ object.name }} (<em>{{object.type}}</em>)</h4>
88

99
<ng-container *ngIf="(auditsRD$ | async)?.payload as audits">
1010

@@ -61,6 +61,7 @@ <h4 class="mt-4 mb-4">{{ object.name }} (<em>{{object.type}})</em></h4>
6161

6262
</ng-container>
6363

64+
<h4 class="mt-4 mb-4" *ngIf="(auditsRD$ | async).statusCode === 404">{{'audit.object.overview.disabled.message' | translate}}</h4>
6465

6566
</ng-container>
6667

src/app/core/data/version-history-data.service.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ import { VERSION_HISTORY } from '../shared/version-history.resource-type';
1616
import { followLink, FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
1717
import { VersionDataService } from './version-data.service';
1818
import { HttpOptions } from '../dspace-rest/dspace-rest.service';
19-
import { getAllSucceededRemoteData, getFirstCompletedRemoteData, getFirstSucceededRemoteDataPayload, getRemoteDataPayload } from '../shared/operators';
19+
import {
20+
getAllSucceededRemoteData,
21+
getFirstCompletedRemoteData,
22+
getFirstSucceededRemoteDataPayload,
23+
getRemoteDataPayload
24+
} from '../shared/operators';
2025
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
2126
import { hasValueOperator } from '../../shared/empty.util';
2227
import { Item } from '../shared/item.model';

src/app/core/layout/models/section.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export interface TopSection extends SectionComponent {
5959
titleKey: string;
6060
componentType: 'top';
6161
numberOfItems: number;
62+
showThumbnails: boolean;
6263
}
6364

6465
export interface SearchSection extends SectionComponent {

src/app/cris-layout/cris-layout-matrix/cris-layout-box-container/boxes/relation/cris-layout-relation-box.component.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@
33
[configuration]="configuration"
44
[searchEnabled]="searchEnabled"
55
[showCharts]="true"
6-
[showScopeSelector]="false">
6+
[showScopeSelector]="false"
7+
[showSearchResultNotice]="showSearchResultNotice$ | async"
8+
[searchResultNotice]="searchResultNotice">
79
</ds-configuration-search-page>

src/app/cris-layout/cris-layout-matrix/cris-layout-box-container/boxes/relation/cris-layout-relation-box.component.spec.ts

Lines changed: 118 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1-
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
1+
import { ComponentFixture, fakeAsync, TestBed, waitForAsync } from '@angular/core/testing';
22

33
import { CrisLayoutRelationBoxComponent } from './cris-layout-relation-box.component';
44
import { NO_ERRORS_SCHEMA } from '@angular/core';
55
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
66
import { CommonModule } from '@angular/common';
77
import { SharedModule } from '../../../../../shared/shared.module';
88
import { Item } from '../../../../../core/shared/item.model';
9-
import { of } from 'rxjs';
9+
import { of as observableOf, of } from 'rxjs';
1010
import { CrisLayoutBox } from '../../../../../core/layout/models/box.model';
1111
import { TranslateLoaderMock } from '../../../../../shared/mocks/translate-loader.mock';
12+
import { MetadataValue } from '../../../../../core/shared/metadata.models';
13+
import { Person } from '@angular/cli/utilities/package-json';
14+
import { AuthService } from '../../../../../core/auth/auth.service';
15+
import { cold } from 'jasmine-marbles';
16+
import { EPersonMock, EPersonMock2 } from '../../../../../shared/testing/eperson.mock';
1217

1318
describe('CrisLayoutRelationBoxComponent', () => {
1419
let component: CrisLayoutRelationBoxComponent;
@@ -25,7 +30,37 @@ describe('CrisLayoutRelationBoxComponent', () => {
2530
collapsed: false,
2631
header: 'CrisLayoutBox Header',
2732
shortname: 'test-box',
28-
configuration: of({ configuration: 'box-configuration-id' })
33+
configuration: { 'discovery-configuration': 'box-configuration-id' }
34+
});
35+
36+
const relationPublicationsBox = Object.assign(new CrisLayoutBox(), {
37+
id: '2',
38+
collapsed: false,
39+
header: 'Publications',
40+
shortname: 'publications',
41+
configuration: { 'discovery-configuration': 'RELATION.Person.researchoutputs' }
42+
});
43+
44+
const personItem = Object.assign(new Item(), {
45+
id: '1234-65487-12354-1235',
46+
bundles: of({}),
47+
metadata: {
48+
'dspace.entity.type': [{ value: 'Person' }] as MetadataValue[],
49+
'dspace.object.owner': [{ value: 'not Owner', authority: EPersonMock2.id }] as MetadataValue[],
50+
}
51+
});
52+
53+
const ownerItem = Object.assign(new Item(), {
54+
id: '1234-65487-12354-1235',
55+
bundles: of({}),
56+
metadata: {
57+
'dspace.entity.type': [{ value: 'Person' }] as MetadataValue[],
58+
'dspace.object.owner': [{ value: 'Owner', authority: EPersonMock.id }] as MetadataValue[],
59+
}
60+
});
61+
62+
const authService = jasmine.createSpyObj('authService', {
63+
getAuthenticatedUserFromStore: observableOf(null)
2964
});
3065

3166
beforeEach(waitForAsync(() => {
@@ -40,25 +75,96 @@ describe('CrisLayoutRelationBoxComponent', () => {
4075
CommonModule,
4176
SharedModule
4277
],
43-
declarations: [ CrisLayoutRelationBoxComponent ],
78+
declarations: [CrisLayoutRelationBoxComponent],
4479
schemas: [NO_ERRORS_SCHEMA],
4580
providers: [
46-
{ provide: 'boxProvider', useClass: testBox },
47-
{ provide: 'itemProvider', useClass: testItem },
81+
{ provide: 'boxProvider', useValue: testBox },
82+
{ provide: 'itemProvider', useValue: testItem },
83+
{ provide: AuthService, useValue: authService },
4884
]
4985
})
50-
.compileComponents();
86+
.compileComponents();
5187
}));
5288

5389
beforeEach(() => {
5490
fixture = TestBed.createComponent(CrisLayoutRelationBoxComponent);
5591
component = fixture.componentInstance;
56-
component.box = testBox;
57-
component.item = testItem;
58-
fixture.detectChanges();
5992
});
6093

61-
xit('should have set scope in searchFilter', () => {
62-
expect(component.searchFilter).toContain('scope=' + testItem.id);
94+
describe('When item is not a Person', () => {
95+
beforeEach(() => {
96+
component.box = testBox;
97+
component.item = testItem;
98+
fixture.detectChanges();
99+
});
100+
101+
it('should create CrisLayoutRelationBoxComponent', () => {
102+
expect(component).toBeDefined();
103+
});
104+
105+
it('should have set scope in searchFilter', () => {
106+
expect(component.searchFilter).toContain('scope=' + testItem.id);
107+
});
108+
109+
it('info message cannot be shown', fakeAsync(() => {
110+
expect(component.showSearchResultNotice$).toBeObservable(cold('a', { a: false }));
111+
}));
112+
113+
it('info message has no value', fakeAsync(() => {
114+
expect(component.searchResultNotice).toBeUndefined();
115+
}));
116+
});
117+
118+
describe('When item is a Person', () => {
119+
120+
describe('When relation-box of researchoutputs is shown', () => {
121+
beforeEach(() => {
122+
component.box = relationPublicationsBox;
123+
});
124+
125+
describe('Whenever the personItem is the researcher profile of the logged user', () => {
126+
beforeEach(() => {
127+
(authService.getAuthenticatedUserFromStore as jasmine.Spy).and.returnValue(observableOf({ id: EPersonMock.id } as Person));
128+
component.item = ownerItem;
129+
fixture.detectChanges();
130+
});
131+
it('info message can be shown', fakeAsync(() => {
132+
expect(component.showSearchResultNotice$).toBeObservable(cold('a', { a: true }));
133+
}));
134+
it('info message has value', fakeAsync(() => {
135+
expect(component.searchResultNotice).not.toBeUndefined();
136+
}));
137+
});
138+
139+
describe('Whenever the personItem is not the researcher profile of the logged user', () => {
140+
beforeEach(() => {
141+
(authService.getAuthenticatedUserFromStore as jasmine.Spy).and.returnValue(observableOf({ id: 'fake-uuid' } as Person));
142+
component.item = personItem;
143+
fixture.detectChanges();
144+
});
145+
it('info message cannot be shown', fakeAsync(() => {
146+
expect(component.showSearchResultNotice$).toBeObservable(cold('a', { a: false }));
147+
}));
148+
it('info message has no value', fakeAsync(() => {
149+
expect(component.searchResultNotice).not.toBeUndefined();
150+
}));
151+
});
152+
153+
describe('no one is logged', () => {
154+
beforeEach(() => {
155+
(authService.getAuthenticatedUserFromStore as jasmine.Spy).and.returnValue(observableOf(null as Person));
156+
fixture.detectChanges();
157+
});
158+
it('info message has no value', fakeAsync(() => {
159+
// component.showSearchResultNotice$.subscribe(value => expect(value).toBeUndefined());
160+
expect(component.showSearchResultNotice$).toBeObservable(cold('a', { a: false }));
161+
}));
162+
it('info message has no value', fakeAsync(() => {
163+
expect(component.searchResultNotice).toBeUndefined();
164+
}));
165+
});
166+
167+
});
63168
});
169+
64170
});

src/app/cris-layout/cris-layout-matrix/cris-layout-box-container/boxes/relation/cris-layout-relation-box.component.ts

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
1-
import { ChangeDetectorRef, Component, Inject, OnInit } from '@angular/core';
1+
import { Component, Inject, OnInit } from '@angular/core';
2+
3+
import { BehaviorSubject, Observable, shareReplay } from 'rxjs';
4+
import { filter, map, take } from 'rxjs/operators';
5+
import { TranslateService } from '@ngx-translate/core';
6+
27
import { RenderCrisLayoutBoxFor } from '../../../../decorators/cris-layout-box.decorator';
38
import { LayoutBox } from '../../../../enums/layout-box.enum';
49
import { CrisLayoutBoxModelComponent } from '../../../../models/cris-layout-box-component.model';
5-
import { TranslateService } from '@ngx-translate/core';
610
import { CrisLayoutBox, RelationBoxConfiguration } from '../../../../../core/layout/models/box.model';
711
import { Item } from '../../../../../core/shared/item.model';
12+
import { AuthService } from '../../../../../core/auth/auth.service';
13+
import { isNotEmpty } from '../../../../../shared/empty.util';
14+
import { EPerson } from '../../../../../core/eperson/models/eperson.model';
815

916
@Component({
1017
selector: 'ds-cris-layout-search-box',
@@ -26,15 +33,23 @@ export class CrisLayoutRelationBoxComponent extends CrisLayoutBoxModelComponent
2633
* flag for enable/disable search bar
2734
*/
2835
searchEnabled = false;
36+
2937
/**
30-
* The width of the sidebar (bootstrap columns)
38+
* A boolean representing if to show or not the search notice
3139
*/
32-
// sideBarWidth = 3;
40+
showSearchResultNotice$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
3341

34-
constructor(public cd: ChangeDetectorRef,
35-
protected translateService: TranslateService,
36-
@Inject('boxProvider') public boxProvider: CrisLayoutBox,
37-
@Inject('itemProvider') public itemProvider: Item) {
42+
/**
43+
* The search notice message
44+
*/
45+
searchResultNotice: string;
46+
47+
constructor(
48+
protected authService: AuthService,
49+
protected translateService: TranslateService,
50+
@Inject('boxProvider') public boxProvider: CrisLayoutBox,
51+
@Inject('itemProvider') public itemProvider: Item
52+
) {
3853
super(translateService, boxProvider, itemProvider);
3954
}
4055

@@ -43,6 +58,31 @@ export class CrisLayoutRelationBoxComponent extends CrisLayoutBoxModelComponent
4358

4459
this.searchFilter = `scope=${this.item.id}`;
4560
this.configuration = (this.box.configuration as RelationBoxConfiguration)['discovery-configuration'];
61+
const isResearchOutputsConfiguration =
62+
this.configuration?.endsWith('researchoutputs') || this.configuration?.endsWith('Publication');
63+
if (!this.isPersonEntity() || !isResearchOutputsConfiguration) {
64+
this.showSearchResultNotice$.next(false);
65+
} else {
66+
this.isProfileOwner().pipe(take(1)).subscribe((result) => {
67+
this.searchResultNotice = this.translateService.instant('manage.relationships.hidden-related-items-alert');
68+
this.showSearchResultNotice$.next(result);
69+
});
70+
}
71+
}
72+
73+
protected getOwner(user: EPerson) {
74+
return this.item.firstMetadataValue('dspace.object.owner', { authority: user.id });
4675
}
4776

77+
protected isProfileOwner(): Observable<boolean> {
78+
return this.authService.getAuthenticatedUserFromStore().pipe(
79+
filter(isNotEmpty),
80+
map((user) => isNotEmpty(this.getOwner(user))),
81+
shareReplay(1)
82+
);
83+
}
84+
85+
protected isPersonEntity(): boolean {
86+
return isNotEmpty(this.item.firstMetadataValue('dspace.entity.type', { value: 'Person' }));
87+
}
4888
}

src/app/shared/dso-page/dso-versioning-modal-service/dso-versioning-modal.service.spec.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ describe('DsoVersioningModalService', () => {
1818
let router;
1919
let workspaceItemDataService;
2020
let itemService;
21+
let editItemService;
2122

2223
const mockItem: Item = Object.assign(new Item(), {
2324
bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])),
@@ -48,6 +49,7 @@ describe('DsoVersioningModalService', () => {
4849
router = jasmine.createSpyObj('router', ['navigateByUrl']);
4950
workspaceItemDataService = jasmine.createSpyObj('workspaceItemDataService', ['findByItem']);
5051
itemService = jasmine.createSpyObj('itemService', ['findByHref']);
52+
editItemService = jasmine.createSpyObj('editItemService', ['invalidateItemCache']);
5153

5254
service = new DsoVersioningModalService(
5355
modalService,
@@ -56,7 +58,8 @@ describe('DsoVersioningModalService', () => {
5658
itemVersionShared,
5759
router,
5860
workspaceItemDataService,
59-
itemService
61+
itemService,
62+
editItemService,
6063
);
6164
}));
6265
describe('when onCreateNewVersion() is called', () => {

src/app/shared/dso-page/dso-versioning-modal-service/dso-versioning-modal.service.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import { ItemVersionsSharedService } from '../../../item-page/versions/item-vers
1616
import {
1717
ItemVersionsSummaryModalComponent
1818
} from '../../../item-page/versions/item-versions-summary-modal/item-versions-summary-modal.component';
19+
import { EditItemDataService } from '../../../core/submission/edititem-data.service';
20+
import { fromPromise } from 'rxjs/internal/observable/innerFrom';
1921

2022
/**
2123
* Service to take care of all the functionality related to the version creation modal
@@ -34,6 +36,7 @@ export class DsoVersioningModalService {
3436
protected router: Router,
3537
protected workspaceItemDataService: WorkspaceitemDataService,
3638
protected itemService: ItemDataService,
39+
protected editItemService: EditItemDataService,
3740
) {
3841
}
3942

@@ -71,11 +74,9 @@ export class DsoVersioningModalService {
7174
getFirstSucceededRemoteDataPayload<Item>(),
7275
switchMap((newVersionItem: Item) => this.workspaceItemDataService.findByItem(newVersionItem.uuid, true, false)),
7376
getFirstSucceededRemoteDataPayload<WorkspaceItem>(),
74-
).subscribe((wsItem) => {
75-
const wsiId = wsItem.id;
76-
const route = 'workspaceitems/' + wsiId + '/edit';
77-
this.router.navigateByUrl(route);
78-
});
77+
map((wsItem: WorkspaceItem) => `workspaceitems/${wsItem?.id}/edit`),
78+
switchMap((route: string) => fromPromise(this.router.navigateByUrl(route))),
79+
).subscribe(() => this.editItemService.invalidateItemCache(item.uuid));
7980
}
8081

8182
/**

0 commit comments

Comments
 (0)