Skip to content

Commit d92aeb6

Browse files
authored
Merge pull request #4251 from atmire/fix-embargoed-thumbnails_contribute-8.1
[Port dspace-8_x] Show restricted thumbnails to users with access rights
2 parents 6148a66 + 484befa commit d92aeb6

File tree

5 files changed

+70
-38
lines changed

5 files changed

+70
-38
lines changed

src/app/item-page/media-viewer/media-viewer.component.html

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,7 @@
1616
</ng-container>
1717
</div>
1818
<ng-template #showThumbnail>
19-
<ds-media-viewer-image *ngIf="mediaOptions.image && mediaOptions.video"
20-
[image]="(thumbnailsRD$ | async)?.payload?.page[0]?._links.content.href || thumbnailPlaceholder"
21-
[preview]="false"
22-
></ds-media-viewer-image>
23-
<ds-thumbnail *ngIf="!(mediaOptions.image && mediaOptions.video)"
24-
[thumbnail]="(thumbnailsRD$ | async)?.payload?.page[0]">
19+
<ds-thumbnail [thumbnail]="(thumbnailsRD$ | async)?.payload?.page[0]">
2520
</ds-thumbnail>
2621
</ng-template>
2722
</ng-container>

src/app/item-page/media-viewer/media-viewer.component.spec.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { NO_ERRORS_SCHEMA } from '@angular/core';
1+
import {
2+
NO_ERRORS_SCHEMA,
3+
PLATFORM_ID,
4+
} from '@angular/core';
25
import {
36
ComponentFixture,
47
TestBed,
@@ -14,7 +17,9 @@ import { of as observableOf } from 'rxjs';
1417

1518
import { AuthService } from '../../core/auth/auth.service';
1619
import { BitstreamDataService } from '../../core/data/bitstream-data.service';
20+
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
1721
import { Bitstream } from '../../core/shared/bitstream.model';
22+
import { FileService } from '../../core/shared/file.service';
1823
import { MediaViewerItem } from '../../core/shared/media-viewer-item.model';
1924
import { MetadataFieldWrapperComponent } from '../../shared/metadata-field-wrapper/metadata-field-wrapper.component';
2025
import { AuthServiceMock } from '../../shared/mocks/auth.service.mock';
@@ -31,6 +36,9 @@ import { MediaViewerComponent } from './media-viewer.component';
3136
describe('MediaViewerComponent', () => {
3237
let comp: MediaViewerComponent;
3338
let fixture: ComponentFixture<MediaViewerComponent>;
39+
let authService;
40+
let authorizationService;
41+
let fileService;
3442

3543
const mockBitstream: Bitstream = Object.assign(new Bitstream(), {
3644
sizeBytes: 10201,
@@ -55,7 +63,7 @@ describe('MediaViewerComponent', () => {
5563
'dc.title': [
5664
{
5765
language: null,
58-
value: 'test_word.docx',
66+
value: 'test_image.jpg',
5967
},
6068
],
6169
},
@@ -73,6 +81,15 @@ describe('MediaViewerComponent', () => {
7381
);
7482

7583
beforeEach(waitForAsync(() => {
84+
authService = jasmine.createSpyObj('AuthService', {
85+
isAuthenticated: observableOf(true),
86+
});
87+
authorizationService = jasmine.createSpyObj('AuthorizationService', {
88+
isAuthorized: observableOf(true),
89+
});
90+
fileService = jasmine.createSpyObj('FileService', {
91+
retrieveFileDownloadLink: null,
92+
});
7693
return TestBed.configureTestingModule({
7794
imports: [
7895
TranslateModule.forRoot({
@@ -88,6 +105,10 @@ describe('MediaViewerComponent', () => {
88105
MetadataFieldWrapperComponent,
89106
],
90107
providers: [
108+
{ provide: AuthService, useValue: authService },
109+
{ provide: AuthorizationDataService, useValue: authorizationService },
110+
{ provide: FileService, useValue: fileService },
111+
{ provide: PLATFORM_ID, useValue: 'browser' },
91112
{ provide: BitstreamDataService, useValue: bitstreamDataService },
92113
{ provide: ThemeService, useValue: getMockThemeService() },
93114
{ provide: AuthService, useValue: new AuthServiceMock() },
@@ -150,9 +171,9 @@ describe('MediaViewerComponent', () => {
150171
expect(mediaItem.thumbnail).toBe(null);
151172
});
152173

153-
it('should display a default, thumbnail', () => {
174+
it('should display a default thumbnail', () => {
154175
const defaultThumbnail = fixture.debugElement.query(
155-
By.css('ds-media-viewer-image'),
176+
By.css('ds-thumbnail'),
156177
);
157178
expect(defaultThumbnail.nativeElement).toBeDefined();
158179
});

src/app/thumbnail/thumbnail.component.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
<div class="thumbnail" [class.limit-width]="limitWidth">
2-
<div *ngIf="isLoading" class="thumbnail-content outer">
2+
<div *ngIf="(isLoading$ | async)" class="thumbnail-content outer">
33
<div class="inner">
44
<div class="centered">
55
<ds-loading [spinner]="true"></ds-loading>
66
</div>
77
</div>
88
</div>
9-
<!-- don't use *ngIf="!isLoading" so the thumbnail can load in while the animation is playing -->
10-
<img *ngIf="src !== null" class="thumbnail-content img-fluid" [ngClass]="{'d-none': isLoading}"
11-
[src]="src | dsSafeUrl" [alt]="alt | translate" (error)="errorHandler()" (load)="successHandler()">
12-
<div *ngIf="src === null && !isLoading" class="thumbnail-content outer">
9+
<!-- don't use *ngIf="!(isLoading$ | async)" so the thumbnail can load in while the animation is playing -->
10+
<img *ngIf="(src$ | async) !== null" class="thumbnail-content img-fluid" [ngClass]="{'d-none': (isLoading$ | async)}"
11+
[src]="(src$ | async) | dsSafeUrl" [alt]="alt | translate" (error)="errorHandler()" (load)="successHandler()">
12+
<div *ngIf="(src$ | async) === null && (isLoading$ | async) === false" class="thumbnail-content outer">
1313
<div class="inner">
1414
<div class="thumbnail-placeholder centered lead">
1515
{{ placeholder | translate }}

src/app/thumbnail/thumbnail.component.spec.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -100,31 +100,31 @@ describe('ThumbnailComponent', () => {
100100

101101
describe('loading', () => {
102102
it('should start out with isLoading$ true', () => {
103-
expect(comp.isLoading).toBeTrue();
103+
expect(comp.isLoading$.getValue()).toBeTrue();
104104
});
105105

106106
it('should set isLoading$ to false once an image is successfully loaded', () => {
107107
comp.setSrc('http://bit.stream');
108108
fixture.debugElement.query(By.css('img.thumbnail-content')).triggerEventHandler('load', new Event('load'));
109-
expect(comp.isLoading).toBeFalse();
109+
expect(comp.isLoading$.getValue()).toBeFalse();
110110
});
111111

112112
it('should set isLoading$ to false once the src is set to null', () => {
113113
comp.setSrc(null);
114-
expect(comp.isLoading).toBeFalse();
114+
expect(comp.isLoading$.getValue()).toBeFalse();
115115
});
116116

117117
it('should show a loading animation while isLoading$ is true', () => {
118118
expect(de.query(By.css('ds-loading'))).toBeTruthy();
119119

120-
comp.isLoading = false;
120+
comp.isLoading$.next(false);
121121
fixture.detectChanges();
122122
expect(fixture.debugElement.query(By.css('ds-loading'))).toBeFalsy();
123123
});
124124

125125
describe('with a thumbnail image', () => {
126126
beforeEach(() => {
127-
comp.src = 'https://bit.stream';
127+
comp.src$.next('https://bit.stream');
128128
fixture.detectChanges();
129129
});
130130

@@ -133,7 +133,7 @@ describe('ThumbnailComponent', () => {
133133
expect(img).toBeTruthy();
134134
expect(img.classes['d-none']).toBeTrue();
135135

136-
comp.isLoading = false;
136+
comp.isLoading$.next(false);
137137
fixture.detectChanges();
138138
img = fixture.debugElement.query(By.css('img.thumbnail-content'));
139139
expect(img).toBeTruthy();
@@ -144,14 +144,14 @@ describe('ThumbnailComponent', () => {
144144

145145
describe('without a thumbnail image', () => {
146146
beforeEach(() => {
147-
comp.src = null;
147+
comp.src$.next(null);
148148
fixture.detectChanges();
149149
});
150150

151151
it('should only show the HTML placeholder once done loading', () => {
152152
expect(fixture.debugElement.query(By.css('div.thumbnail-placeholder'))).toBeFalsy();
153153

154-
comp.isLoading = false;
154+
comp.isLoading$.next(false);
155155
fixture.detectChanges();
156156
expect(fixture.debugElement.query(By.css('div.thumbnail-placeholder'))).toBeTruthy();
157157
});
@@ -247,14 +247,14 @@ describe('ThumbnailComponent', () => {
247247
describe('fallback', () => {
248248
describe('if there is a default image', () => {
249249
it('should display the default image', () => {
250-
comp.src = 'http://bit.stream';
250+
comp.src$.next('http://bit.stream');
251251
comp.defaultImage = 'http://default.img';
252252
comp.errorHandler();
253-
expect(comp.src).toBe(comp.defaultImage);
253+
expect(comp.src$.getValue()).toBe(comp.defaultImage);
254254
});
255255

256256
it('should include the alt text', () => {
257-
comp.src = 'http://bit.stream';
257+
comp.src$.next('http://bit.stream');
258258
comp.defaultImage = 'http://default.img';
259259
comp.errorHandler();
260260

@@ -266,10 +266,10 @@ describe('ThumbnailComponent', () => {
266266

267267
describe('if there is no default image', () => {
268268
it('should display the HTML placeholder', () => {
269-
comp.src = 'http://default.img';
269+
comp.src$.next('http://default.img');
270270
comp.defaultImage = null;
271271
comp.errorHandler();
272-
expect(comp.src).toBe(null);
272+
expect(comp.src$.getValue()).toBe(null);
273273

274274
fixture.detectChanges();
275275
const placeholder = fixture.debugElement.query(By.css('div.thumbnail-placeholder')).nativeElement;
@@ -361,7 +361,7 @@ describe('ThumbnailComponent', () => {
361361
it('should show the default image', () => {
362362
comp.defaultImage = 'default/image.jpg';
363363
comp.ngOnChanges({});
364-
expect(comp.src).toBe('default/image.jpg');
364+
expect(comp.src$.getValue()).toBe('default/image.jpg');
365365
});
366366
});
367367
});
@@ -417,7 +417,7 @@ describe('ThumbnailComponent', () => {
417417
});
418418

419419
it('should start out with isLoading$ true', () => {
420-
expect(comp.isLoading).toBeTrue();
420+
expect(comp.isLoading$.getValue()).toBeTrue();
421421
expect(de.query(By.css('ds-loading'))).toBeTruthy();
422422
});
423423

src/app/thumbnail/thumbnail.component.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ import {
1111
SimpleChanges,
1212
} from '@angular/core';
1313
import { TranslateModule } from '@ngx-translate/core';
14-
import { of as observableOf } from 'rxjs';
14+
import {
15+
BehaviorSubject,
16+
of as observableOf,
17+
} from 'rxjs';
1518
import { switchMap } from 'rxjs/operators';
1619

1720
import { AuthService } from '../core/auth/auth.service';
@@ -55,7 +58,7 @@ export class ThumbnailComponent implements OnChanges {
5558
/**
5659
* The src attribute used in the template to render the image.
5760
*/
58-
src: string = undefined;
61+
src$: BehaviorSubject<string> = new BehaviorSubject<string>(undefined);
5962

6063
retriedWithToken = false;
6164

@@ -78,7 +81,7 @@ export class ThumbnailComponent implements OnChanges {
7881
* Whether the thumbnail is currently loading
7982
* Start out as true to avoid flashing the alt text while a thumbnail is being loaded.
8083
*/
81-
isLoading = true;
84+
isLoading$: BehaviorSubject<boolean> = new BehaviorSubject(true);
8285

8386
constructor(
8487
@Inject(PLATFORM_ID) private platformID: any,
@@ -134,7 +137,7 @@ export class ThumbnailComponent implements OnChanges {
134137
* Otherwise, fall back to the default image or a HTML placeholder
135138
*/
136139
errorHandler() {
137-
const src = this.src;
140+
const src = this.src$.getValue();
138141
const thumbnail = this.bitstream;
139142
const thumbnailSrc = thumbnail?._links?.content?.href;
140143

@@ -186,16 +189,29 @@ export class ThumbnailComponent implements OnChanges {
186189
* @param src
187190
*/
188191
setSrc(src: string): void {
189-
this.src = src;
190-
if (src === null) {
191-
this.isLoading = false;
192+
// only update the src if it has changed (the parent component may fire the same one multiple times
193+
if (this.src$.getValue() !== src) {
194+
// every time the src changes we need to start the loading animation again, as it's possible
195+
// that it is first set to null when the parent component initializes and then set to
196+
// the actual value
197+
//
198+
// isLoading$ will be set to false by the error or success handler afterwards, except in the
199+
// case where src is null, then we have to set it manually here (because those handlers won't
200+
// trigger)
201+
if (src !== null && this.isLoading$.getValue() === false) {
202+
this.isLoading$.next(true);
203+
}
204+
this.src$.next(src);
205+
if (src === null && this.isLoading$.getValue() === true) {
206+
this.isLoading$.next(false);
207+
}
192208
}
193209
}
194210

195211
/**
196212
* Stop the loading animation once the thumbnail is successfully loaded
197213
*/
198214
successHandler() {
199-
this.isLoading = false;
215+
this.isLoading$.next(false);
200216
}
201217
}

0 commit comments

Comments
 (0)