Skip to content

Commit e7b70aa

Browse files
committed
Merge branch 'dspace-cris-2023_02_x' into ux-plus-2023_02_x
# Conflicts: # src/app/item-page/item-page-routing.module.ts
2 parents 03d9c08 + fe7ea18 commit e7b70aa

61 files changed

Lines changed: 876 additions & 283 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build.yml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
CYPRESS_BASE_URL: http://127.0.0.1:4000
3131
# When Chrome version is specified, we pin to a specific version of Chrome
3232
# Comment this out to use the latest release
33-
CHROME_VERSION: "116.0.5845.187-1"
33+
#CHROME_VERSION: "116.0.5845.187-1"
3434
# Bump Node heap size (OOM in CI after upgrading to Angular 15)
3535
NODE_OPTIONS: '--max-old-space-size=4096'
3636
# Project name to use when running "docker compose" prior to e2e tests
@@ -172,11 +172,12 @@ jobs:
172172
# Get homepage and verify that the <meta name="title"> tag includes "DSpace".
173173
# If it does, then SSR is working, as this tag is created by our MetadataService.
174174
# This step also prints entire HTML of homepage for easier debugging if grep fails.
175-
- name: Verify SSR (server-side rendering)
176-
run: |
177-
result=$(wget -O- -q http://127.0.0.1:4000/home)
178-
echo "$result"
179-
echo "$result" | grep -oE "<meta name=\"title\" [^>]*>" | grep DSpace
175+
# TODO: enable this step once we have a CRIS back end to test against
176+
# - name: Verify SSR (server-side rendering)
177+
# run: |
178+
# result=$(wget -O- -q http://127.0.0.1:4000/home)
179+
# echo "$result"
180+
# echo "$result" | grep -oE "<meta name=\"title\" [^>]*>" | grep DSpace
180181

181182
- name: Stop running app
182183
run: kill -9 $(lsof -t -i:4000)

bitbucket-pipelines.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ definitions:
66
- step: &unittest-code-checks
77
name: test-code-checks
88
image:
9-
name: cypress/browsers:node18.12.0-chrome107
9+
name: cypress/browsers:node-18.20.3-chrome-125.0.6422.141-1-ff-126.0.1-edge-125.0.2535.85-1
1010
run-as-user: 1000
11-
size: 2x
11+
size: 4x
1212
caches:
1313
- node
1414
script:

config/config.example.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,8 @@ submission:
187187
metadataDetailsList:
188188
- label: 'Document type'
189189
name: dc.type
190+
# Minimum number of characters required before performing a lookup.
191+
minChars: 3
190192

191193
# Default Language in which the UI will be rendered if the user's browser language is not an active language
192194
defaultLanguage: en

cypress.config.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,19 @@ export default defineConfig({
4343
// It can be overridden via the CYPRESS_BASE_URL environment variable
4444
// (By default we set this to a value which should work in most development environments)
4545
baseUrl: 'http://localhost:4000',
46+
excludeSpecPattern: [
47+
'cypress/e2e/collection-create.cy.ts',
48+
'cypress/e2e/collection-edit.cy.ts',
49+
'cypress/e2e/collection-statistics.cy.ts',
50+
'cypress/e2e/community-edit.cy.ts',
51+
'cypress/e2e/community-statistics.cy.ts',
52+
'cypress/e2e/homepage.cy.ts',
53+
'cypress/e2e/item-edit.cy.ts',
54+
'cypress/e2e/item-template.cy.ts',
55+
'cypress/e2e/login-modal.cy.ts',
56+
'cypress/e2e/search-navbar.cy.ts',
57+
'cypress/e2e/search-page.cy.ts',
58+
]
4659
},
60+
defaultCommandTimeout: 10000,
4761
});

