Skip to content

Commit 85f2854

Browse files
author
Andrea Barbasso
committed
Merged dspace-cris-2025_02_x into task/dspace-cris-2025_02_x/DSC-2607
2 parents be956af + c420571 commit 85f2854

21 files changed

Lines changed: 328 additions & 96 deletions

File tree

.github/workflows/build.yml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ name: Build
77
on: [push, pull_request]
88

99
permissions:
10-
contents: read # to fetch code (actions/checkout)
11-
packages: read # to fetch private images from GitHub Container Registry (GHCR)
10+
contents: read # to fetch code (actions/checkout)
11+
packages: read # to fetch private images from GitHub Container Registry (GHCR)
1212

1313
jobs:
1414
tests:
@@ -19,7 +19,7 @@ jobs:
1919
# NOTE: These settings should be kept in sync with those in [src]/docker/docker-compose-ci.yml
2020
DSPACE_REST_HOST: 127.0.0.1
2121
DSPACE_REST_PORT: 8080
22-
DSPACE_REST_NAMESPACE: '/server'
22+
DSPACE_REST_NAMESPACE: "/server"
2323
DSPACE_REST_SSL: false
2424
# Spin up UI on 127.0.0.1 to avoid host resolution issues in e2e tests with Node 20+
2525
DSPACE_UI_HOST: 127.0.0.1
@@ -35,9 +35,9 @@ jobs:
3535
# Comment this out to use the latest release
3636
#CHROME_VERSION: "116.0.5845.187-1"
3737
# Bump Node heap size (OOM in CI after upgrading to Angular 15)
38-
NODE_OPTIONS: '--max-old-space-size=4096'
38+
NODE_OPTIONS: "--max-old-space-size=4096"
3939
# Project name to use when running "docker compose" prior to e2e tests
40-
COMPOSE_PROJECT_NAME: 'ci'
40+
COMPOSE_PROJECT_NAME: "ci"
4141
# Docker Registry to use for Docker compose scripts below.
4242
# We use GitHub's Container Registry to avoid aggressive rate limits at DockerHub.
4343
DOCKER_REGISTRY: ghcr.io
@@ -117,7 +117,7 @@ jobs:
117117
if: matrix.node-version == '20.x'
118118
with:
119119
name: coverage-report-${{ matrix.node-version }}
120-
path: 'coverage/dspace-angular/lcov.info'
120+
path: "coverage/dspace-angular/lcov.info"
121121
retention-days: 14
122122

