Skip to content

Commit 20a9b52

Browse files
Merge branch 'legacy-bitstream-redirect-7.6' into legacy-bitstream-redirect_contribute-main
# Conflicts: # src/app/bitstream-page/bitstream-page-routing.module.ts # src/app/bitstream-page/legacy-bitstream-url.resolver.spec.ts # src/app/bitstream-page/legacy-bitstream-url.resolver.ts
2 parents d74e672 + 369bd69 commit 20a9b52

6 files changed

Lines changed: 250 additions & 199 deletions

src/app/bitstream-page/bitstream-page-routes.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { BitstreamAuthorizationsComponent } from './bitstream-authorizations/bit
1111
import { BitstreamDownloadPageComponent } from './bitstream-download-page/bitstream-download-page.component';
1212
import { bitstreamPageResolver } from './bitstream-page.resolver';
1313
import { ThemedEditBitstreamPageComponent } from './edit-bitstream-page/themed-edit-bitstream-page.component';
14-
import { legacyBitstreamUrlResolver } from './legacy-bitstream-url.resolver';
14+
import { legacyBitstreamURLRedirectGuard } from './legacy-bitstream-url-redirect.guard';
1515

1616
const EDIT_BITSTREAM_PATH = ':id/edit';
1717
const EDIT_BITSTREAM_AUTHORIZATIONS_PATH = ':id/authorizations';
@@ -24,17 +24,13 @@ export const ROUTES: Route[] = [
2424
// Resolve XMLUI bitstream download URLs
2525
path: 'handle/:prefix/:suffix/:filename',
2626
component: BitstreamDownloadPageComponent,
27-
resolve: {
28-
bitstream: legacyBitstreamUrlResolver,
29-
},
27+
canActivate: [legacyBitstreamURLRedirectGuard],
3028
},
3129
{
3230
// Resolve JSPUI bitstream download URLs
3331
path: ':prefix/:suffix/:sequence_id/:filename',
3432
component: BitstreamDownloadPageComponent,
35-
resolve: {
36-
bitstream: legacyBitstreamUrlResolver,
37-
},
33+
canActivate: [legacyBitstreamURLRedirectGuard],
3834
},
3935
{
4036
// Resolve angular bitstream download URLs
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import { fakeAsync } from '@angular/core/testing';
2+
import { cold } from 'jasmine-marbles';
3+
import { EMPTY } from 'rxjs';
4+
5+
import { PAGE_NOT_FOUND_PATH } from '../app-routing-paths';
6+
import { BitstreamDataService } from '../core/data/bitstream-data.service';
7+
import { RemoteData } from '../core/data/remote-data';
8+
import { RequestEntryState } from '../core/data/request-entry-state.model';
9+
import { Bitstream } from '../core/shared/bitstream.model';
10+
import { RouterStub } from '../shared/testing/router.stub';
11+
import { ServerResponseServiceStub } from '../shared/testing/server-response-service.stub';
12+
import { legacyBitstreamURLRedirectGuard } from './legacy-bitstream-url-redirect.guard';
13+
14+
describe('legacyBitstreamURLRedirectGuard', () => {
15+
let resolver: any;
16+
let bitstreamDataService: BitstreamDataService;
17+
let remoteDataMocks: { [type: string]: RemoteData<Bitstream> };
18+
let route;
19+
let state;
20+
let serverResponseService: ServerResponseServiceStub;
21+
let router: RouterStub;
22+
23+
beforeEach(() => {
24+
route = {
25+
params: {},
26+
queryParams: {},
27+
};
28+
router = new RouterStub();
29+
serverResponseService = new ServerResponseServiceStub();
30+
state = {};
31+
remoteDataMocks = {
32+
RequestPending: new RemoteData(undefined, 0, 0, RequestEntryState.RequestPending, undefined, undefined, undefined),
33+
ResponsePending: new RemoteData(undefined, 0, 0, RequestEntryState.ResponsePending, undefined, undefined, undefined),
34+
Success: new RemoteData(0, 0, 0, RequestEntryState.Success, undefined, new Bitstream(), 200),
35+
NoContent: new RemoteData(0, 0, 0, RequestEntryState.Success, undefined, undefined, 204),
36+
Error: new RemoteData(0, 0, 0, RequestEntryState.Error, 'Internal server error', undefined, 500),
37+
};
38+
bitstreamDataService = {
39+
findByItemHandle: () => undefined,
40+
} as any;
41+
resolver = legacyBitstreamURLRedirectGuard;
42+
});
43+
44+
describe(`resolve`, () => {
45+
describe(`For JSPUI-style URLs`, () => {
46+
beforeEach(() => {
47+
spyOn(bitstreamDataService, 'findByItemHandle').and.returnValue(EMPTY);
48+
route = Object.assign({}, route, {
49+
params: {
50+
prefix: '123456789',
51+
suffix: '1234',
52+
filename: 'some-file.pdf',
53+
sequence_id: '5',
54+
},
55+
});
56+
});
57+
it(`should call findByItemHandle with the handle, sequence id, and filename from the route`, () => {
58+
resolver(route, state, bitstreamDataService, serverResponseService, router);
59+
expect(bitstreamDataService.findByItemHandle).toHaveBeenCalledWith(
60+
`${route.params.prefix}/${route.params.suffix}`,
61+
route.params.sequence_id,
62+
route.params.filename,
63+
);
64+
});
65+
});
66+
67+
describe(`For XMLUI-style URLs`, () => {
68+
describe(`when there is a sequenceId query parameter`, () => {
69+
beforeEach(() => {
70+
spyOn(bitstreamDataService, 'findByItemHandle').and.returnValue(EMPTY);
71+
route = Object.assign({}, route, {
72+
params: {
73+
prefix: '123456789',
74+
suffix: '1234',
75+
filename: 'some-file.pdf',
76+
},
77+
queryParams: {
78+
sequenceId: '5',
79+
},
80+
});
81+
});
82+
it(`should call findByItemHandle with the handle and filename from the route, and the sequence ID from the queryParams`, () => {
83+
resolver(route, state, bitstreamDataService, serverResponseService, router);
84+
expect(bitstreamDataService.findByItemHandle).toHaveBeenCalledWith(
85+
`${route.params.prefix}/${route.params.suffix}`,
86+
route.queryParams.sequenceId,
87+
route.params.filename,
88+
);
89+
});
90+
});
91+
describe(`when there's no sequenceId query parameter`, () => {
92+
beforeEach(() => {
93+
spyOn(bitstreamDataService, 'findByItemHandle').and.returnValue(EMPTY);
94+
route = Object.assign({}, route, {
95+
params: {
96+
prefix: '123456789',
97+
suffix: '1234',
98+
filename: 'some-file.pdf',
99+
},
100+
});
101+
});
102+
it(`should call findByItemHandle with the handle, and filename from the route`, () => {
103+
resolver(route, state, bitstreamDataService, serverResponseService, router);
104+
expect(bitstreamDataService.findByItemHandle).toHaveBeenCalledWith(
105+
`${route.params.prefix}/${route.params.suffix}`,
106+
undefined,
107+
route.params.filename,
108+
);
109+
});
110+
});
111+
});
112+
describe('should return and complete after the RemoteData has...', () => {
113+
it('...failed', fakeAsync(() => {
114+
spyOn(router, 'createUrlTree').and.callThrough();
115+
spyOn(bitstreamDataService, 'findByItemHandle').and.returnValue(cold('a-b-c', {
116+
a: remoteDataMocks.RequestPending,
117+
b: remoteDataMocks.ResponsePending,
118+
c: remoteDataMocks.Error,
119+
}));
120+
resolver(route, state, bitstreamDataService, serverResponseService, router).subscribe(() => {
121+
expect(bitstreamDataService.findByItemHandle).toHaveBeenCalled();
122+
expect(router.createUrlTree).toHaveBeenCalledWith([PAGE_NOT_FOUND_PATH]);
123+
});
124+
}));
125+
126+
it('...succeeded without content', fakeAsync(() => {
127+
spyOn(router, 'createUrlTree').and.callThrough();
128+
spyOn(bitstreamDataService, 'findByItemHandle').and.returnValue(cold('a-b-c', {
129+
a: remoteDataMocks.RequestPending,
130+
b: remoteDataMocks.ResponsePending,
131+
c: remoteDataMocks.NoContent,
132+
}));
133+
resolver(route, state, bitstreamDataService, serverResponseService, router).subscribe(() => {
134+
expect(bitstreamDataService.findByItemHandle).toHaveBeenCalled();
135+
expect(router.createUrlTree).toHaveBeenCalledWith([PAGE_NOT_FOUND_PATH]);
136+
});
137+
}));
138+
139+
it('...succeeded', fakeAsync(() => {
140+
spyOn(serverResponseService, 'setStatus').and.callThrough();
141+
spyOn(bitstreamDataService, 'findByItemHandle').and.returnValue(cold('a-b-c', {
142+
a: remoteDataMocks.RequestPending,
143+
b: remoteDataMocks.ResponsePending,
144+
c: remoteDataMocks.Success,
145+
}));
146+
resolver(route, state, bitstreamDataService, serverResponseService, router).subscribe(() => {
147+
expect(bitstreamDataService.findByItemHandle).toHaveBeenCalled();
148+
expect(serverResponseService.setStatus).toHaveBeenCalledWith(301);
149+
expect(router.parseUrl).toHaveBeenCalled();
150+
});
151+
}));
152+
});
153+
});
154+
});
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { inject } from '@angular/core';
2+
import {
3+
ActivatedRouteSnapshot,
4+
CanActivateFn,
5+
Router,
6+
RouterStateSnapshot,
7+
UrlTree,
8+
} from '@angular/router';
9+
import { Observable } from 'rxjs';
10+
import {
11+
map,
12+
tap,
13+
} from 'rxjs/operators';
14+
15+
import { PAGE_NOT_FOUND_PATH } from '../app-routing-paths';
16+
import { BitstreamDataService } from '../core/data/bitstream-data.service';
17+
import { RemoteData } from '../core/data/remote-data';
18+
import { ServerResponseService } from '../core/services/server-response.service';
19+
import { Bitstream } from '../core/shared/bitstream.model';
20+
import { getFirstCompletedRemoteData } from '../core/shared/operators';
21+
import { hasNoValue } from '../shared/empty.util';
22+
23+
/**
24+
* Redirects to a bitstream based on the handle of the item, and the sequence id or the filename of the
25+
* bitstream. In production mode the status code will also be set the status code to 301 marking it as a permanent URL
26+
* redirect for bots.
27+
*
28+
* @returns Observable<UrlTree> Returns a URL to redirect the user to the new URL format
29+
*/
30+
export const legacyBitstreamURLRedirectGuard: CanActivateFn = (
31+
route: ActivatedRouteSnapshot,
32+
state: RouterStateSnapshot,
33+
bitstreamDataService: BitstreamDataService = inject(BitstreamDataService),
34+
serverResponseService: ServerResponseService = inject(ServerResponseService),
35+
router: Router = inject(Router),
36+
): Observable<UrlTree> => {
37+
const prefix = route.params.prefix;
38+
const suffix = route.params.suffix;
39+
const filename = route.params.filename;
40+
let sequenceId = route.params.sequence_id;
41+
if (hasNoValue(sequenceId)) {
42+
sequenceId = route.queryParams.sequenceId;
43+
}
44+
return bitstreamDataService.findByItemHandle(
45+
`${prefix}/${suffix}`,
46+
sequenceId,
47+
filename,
48+
).pipe(
49+
getFirstCompletedRemoteData(),
50+
tap((rd: RemoteData<Bitstream>) => {
51+
if (rd.hasSucceeded && !rd.hasNoContent) {
52+
serverResponseService.setStatus(301);
53+
}
54+
}),
55+
map((rd: RemoteData<Bitstream>) => {
56+
if (rd.hasSucceeded && !rd.hasNoContent) {
57+
return router.parseUrl(`/bitstreams/${rd.payload.uuid}/download`);
58+
} else {
59+
return router.createUrlTree([PAGE_NOT_FOUND_PATH]);
60+
}
61+
}),
62+
);
63+
};

src/app/bitstream-page/legacy-bitstream-url.resolver.spec.ts

Lines changed: 0 additions & 146 deletions
This file was deleted.

0 commit comments

Comments
 (0)