mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 18:14:17 +00:00
76150: Implement feedback
This commit is contained in:
@@ -1,10 +1,11 @@
|
|||||||
import { Inject, Injectable } from '@angular/core';
|
import { Inject, Injectable } from '@angular/core';
|
||||||
import { RawRestResponse } from '../dspace-rest/raw-rest-response.model';
|
import { RawRestResponse } from '../dspace-rest/raw-rest-response.model';
|
||||||
import { AuthService } from '../auth/auth.service';
|
import { AuthService } from '../auth/auth.service';
|
||||||
import { take } from 'rxjs/operators';
|
import { map, take } from 'rxjs/operators';
|
||||||
import { NativeWindowRef, NativeWindowService } from '../services/window.service';
|
import { NativeWindowRef, NativeWindowService } from '../services/window.service';
|
||||||
import { URLCombiner } from '../url-combiner/url-combiner';
|
import { URLCombiner } from '../url-combiner/url-combiner';
|
||||||
import { hasValue } from '../../shared/empty.util';
|
import { hasValue } from '../../shared/empty.util';
|
||||||
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides utility methods to save files on the client-side.
|
* Provides utility methods to save files on the client-side.
|
||||||
@@ -17,17 +18,16 @@ export class FileService {
|
|||||||
) { }
|
) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combines an URL with a short-lived token and sets the current URL to the newly created one
|
* Combines an URL with a short-lived token and sets the current URL to the newly created one and returns it
|
||||||
*
|
*
|
||||||
* @param url
|
* @param url
|
||||||
* file url
|
* file url
|
||||||
*/
|
*/
|
||||||
downloadFile(url: string) {
|
retrieveFileDownloadLink(url: string): Observable<string> {
|
||||||
this.authService.getShortlivedToken().pipe(take(1)).subscribe((token) => {
|
return this.authService.getShortlivedToken().pipe(take(1), map((token) =>
|
||||||
this._window.nativeWindow.location.href = hasValue(token) ? new URLCombiner(url, `?authentication-token=${token}`).toString() : url;
|
hasValue(token) ? new URLCombiner(url, `?authentication-token=${token}`).toString() : url
|
||||||
});
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derives file name from the http response
|
* Derives file name from the http response
|
||||||
* by looking inside content-disposition
|
* by looking inside content-disposition
|
||||||
|
@@ -35,7 +35,7 @@ describe('BitstreamDownloadPageComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
fileService = jasmine.createSpyObj('fileService', {
|
fileService = jasmine.createSpyObj('fileService', {
|
||||||
downloadFile: observableOf('content-url-with-headers')
|
retrieveFileDownloadLink: observableOf('content-url-with-headers')
|
||||||
});
|
});
|
||||||
|
|
||||||
hardRedirectService = jasmine.createSpyObj('fileService', {
|
hardRedirectService = jasmine.createSpyObj('fileService', {
|
||||||
|
@@ -1,19 +1,17 @@
|
|||||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { map } from 'rxjs/operators';
|
import { filter, map, switchMap, take } from 'rxjs/operators';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { Subscription } from 'rxjs/internal/Subscription';
|
|
||||||
import { hasValue, isNotEmpty } from '../empty.util';
|
import { hasValue, isNotEmpty } from '../empty.util';
|
||||||
import { getRemoteDataPayload, redirectOn4xx } from '../../core/shared/operators';
|
import { getRemoteDataPayload, redirectOn4xx } from '../../core/shared/operators';
|
||||||
import { Bitstream } from '../../core/shared/bitstream.model';
|
import { Bitstream } from '../../core/shared/bitstream.model';
|
||||||
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
|
||||||
import { AuthService } from '../../core/auth/auth.service';
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
|
import { combineLatest as observableCombineLatest, Observable, of as observableOf } from 'rxjs';
|
||||||
import { FileService } from '../../core/shared/file.service';
|
import { FileService } from '../../core/shared/file.service';
|
||||||
import { HardRedirectService } from '../../core/services/hard-redirect.service';
|
import { HardRedirectService } from '../../core/services/hard-redirect.service';
|
||||||
import { getForbiddenRoute } from '../../app-routing-paths';
|
import { getForbiddenRoute } from '../../app-routing-paths';
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
import { tap } from 'rxjs/internal/operators/tap';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-bitstream-download-page',
|
selector: 'ds-bitstream-download-page',
|
||||||
@@ -22,12 +20,11 @@ import { tap } from 'rxjs/internal/operators/tap';
|
|||||||
/**
|
/**
|
||||||
* Page component for downloading a bitstream
|
* Page component for downloading a bitstream
|
||||||
*/
|
*/
|
||||||
export class BitstreamDownloadPageComponent implements OnInit, OnDestroy {
|
export class BitstreamDownloadPageComponent implements OnInit {
|
||||||
|
|
||||||
bitstream$: Observable<Bitstream>;
|
bitstream$: Observable<Bitstream>;
|
||||||
bitstreamRD$: Observable<RemoteData<Bitstream>>;
|
bitstreamRD$: Observable<RemoteData<Bitstream>>;
|
||||||
|
|
||||||
subs: Subscription[] = [];
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
@@ -46,38 +43,42 @@ export class BitstreamDownloadPageComponent implements OnInit, OnDestroy {
|
|||||||
map((data) => data.bitstream));
|
map((data) => data.bitstream));
|
||||||
|
|
||||||
this.bitstream$ = this.bitstreamRD$.pipe(
|
this.bitstream$ = this.bitstreamRD$.pipe(
|
||||||
tap((v) => console.log('dfdf', v)),
|
|
||||||
redirectOn4xx(this.router, this.auth),
|
redirectOn4xx(this.router, this.auth),
|
||||||
getRemoteDataPayload()
|
getRemoteDataPayload()
|
||||||
);
|
);
|
||||||
|
|
||||||
this.subs.push(this.bitstream$.subscribe((bitstream) => {
|
this.bitstream$.pipe(
|
||||||
const isAuthorized$ = this.authorizationService.isAuthorized(FeatureID.CanDownload, isNotEmpty(bitstream) ? bitstream.self : undefined);
|
switchMap((bitstream: Bitstream) => {
|
||||||
const isLoggedIn$ = this.auth.isAuthenticated();
|
const isAuthorized$ = this.authorizationService.isAuthorized(FeatureID.CanDownload, isNotEmpty(bitstream) ? bitstream.self : undefined);
|
||||||
|
const isLoggedIn$ = this.auth.isAuthenticated();
|
||||||
this.subs.push(observableCombineLatest(isAuthorized$, isLoggedIn$)
|
return observableCombineLatest([isAuthorized$, isLoggedIn$, observableOf(bitstream)]);
|
||||||
.subscribe(([isAuthorized, isLoggedIn]) => {
|
}),
|
||||||
if (isAuthorized && isLoggedIn) {
|
filter(([isAuthorized, isLoggedIn, bitstream]: [boolean, boolean, Bitstream]) => hasValue(isAuthorized) && hasValue(isLoggedIn)),
|
||||||
const fileLink$ = this.fileService.downloadFile(bitstream._links.content.href);
|
take(1),
|
||||||
this.subs.push(fileLink$.subscribe((fileLink) => {
|
switchMap(([isAuthorized, isLoggedIn, bitstream]: [boolean, boolean, Bitstream]) => {
|
||||||
this.hardRedirectService.redirect(fileLink);
|
if (isAuthorized && isLoggedIn) {
|
||||||
|
return this.fileService.retrieveFileDownloadLink(bitstream._links.content.href).pipe(
|
||||||
|
filter((fileLink) => hasValue(fileLink)),
|
||||||
|
take(1),
|
||||||
|
map((fileLink) => {
|
||||||
|
return [isAuthorized, isLoggedIn, bitstream, fileLink];
|
||||||
|
// return [isAuthorized, isLoggedIn, bitstream];
|
||||||
}));
|
}));
|
||||||
} else if (isAuthorized && !isLoggedIn) {
|
} else {
|
||||||
this.hardRedirectService.redirect(bitstream._links.content.href);
|
return [[isAuthorized, isLoggedIn, bitstream, '']];
|
||||||
} else if (!isAuthorized && isLoggedIn) {
|
}
|
||||||
this.router.navigateByUrl(getForbiddenRoute(), {skipLocationChange: true});
|
})
|
||||||
} else if (!isAuthorized && !isLoggedIn) {
|
).subscribe(([isAuthorized, isLoggedIn, bitstream, fileLink]: [boolean, boolean, Bitstream, string]) => {
|
||||||
this.auth.setRedirectUrl(this.router.url);
|
if (isAuthorized && isLoggedIn && isNotEmpty(fileLink)) {
|
||||||
this.router.navigateByUrl('login');
|
this.hardRedirectService.redirect(fileLink);
|
||||||
}
|
} else if (isAuthorized && !isLoggedIn) {
|
||||||
}));
|
this.hardRedirectService.redirect(bitstream._links.content.href);
|
||||||
}));
|
} else if (!isAuthorized && isLoggedIn) {
|
||||||
|
this.router.navigateByUrl(getForbiddenRoute(), {skipLocationChange: true});
|
||||||
}
|
} else if (!isAuthorized && !isLoggedIn) {
|
||||||
|
this.auth.setRedirectUrl(this.router.url);
|
||||||
ngOnDestroy(): void {
|
this.router.navigateByUrl('login');
|
||||||
this.subs
|
}
|
||||||
.filter((subscription) => hasValue(subscription))
|
});
|
||||||
.forEach((subscription) => subscription.unsubscribe());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -82,7 +82,7 @@ export class ItemDetailPreviewComponent {
|
|||||||
first())
|
first())
|
||||||
.subscribe((url) => {
|
.subscribe((url) => {
|
||||||
const fileUrl = `${url}/${uuid}/content`;
|
const fileUrl = `${url}/${uuid}/content`;
|
||||||
this.fileService.downloadFile(fileUrl);
|
this.fileService.retrieveFileDownloadLink(fileUrl);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -41,7 +41,7 @@ import { FormBuilderService } from '../../../../shared/form/builder/form-builder
|
|||||||
|
|
||||||
function getMockFileService(): FileService {
|
function getMockFileService(): FileService {
|
||||||
return jasmine.createSpyObj('FileService', {
|
return jasmine.createSpyObj('FileService', {
|
||||||
downloadFile: jasmine.createSpy('downloadFile'),
|
retrieveFileDownloadLink: jasmine.createSpy('retrieveFileDownloadLink'),
|
||||||
getFileNameFromResponseContentDisposition: jasmine.createSpy('getFileNameFromResponseContentDisposition')
|
getFileNameFromResponseContentDisposition: jasmine.createSpy('getFileNameFromResponseContentDisposition')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -232,7 +232,7 @@ describe('SubmissionSectionUploadFileComponent test suite', () => {
|
|||||||
|
|
||||||
tick();
|
tick();
|
||||||
|
|
||||||
expect(fileService.downloadFile).toHaveBeenCalled();
|
expect(fileService.retrieveFileDownloadLink).toHaveBeenCalled();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should save Bitstream File data properly when form is valid', fakeAsync(() => {
|
it('should save Bitstream File data properly when form is valid', fakeAsync(() => {
|
||||||
|
@@ -224,7 +224,7 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit {
|
|||||||
first())
|
first())
|
||||||
.subscribe((url) => {
|
.subscribe((url) => {
|
||||||
const fileUrl = `${url}/${this.fileData.uuid}/content`;
|
const fileUrl = `${url}/${this.fileData.uuid}/content`;
|
||||||
this.fileService.downloadFile(fileUrl);
|
this.fileService.retrieveFileDownloadLink(fileUrl);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user