123123
# Login to our Docker registry, so that we can access private Docker images using "docker compose" below.
@@ -142,6 +142,7 @@ jobs:
142142
- name: Run e2e tests (integration tests)
143143
uses: cypress-io/github-action@v6
144144
with:
145+
install-command: npm ci
145146
# Run tests in Chrome, headless mode (default)
146147
browser: chrome
147148
# Start app before running tests (will be stopped automatically after tests finish)
@@ -234,9 +235,9 @@ jobs:
234235
# the name of the project. If it does, then SSR is working.
235236
- name: Verify SSR on a Project page
236237
run: |
237-
result=$(wget -O- -q http://127.0.0.1:4000/entities/project/1e3451e4-60d7-46a8-962e-5b94b62c63ff)
238+
result=$(wget -O- -q http://127.0.0.1:4000/entities/project/28f8f49a-1aaf-4acc-93a9-203f3cf7ba62)
238239
echo "$result"
239-
echo "$result" | grep -oE "<meta name=\"title\" [^>]*>" | grep "Test DSC-1819"
240+
echo "$result" | grep -oE "<meta name=\"title\" [^>]*>" | grep "TEST PROJECT"
240241
241242
# Get a specific orgunit in our test data and verify that the <meta name="title"> tag includes
242243
# the name of the orgunit. If it does, then SSR is working.
@@ -262,7 +263,6 @@ jobs:
262263
echo "$result"
263264
echo "$result" | grep -oE "<meta name=\"title\" [^>]*>" | grep "test funding"
264265
265-
266266
# Verify 301 Handle redirect behavior
267267
# Note: /handle/123456789/260 is the same test Publication used by our e2e tests
268268
- name: Verify 301 redirect from '/handle' URLs

cypress/e2e/my-dspace.cy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ describe('My DSpace page', () => {
119119
// Open the New Import dropdown
120120
cy.get('button[data-test="import-dropdown"]').click();
121121
// Click on the "Item" type in that dropdown
122-
cy.get('#importControlsDropdownMenu button[title="Equipment"]').click();
122+
cy.get('#importControlsDropdownMenu button[title="Funding"]').click();
123123

124124
// New URL should include /import-external, as we've moved to the import page
125125
cy.url().should('include', '/import-external');

cypress/support/e2e.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ import 'cypress-axe';
2121

2222
import { DSPACE_XSRF_COOKIE } from 'src/app/core/xsrf/xsrf.constants';
2323

24+
Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
25+
return originalFn(url, options).then(() => {
26+
cy.get('[data-test="ds-hydrated"]');
27+
});
28+
});
29+
2430
// We might receive uncaught exceptions from external libraries (e.g. it happened before with a broken
2531
// version of the addToAny plugin). These should not cause our tests to fail, so we catch them here.
2632
Cypress.on('uncaught:exception', (err, runnable) => {

docker/db.entities.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
# # Therefore, it should be kept in sync with that file
1515
services:
1616
dspacedb:
17-
image: "${DOCKER_REGISTRY:-docker.io}/${DOCKER_OWNER:-4science}/dspace-cris-postgres-pgcrypto:${DSPACE_VER:-dspace-cris-2025_02_x}-loadsql"
17+
image: "${DOCKER_REGISTRY:-docker.io}/${DOCKER_OWNER:-4science}/dspace-cris-postgres-loadsql:${DSPACE_VER:-dspace-cris-2025_02_x}"
1818
environment:
1919
# This LOADSQL should be kept in sync with the URL in 4Science/DSpace
2020
# This SQL is available from https://github.com/4Science/DSpace-CRIS-Files/releases/download/cris-2025.02.00/db-entities.sql

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "dspace-angular",
3-
"version": "2025.02.00-SNAPSHOT",
3+
"version": "2025.02.01-SNAPSHOT",
44
"scripts": {
55
"ng": "ng",
66
"test:rest": "ts-node --project ./tsconfig.ts-node.json scripts/test-rest.ts",

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

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ <h2 class="flex-grow-1">{{'audit.object.overview.title' | translate}}</h2>
55

66
@if (object) {
77
<h4 class="mt-4 mb-4">{{ object.name }} (<em>{{object.type}}</em>)</h4>
8-
@if ((auditsRD$ | async)?.payload; as audits) {
8+
@let auditRD = (auditsRD$ | async);
9+
@let audits = auditRD?.payload;
10+
@if (audits) {
911
@if (audits.totalElements === 0) {
1012
<div>
1113
No audits found.
@@ -29,22 +31,25 @@ <h4 class="mt-4 mb-4">{{ object.name }} (<em>{{object.type}}</em>)</h4>
2931
</tr>
3032
</thead>
3133
<tbody>
32-
@for (audit of audits.page; track audit) {
34+
@for (audit of audits.page; track audit.id) {
3335
<tr>
3436
<!-- <td><a [routerLink]="['/auditlogs/', audit.id]">{{audit.id}}</a></td> -->
3537
<td>{{ audit.eventType }}</td>
36-
<td *ngVar="(getEpersonName(audit) | async) as ePersonName">{{ePersonName}}</td>
38+
<td>
39+
@let epersonName = (audit?.epersonName | async);
40+
@if (epersonName) {
41+
<span>{{epersonName}}</span>
42+
} @else {
43+
<em>{{ 'audit.overview.table.eperson.anonymous' | translate }}</em>
44+
}
45+
</td>
3746
<td>{{ audit.timeStamp | date:dateFormat}}</td>
3847
<td>
3948
@if (object.id === audit.objectUUID) {
40-
<span>
41-
<!-- object.id === audit.objectUUID -->
42-
@if ((getOtherObject(audit, object.id) | async); as subject) {
43-
@if (subject) {
44-
{{ subject.name }} <em>({{ subject.type }})</em>
45-
}
46-
}
47-
</span>
49+
@let subject = $any(audit.subject | async);
50+
@if (subject) {
51+
<span>{{ subject?.name }} <em>({{ subject?.type }})</em></span>
52+
}
4853
}
4954
@if (object.id === audit.subjectUUID) {
5055
<span>
@@ -62,7 +67,7 @@ <h4 class="mt-4 mb-4">{{ object.name }} (<em>{{object.type}}</em>)</h4>
6267
<a class="btn btn-light mt-3" [routerLink]="['/items', object.id]"><i class="fas fa-arrow-left"></i> Back to Item</a>
6368
<!-- <a class="btn btn-light mt-3" [routerLink]="'/auditlogs'">{{'audit.detail.back' | translate}}</a> -->
6469
}
65-
@if ((auditsRD$ | async)?.statusCode === 404) {
70+
@if (auditRD?.statusCode === 404) {
6671
<h4 class="mt-4 mb-4">{{'audit.object.overview.disabled.message' | translate}}</h4>
6772
}
6873
}

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

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ import {
2626
} from 'rxjs/operators';
2727

2828
import { COLLECTION_PAGE_LINKS_TO_FOLLOW } from '../../collection-page/collection-page.resolver';
29-
import { AuditDataService } from '../../core/audit/audit-data.service';
30-
import { Audit } from '../../core/audit/model/audit.model';
29+
import {
30+
AuditDataService,
31+
AuditDetails,
32+
} from '../../core/audit/audit-data.service';
3133
import { AuthService } from '../../core/auth/auth.service';
3234
import { SortDirection } from '../../core/cache/models/sort-options.model';
3335
import { CollectionDataService } from '../../core/data/collection-data.service';
@@ -44,7 +46,6 @@ import { Item } from '../../core/shared/item.model';
4446
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
4547
import { PaginationComponent } from '../../shared/pagination/pagination.component';
4648
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
47-
import { VarDirective } from '../../shared/utils/var.directive';
4849

4950
/**
5051
* Component displaying a list of all audit about a object in a paginated table
@@ -58,7 +59,6 @@ import { VarDirective } from '../../shared/utils/var.directive';
5859
PaginationComponent,
5960
RouterLink,
6061
TranslateModule,
61-
VarDirective,
6262
],
6363
})
6464
export class ObjectAuditOverviewComponent implements OnInit {
@@ -71,7 +71,7 @@ export class ObjectAuditOverviewComponent implements OnInit {
7171
/**
7272
* List of all audits
7373
*/
74-
auditsRD$: Observable<RemoteData<PaginatedList<Audit>>>;
74+
auditsRD$: Observable<RemoteData<PaginatedList<AuditDetails>>>;
7575

7676
/**
7777
* The current pagination configuration for the page used by the FindAll method
@@ -143,9 +143,13 @@ export class ObjectAuditOverviewComponent implements OnInit {
143143

144144

145145
this.auditsRD$ = combineLatest([isAdmin$, config$, this.owningCollection$, parentCommunity$]).pipe(
146-
mergeMap(([isAdmin, config, owningCollection, parentCommunity]) => {
146+
mergeMap(([isAdmin, config, owningCollection, parentCommunity]) => {
147147
if (isAdmin) {
148-
return this.auditService.findByObject(this.object.id, config, owningCollection.id, parentCommunity.id);
148+
return this.auditService.findByObject(this.object.id, config, owningCollection.id, parentCommunity.id)
149+
.pipe(
150+
getFirstCompletedRemoteData(),
151+
map(data => this.auditService.mapToAuditDetails(data)),
152+
);
149153
}
150154

151155
return of(null);
@@ -166,16 +170,5 @@ export class ObjectAuditOverviewComponent implements OnInit {
166170
);
167171
}
168172

169-
/**
170-
* Get the name of an EPerson by ID
171-
* @param audit Audit object
172-
*/
173-
getEpersonName(audit: Audit): Observable<string> {
174-
return this.auditService.getEpersonName(audit);
175-
}
176-
177-
getOtherObject(audit: Audit, contextObjectId: string): Observable<any> {
178-
return this.auditService.getOtherObject(audit, contextObjectId);
179-
}
180173

181174
}

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

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,18 @@
33
<h2 class="flex-grow-1">{{'audit.overview.title' | translate}}</h2>
44
</div>
55

6-
@if (isAdmin$ | async) {
7-
@if ((auditsRD$ | async)?.payload?.totalElements === 0) {
6+
@let isAdmin = (isAdmin$ | async);
7+
@if (isAdmin) {
8+
@let audits = (auditsRD$ | async)?.payload;
9+
@if (audits?.totalElements === 0) {
810
<div>
911
No audits found.
1012
</div>
1113
}
12-
@if ((auditsRD$ | async)?.payload?.totalElements > 0) {
14+
@if (audits?.totalElements > 0) {
1315
<ds-pagination
1416
[paginationOptions]="pageConfig"
15-
[collectionSize]="(auditsRD$ | async)?.payload?.totalElements"
17+
[collectionSize]="audits?.totalElements"
1618
[hideGear]="true"
1719
[hidePagerWhenSinglePage]="true">
1820
<div class="table-responsive">
@@ -30,7 +32,8 @@ <h2 class="flex-grow-1">{{'audit.overview.title' | translate}}</h2>
3032
</tr>
3133
</thead>
3234
<tbody>
33-
@for (audit of (auditsRD$ | async)?.payload?.page; track audit) {
35+
@for (audit of audits?.page; track audit.id) {
36+
@let epersonName = (audit.epersonName | async);
3437
<tr>
3538
<td><a [routerLink]="['/auditlogs/', audit.id]">{{audit.id}}</a></td>
3639
<td>{{ audit.eventType }}</td>
@@ -40,7 +43,13 @@ <h2 class="flex-grow-1">{{'audit.overview.title' | translate}}</h2>
4043
<td>{{ audit.objectType }}</td>
4144
<td>{{ audit.subjectUUID }}</td>
4245
<td>{{ audit.subjectType }}</td>
43-
<td *ngVar="(getEpersonName(audit) | async) as ePersonName">{{ePersonName}}</td>
46+
<td>
47+
@if (epersonName) {
48+
<span>{{epersonName}}</span>
49+
} @else {
50+
<span><em>{{ 'audit.overview.table.eperson.anonymous' | translate }}</em></span>
51+
}
52+
</td>
4453
<td>{{ audit.timeStamp | date:dateFormat}}</td>
4554
</tr>
4655
}

src/app/audit-page/overview/audit-overview.component.spec.ts

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { NO_ERRORS_SCHEMA } from '@angular/core';
22
import {
33
ComponentFixture,
4+
fakeAsync,
45
TestBed,
56
waitForAsync,
67
} from '@angular/core/testing';
@@ -9,13 +10,22 @@ import { RouterTestingModule } from '@angular/router/testing';
910
import { TranslateModule } from '@ngx-translate/core';
1011
import { of } from 'rxjs';
1112

12-
import { AuditDataService } from '../../core/audit/audit-data.service';
13+
import {
14+
AuditDataService,
15+
AuditDetails,
16+
} from '../../core/audit/audit-data.service';
1317
import { Audit } from '../../core/audit/model/audit.model';
1418
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
1519
import { PaginationService } from '../../core/pagination/pagination.service';
1620
import { PaginationComponent } from '../../shared/pagination/pagination.component';
17-
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
18-
import { AuditMock } from '../../shared/testing/audit.mock';
21+
import {
22+
createSuccessfulRemoteDataObject,
23+
createSuccessfulRemoteDataObject$,
24+
} from '../../shared/remote-data.utils';
25+
import {
26+
AuditDetailsMock,
27+
AuditMock,
28+
} from '../../shared/testing/audit.mock';
1929
import { PaginationServiceStub } from '../../shared/testing/pagination-service.stub';
2030
import { createPaginatedList } from '../../shared/testing/utils.test';
2131
import { VarDirective } from '../../shared/utils/var.directive';
@@ -28,15 +38,21 @@ describe('AuditOverviewComponent', () => {
2838
let auditService: AuditDataService;
2939
let authorizationService: any;
3040
let audits: Audit[];
41+
let auditDetails: AuditDetails[];
3142
const paginationService = new PaginationServiceStub();
3243

3344
function init() {
34-
audits = [ AuditMock, AuditMock, AuditMock ];
35-
auditService = jasmine.createSpyObj('processService', {
45+
audits = [AuditMock, AuditMock, AuditMock];
46+
auditDetails = [AuditDetailsMock, AuditDetailsMock, AuditDetailsMock];
47+
auditService = jasmine.createSpyObj('auditService', {
3648
findAll: createSuccessfulRemoteDataObject$(createPaginatedList(audits)),
3749
getEpersonName: of('Eperson Name'),
50+
mapToAuditDetails: createSuccessfulRemoteDataObject(createPaginatedList(auditDetails)),
51+
});
52+
53+
authorizationService = jasmine.createSpyObj('authorizationService', {
54+
isAuthorized: jasmine.createSpy('isAuthorized'),
3855
});
39-
authorizationService = jasmine.createSpyObj('authorizationService', ['isAuthorized']);
4056
}
4157

4258
beforeEach(waitForAsync(() => {
@@ -54,13 +70,13 @@ describe('AuditOverviewComponent', () => {
5470

5571
describe('if the current user is an admin', () => {
5672

57-
beforeEach(() => {
58-
authorizationService.isAuthorized.and.callFake(() => of(true));
73+
beforeEach(fakeAsync(() => {
74+
authorizationService.isAuthorized.and.returnValue(of(true));
5975

6076
fixture = TestBed.createComponent(AuditOverviewComponent);
6177
component = fixture.componentInstance;
6278
fixture.detectChanges();
63-
});
79+
}));
6480

6581
describe('table structure', () => {
6682
let rowElements;
@@ -118,7 +134,7 @@ describe('AuditOverviewComponent', () => {
118134
it('should display the eperson name in the seventh column', () => {
119135
rowElements.forEach((rowElement, index) => {
120136
const el = rowElement.query(By.css('td:nth-child(7)')).nativeElement;
121-
expect(el.textContent).toContain('Eperson Name');
137+
expect(el.textContent).toContain('Eperson Test');
122138
});
123139
});
124140

0 commit comments

Comments
 (0)