cypress/support/e2e.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ before(() => {
5757
beforeEach(() => {
5858
// Pre-agree to all Klaro cookies by setting the klaro-anonymous cookie
5959
// This just ensures it doesn't get in the way of matching other objects in the page.
60-
cy.setCookie('klaro-anonymous', '{%22authentication%22:true%2C%22preferences%22:true%2C%22acknowledgement%22:true%2C%22google-analytics%22:true%2C%22google-recaptcha%22:true}');
60+
cy.setCookie('klaro-anonymous', '{%22authentication%22:true%2C%22preferences%22:true%2C%22acknowledgement%22:true%2C%22google-analytics%22:true%2C%22google-recaptcha%22:true%2C%22plumX%22:true%2C%22altmetric%22:true%2C%22dimensions%22:true}');
6161

6262
// Remove any CSRF cookies saved from prior tests
6363
cy.clearCookie(DSPACE_XSRF_COOKIE);

src/app/app-routing.module.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
HEALTH_PAGE_PATH,
1919
INFO_MODULE_PATH,
2020
INTERNAL_SERVER_ERROR,
21-
LEGACY_BITSTREAM_MODULE_PATH,
21+
LEGACY_BITSTREAM_MODULE_PATH, PAGE_NOT_FOUND_PATH,
2222
PROFILE_MODULE_PATH,
2323
REGISTER_PATH,
2424
REQUEST_COPY_MODULE_PATH,
@@ -55,8 +55,8 @@ import {
5555
@NgModule({
5656
imports: [
5757
RouterModule.forRoot([
58-
{ path: INTERNAL_SERVER_ERROR, component: ThemedPageInternalServerErrorComponent },
59-
{ path: ERROR_PAGE , component: ThemedPageErrorComponent },
58+
{ path: INTERNAL_SERVER_ERROR, component: ThemedPageInternalServerErrorComponent, data: { title: INTERNAL_SERVER_ERROR } },
59+
{ path: ERROR_PAGE , component: ThemedPageErrorComponent, data: { title: ERROR_PAGE} },
6060
{
6161
path: '',
6262
canActivate: [AuthBlockingGuard],
@@ -68,7 +68,10 @@ import {
6868
path: 'reload/:rnd',
6969
component: ThemedPageNotFoundComponent,
7070
pathMatch: 'full',
71-
canActivate: [ReloadGuard]
71+
canActivate: [ReloadGuard],
72+
data: {
73+
title: PAGE_NOT_FOUND_PATH
74+
}
7275
},
7376
{
7477
path: 'home',
@@ -275,7 +278,10 @@ import {
275278
},
276279
{
277280
path: FORBIDDEN_PATH,
278-
component: ThemedForbiddenComponent
281+
component: ThemedForbiddenComponent,
282+
data: {
283+
title: FORBIDDEN_PATH
284+
}
279285
},
280286
{
281287
path: STATISTICS_PAGE_PATH,
@@ -314,7 +320,7 @@ import {
314320
loadChildren: () => import('./invitation/invitation.module')
315321
.then((m) => m.InvitationModule)
316322
},
317-
{ path: '**', pathMatch: 'full', component: ThemedPageNotFoundComponent, canActivate: [RedirectService] },
323+
{ path: '**', pathMatch: 'full', component: ThemedPageNotFoundComponent, canActivate: [RedirectService], data: { title: PAGE_NOT_FOUND_PATH } },
318324
]
319325
}
320326
], {

src/app/bitstream-page/bitstream-download-page/bitstream-download-page.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<div class="container">
22
<div class="d-flex justify-content-between">
3-
<h1 class="h3">{{'bitstream.download.page' | translate:{ bitstream: dsoNameService.getName((bitstream$ | async)) } }}</h1>
3+
<h1 class="h3">{{'bitstream.download.page' | translate:{ bitstream: (fileName$ | async) } }}</h1>
44
<div class="pt-3">
55
<button *ngIf="hasHistory" (click)="back()" class="btn btn-outline-secondary">
66
<i class="fas fa-arrow-left"></i> {{'bitstream.download.page.back' | translate}}

src/app/bitstream-page/bitstream-download-page/bitstream-download-page.component.spec.ts

Lines changed: 0 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { AuthorizationDataService } from '../../core/data/feature-authorization/
88
import { HardRedirectService } from '../../core/services/hard-redirect.service';
99
import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils';
1010
import { ActivatedRoute, Router } from '@angular/router';
11-
import { getForbiddenRoute } from '../../app-routing-paths';
1211
import { TranslateModule } from '@ngx-translate/core';
1312
import { CommonModule } from '@angular/common';
1413
import { SignpostingDataService } from '../../core/data/signposting-data.service';
@@ -123,72 +122,4 @@ describe('BitstreamDownloadPageComponent', () => {
123122
expect(component).toBeTruthy();
124123
});
125124
});
126-
127-
describe('bitstream retrieval', () => {
128-
describe('when the user is authorized and not logged in', () => {
129-
beforeEach(waitForAsync(() => {
130-
init();
131-
(authService.isAuthenticated as jasmine.Spy).and.returnValue(observableOf(false));
132-
133-
initTestbed();
134-
}));
135-
beforeEach(() => {
136-
fixture = TestBed.createComponent(BitstreamDownloadPageComponent);
137-
component = fixture.componentInstance;
138-
fixture.detectChanges();
139-
});
140-
it('should redirect to the content link', () => {
141-
expect(hardRedirectService.redirect).toHaveBeenCalledWith('bitstream-content-link');
142-
});
143-
it('should add the signposting links', () => {
144-
expect(serverResponseService.setHeader).toHaveBeenCalled();
145-
});
146-
});
147-
describe('when the user is authorized and logged in', () => {
148-
beforeEach(waitForAsync(() => {
149-
init();
150-
initTestbed();
151-
}));
152-
beforeEach(() => {
153-
fixture = TestBed.createComponent(BitstreamDownloadPageComponent);
154-
component = fixture.componentInstance;
155-
fixture.detectChanges();
156-
});
157-
it('should redirect to an updated content link', () => {
158-
expect(hardRedirectService.redirect).toHaveBeenCalledWith('content-url-with-headers');
159-
});
160-
});
161-
describe('when the user is not authorized and logged in', () => {
162-
beforeEach(waitForAsync(() => {
163-
init();
164-
(authorizationService.isAuthorized as jasmine.Spy).and.returnValue(observableOf(false));
165-
initTestbed();
166-
}));
167-
beforeEach(() => {
168-
fixture = TestBed.createComponent(BitstreamDownloadPageComponent);
169-
component = fixture.componentInstance;
170-
fixture.detectChanges();
171-
});
172-
it('should navigate to the forbidden route', () => {
173-
expect(router.navigateByUrl).toHaveBeenCalledWith(getForbiddenRoute(), { skipLocationChange: true });
174-
});
175-
});
176-
describe('when the user is not authorized and not logged in', () => {
177-
beforeEach(waitForAsync(() => {
178-
init();
179-
(authService.isAuthenticated as jasmine.Spy).and.returnValue(observableOf(false));
180-
(authorizationService.isAuthorized as jasmine.Spy).and.returnValue(observableOf(false));
181-
initTestbed();
182-
}));
183-
beforeEach(() => {
184-
fixture = TestBed.createComponent(BitstreamDownloadPageComponent);
185-
component = fixture.componentInstance;
186-
fixture.detectChanges();
187-
});
188-
it('should navigate to the login page', () => {
189-
expect(authService.setRedirectUrl).toHaveBeenCalled();
190-
expect(router.navigateByUrl).toHaveBeenCalledWith('login');
191-
});
192-
});
193-
});
194125
});

src/app/bitstream-page/bitstream-download-page/bitstream-download-page.component.ts

Lines changed: 6 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
import { Component, Inject, OnInit, PLATFORM_ID } from '@angular/core';
2-
import { filter, map, startWith, switchMap, take } from 'rxjs/operators';
2+
import { map, startWith, take } from 'rxjs/operators';
33
import { ActivatedRoute, Router } from '@angular/router';
4-
import { hasValue, isNotEmpty } from '../../shared/empty.util';
4+
import { isNotEmpty } from '../../shared/empty.util';
55
import { getRemoteDataPayload } from '../../core/shared/operators';
66
import { Bitstream } from '../../core/shared/bitstream.model';
77
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
8-
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
98
import { AuthService } from '../../core/auth/auth.service';
10-
import { combineLatest as observableCombineLatest, Observable, of as observableOf } from 'rxjs';
9+
import { Observable } from 'rxjs';
1110
import { FileService } from '../../core/shared/file.service';
1211
import { HardRedirectService } from '../../core/services/hard-redirect.service';
13-
import { getForbiddenRoute } from '../../app-routing-paths';
1412
import { RemoteData } from '../../core/data/remote-data';
15-
import { redirectOn4xx } from '../../core/shared/authorized.operators';
1613
import { isPlatformServer, Location } from '@angular/common';
1714
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
1815
import { SignpostingDataService } from '../../core/data/signposting-data.service';
@@ -62,52 +59,18 @@ export class BitstreamDownloadPageComponent implements OnInit {
6259
}
6360

6461
ngOnInit(): void {
65-
6662
this.bitstreamRD$ = this.route.data.pipe(
67-
map((data) => data.bitstream));
63+
map((data) => data.bitstream)
64+
);
6865

6966
this.bitstream$ = this.bitstreamRD$.pipe(
70-
redirectOn4xx(this.router, this.auth),
7167
getRemoteDataPayload()
7268
);
7369

7470
this.fileName$ = this.bitstream$.pipe(
7571
map((bitstream: Bitstream) => this.dsoNameService.getName(bitstream)),
76-
startWith('file'),
72+
startWith('file')
7773
);
78-
79-
this.bitstream$.pipe(
80-
switchMap((bitstream: Bitstream) => {
81-
const isAuthorized$ = this.authorizationService.isAuthorized(FeatureID.CanDownload, isNotEmpty(bitstream) ? bitstream.self : undefined);
82-
const isLoggedIn$ = this.auth.isAuthenticated();
83-
return observableCombineLatest([isAuthorized$, isLoggedIn$, observableOf(bitstream)]);
84-
}),
85-
filter(([isAuthorized, isLoggedIn, bitstream]: [boolean, boolean, Bitstream]) => hasValue(isAuthorized) && hasValue(isLoggedIn)),
86-
take(1),
87-
switchMap(([isAuthorized, isLoggedIn, bitstream]: [boolean, boolean, Bitstream]) => {
88-
if (isAuthorized && isLoggedIn) {
89-
return this.fileService.retrieveFileDownloadLink(bitstream._links.content.href).pipe(
90-
filter((fileLink) => hasValue(fileLink)),
91-
take(1),
92-
map((fileLink) => {
93-
return [isAuthorized, isLoggedIn, bitstream, fileLink];
94-
}));
95-
} else {
96-
return [[isAuthorized, isLoggedIn, bitstream, '']];
97-
}
98-
})
99-
).subscribe(([isAuthorized, isLoggedIn, bitstream, fileLink]: [boolean, boolean, Bitstream, string]) => {
100-
if (isAuthorized && isLoggedIn && isNotEmpty(fileLink)) {
101-
this.hardRedirectService.redirect(fileLink);
102-
} else if (isAuthorized && !isLoggedIn) {
103-
this.hardRedirectService.redirect(bitstream._links.content.href);
104-
} else if (!isAuthorized && isLoggedIn) {
105-
this.router.navigateByUrl(getForbiddenRoute(), {skipLocationChange: true});
106-
} else if (!isAuthorized && !isLoggedIn) {
107-
this.auth.setRedirectUrl(this.router.url);
108-
this.router.navigateByUrl('login');
109-
}
110-
});
11174
}
11275

11376
/**
@@ -124,7 +87,6 @@ export class BitstreamDownloadPageComponent implements OnInit {
12487
signpostingLinks.forEach((link: SignpostingLink) => {
12588
links = links + (isNotEmpty(links) ? ', ' : '') + `<${link.href}> ; rel="${link.rel}"` + (isNotEmpty(link.type) ? ` ; type="${link.type}" ` : ' ');
12689
});
127-
12890
this.responseService.setHeader('Link', links);
12991
});
13092
});

0 commit comments

Comments
 (0)