Skip to content

Commit

Permalink
Merge pull request #3887 from tdonohue/port_3694_to_8x
Browse files Browse the repository at this point in the history
[Port dspace-8_x] Prevent request with page size of 9999 (#3694)
  • Loading branch information
tdonohue authored Jan 23, 2025
2 parents 204062c + ff304f3 commit 2d7c0cc
Show file tree
Hide file tree
Showing 25 changed files with 640 additions and 296 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<ng-container *ngVar="(bitstreamRD$ | async) as bitstreamRD">
<div class="container" *ngVar="(bitstreamFormatsRD$ | async) as formatsRD">
<div class="row" *ngIf="bitstreamRD?.hasSucceeded && formatsRD?.hasSucceeded">
<div class="container">
<div class="row" *ngIf="bitstreamRD?.hasSucceeded">
<div class="col-md-2">
<ds-thumbnail [thumbnail]="bitstreamRD?.payload"></ds-thumbnail>
</div>
Expand All @@ -27,7 +27,7 @@ <h1 class="h2">{{dsoNameService.getName(bitstreamRD?.payload)}} <span class="tex
</div>
</div>
<ds-error *ngIf="bitstreamRD?.hasFailed" message="{{'error.bitstream' | translate}}"></ds-error>
<ds-loading *ngIf="!bitstreamRD || !formatsRD || bitstreamRD?.isLoading || formatsRD?.isLoading"
<ds-loading *ngIf="!bitstreamRD || bitstreamRD?.isLoading"
message="{{'loading.bitstream' | translate}}"></ds-loading>
</div>
</ng-container>
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ describe('EditBitstreamPageComponent', () => {
});

it('should select the correct format', () => {
expect(rawForm.formatContainer.selectedFormat).toEqual(selectedFormat.id);
expect(rawForm.formatContainer.selectedFormat).toEqual(selectedFormat.shortDescription);
});

it('should put the \"New Format\" input on invisible', () => {
Expand Down Expand Up @@ -292,7 +292,13 @@ describe('EditBitstreamPageComponent', () => {

describe('when an unknown format is selected', () => {
beforeEach(() => {
comp.updateNewFormatLayout(allFormats[0].id);
comp.onChange({
model: {
id: 'selectedFormat',
value: allFormats[0],
},
});
comp.updateNewFormatLayout();
});

it('should remove the invisible class from the \"New Format\" input', () => {
Expand Down Expand Up @@ -394,9 +400,10 @@ describe('EditBitstreamPageComponent', () => {

describe('when selected format has changed', () => {
beforeEach(() => {
comp.formGroup.patchValue({
formatContainer: {
selectedFormat: allFormats[2].id,
comp.onChange({
model: {
id: 'selectedFormat',
value: allFormats[2],
},
});
fixture.detectChanges();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import {
DynamicFormLayout,
DynamicFormService,
DynamicInputModel,
DynamicSelectModel,
} from '@ng-dynamic-forms/core';
import {
TranslateModule,
Expand All @@ -39,23 +38,24 @@ import {
filter,
map,
switchMap,
take,
tap,
} from 'rxjs/operators';

import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { FindAllDataImpl } from '../../core/data/base/find-all-data';
import { BitstreamDataService } from '../../core/data/bitstream-data.service';
import { BitstreamFormatDataService } from '../../core/data/bitstream-format-data.service';
import { PaginatedList } from '../../core/data/paginated-list.model';
import { PrimaryBitstreamService } from '../../core/data/primary-bitstream.service';
import { RemoteData } from '../../core/data/remote-data';
import { Bitstream } from '../../core/shared/bitstream.model';
import { BitstreamFormat } from '../../core/shared/bitstream-format.model';
import { BITSTREAM_FORMAT } from '../../core/shared/bitstream-format.resource-type';
import { BitstreamFormatSupportLevel } from '../../core/shared/bitstream-format-support-level';
import { Bundle } from '../../core/shared/bundle.model';
import { Item } from '../../core/shared/item.model';
import { Metadata } from '../../core/shared/metadata.utils';
import {
getAllSucceededRemoteDataPayload,
getFirstCompletedRemoteData,
getFirstSucceededRemoteData,
getFirstSucceededRemoteDataPayload,
Expand All @@ -72,6 +72,7 @@ import { ErrorComponent } from '../../shared/error/error.component';
import { DynamicCustomSwitchModel } from '../../shared/form/builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.model';
import { DsDynamicInputModel } from '../../shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-input.model';
import { DsDynamicTextAreaModel } from '../../shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-textarea.model';
import { DynamicScrollableDropdownModel } from '../../shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.model';
import { FormComponent } from '../../shared/form/form.component';
import { ThemedLoadingComponent } from '../../shared/loading/themed-loading.component';
import { NotificationsService } from '../../shared/notifications/notifications.service';
Expand Down Expand Up @@ -109,12 +110,6 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
*/
bitstreamRD$: Observable<RemoteData<Bitstream>>;

/**
* The formats their remote data observable
* Tracks changes and updates the view
*/
bitstreamFormatsRD$: Observable<RemoteData<PaginatedList<BitstreamFormat>>>;

/**
* The UUID of the primary bitstream for this bundle
*/
Expand All @@ -130,11 +125,6 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
*/
originalFormat: BitstreamFormat;

/**
* A list of all available bitstream formats
*/
formats: BitstreamFormat[];

/**
* @type {string} Key prefix used to generate form messages
*/
Expand Down Expand Up @@ -178,7 +168,10 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
/**
* Options for fetching all bitstream formats
*/
findAllOptions = { elementsPerPage: 9999 };
findAllOptions = {
elementsPerPage: 20,
currentPage: 1,
};

/**
* The Dynamic Input Model for the file's name
Expand Down Expand Up @@ -218,9 +211,22 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
/**
* The Dynamic Input Model for the selected format
*/
selectedFormatModel = new DynamicSelectModel({
selectedFormatModel = new DynamicScrollableDropdownModel({
id: 'selectedFormat',
name: 'selectedFormat',
displayKey: 'shortDescription',
repeatable: false,
metadataFields: [],
submissionId: '',
hasSelectableMetadata: false,
resourceType: BITSTREAM_FORMAT,
formatFunction: (format: BitstreamFormat | string) => {
if (format instanceof BitstreamFormat) {
return hasValue(format) && format.supportLevel === BitstreamFormatSupportLevel.Unknown ? this.translate.instant(this.KEY_PREFIX + 'selectedFormat.unknown') : format.shortDescription;
} else {
return format;
}
},
});

/**
Expand Down Expand Up @@ -438,6 +444,11 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
* @private
*/
private bundle: Bundle;
/**
* The currently selected format
* @private
*/
private selectedFormat: BitstreamFormat;

constructor(private route: ActivatedRoute,
private router: Router,
Expand All @@ -463,18 +474,12 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
this.itemId = this.route.snapshot.queryParams.itemId;
this.entityType = this.route.snapshot.queryParams.entityType;
this.bitstreamRD$ = this.route.data.pipe(map((data: any) => data.bitstream));
this.bitstreamFormatsRD$ = this.bitstreamFormatService.findAll(this.findAllOptions);

const bitstream$ = this.bitstreamRD$.pipe(
getFirstSucceededRemoteData(),
getRemoteDataPayload(),
);

const allFormats$ = this.bitstreamFormatsRD$.pipe(
getFirstSucceededRemoteData(),
getRemoteDataPayload(),
);

const bundle$ = bitstream$.pipe(
switchMap((bitstream: Bitstream) => bitstream.bundle),
getFirstSucceededRemoteDataPayload(),
Expand All @@ -490,24 +495,31 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
switchMap((bundle: Bundle) => bundle.item),
getFirstSucceededRemoteDataPayload(),
);
const format$ = bitstream$.pipe(
switchMap(bitstream => bitstream.format),
getFirstSucceededRemoteDataPayload(),
);

this.subs.push(
observableCombineLatest(
bitstream$,
allFormats$,
bundle$,
primaryBitstream$,
item$,
).pipe()
.subscribe(([bitstream, allFormats, bundle, primaryBitstream, item]) => {
this.bitstream = bitstream as Bitstream;
this.formats = allFormats.page;
this.bundle = bundle;
// hasValue(primaryBitstream) because if there's no primaryBitstream on the bundle it will
// be a success response, but empty
this.primaryBitstreamUUID = hasValue(primaryBitstream) ? primaryBitstream.uuid : null;
this.itemId = item.uuid;
this.setIiifStatus(this.bitstream);
}),
format$,
).subscribe(([bitstream, bundle, primaryBitstream, item, format]) => {
this.bitstream = bitstream as Bitstream;
this.bundle = bundle;
this.selectedFormat = format;
// hasValue(primaryBitstream) because if there's no primaryBitstream on the bundle it will
// be a success response, but empty
this.primaryBitstreamUUID = hasValue(primaryBitstream) ? primaryBitstream.uuid : null;
this.itemId = item.uuid;
this.setIiifStatus(this.bitstream);
}),
format$.pipe(take(1)).subscribe(
(format) => this.originalFormat = format,
),
);

this.subs.push(
Expand All @@ -523,7 +535,6 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
*/
setForm() {
this.formGroup = this.formService.createFormGroup(this.formModel);
this.updateFormatModel();
this.updateForm(this.bitstream);
this.updateFieldTranslations();
}
Expand All @@ -542,6 +553,7 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
description: bitstream.firstMetadataValue('dc.description'),
},
formatContainer: {
selectedFormat: this.selectedFormat.shortDescription,
newFormat: hasValue(bitstream.firstMetadata('dc.format')) ? bitstream.firstMetadata('dc.format').value : undefined,
},
});
Expand All @@ -561,36 +573,16 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
},
});
}
this.bitstream.format.pipe(
getAllSucceededRemoteDataPayload(),
).subscribe((format: BitstreamFormat) => {
this.originalFormat = format;
this.formGroup.patchValue({
formatContainer: {
selectedFormat: format.id,
},
});
this.updateNewFormatLayout(format.id);
});
this.updateNewFormatLayout();
}

/**
* Create the list of unknown format IDs an add options to the selectedFormatModel
*/
updateFormatModel() {
this.selectedFormatModel.options = this.formats.map((format: BitstreamFormat) =>
Object.assign({
value: format.id,
label: this.isUnknownFormat(format.id) ? this.translate.instant(this.KEY_PREFIX + 'selectedFormat.unknown') : format.shortDescription,
}));
}

/**
* Update the layout of the "Other Format" input depending on the selected format
* @param selectedId
*/
updateNewFormatLayout(selectedId: string) {
if (this.isUnknownFormat(selectedId)) {
updateNewFormatLayout() {
if (this.isUnknownFormat()) {
this.formLayout.newFormat.grid.host = this.newFormatBaseLayout;
} else {
this.formLayout.newFormat.grid.host = this.newFormatBaseLayout + ' invisible';
Expand All @@ -601,9 +593,8 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
* Is the provided format (id) part of the list of unknown formats?
* @param id
*/
isUnknownFormat(id: string): boolean {
const format = this.formats.find((f: BitstreamFormat) => f.id === id);
return hasValue(format) && format.supportLevel === BitstreamFormatSupportLevel.Unknown;
isUnknownFormat(): boolean {
return hasValue(this.selectedFormat) && this.selectedFormat.supportLevel === BitstreamFormatSupportLevel.Unknown;
}

/**
Expand Down Expand Up @@ -635,7 +626,8 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
onChange(event) {
const model = event.model;
if (model.id === this.selectedFormatModel.id) {
this.updateNewFormatLayout(model.value);
this.selectedFormat = model.value;
this.updateNewFormatLayout();
}
}

Expand All @@ -645,8 +637,7 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
onSubmit() {
const updatedValues = this.formGroup.getRawValue();
const updatedBitstream = this.formToBitstream(updatedValues);
const selectedFormat = this.formats.find((f: BitstreamFormat) => f.id === updatedValues.formatContainer.selectedFormat);
const isNewFormat = selectedFormat.id !== this.originalFormat.id;
const isNewFormat = this.selectedFormat.id !== this.originalFormat.id;
const isPrimary = updatedValues.fileNamePrimaryContainer.primaryBitstream;
const wasPrimary = this.primaryBitstreamUUID === this.bitstream.uuid;

Expand Down Expand Up @@ -698,7 +689,7 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
bundle$ = observableOf(this.bundle);
}
if (isNewFormat) {
bitstream$ = this.bitstreamService.updateFormat(this.bitstream, selectedFormat).pipe(
bitstream$ = this.bitstreamService.updateFormat(this.bitstream, this.selectedFormat).pipe(
getFirstCompletedRemoteData(),
map((formatResponse: RemoteData<Bitstream>) => {
if (hasValue(formatResponse) && formatResponse.hasFailed) {
Expand Down Expand Up @@ -856,4 +847,7 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
.forEach((subscription) => subscription.unsubscribe());
}

findAllFormatsServiceFactory() {
return () => this.bitstreamFormatService as any as FindAllDataImpl<BitstreamFormat>;
}
}
5 changes: 3 additions & 2 deletions src/app/core/data/bitstream-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,12 @@ export class BitstreamDataService extends IdentifiableDataService<Bitstream> imp
* no valid cached version. Defaults to true
* @param reRequestOnStale Whether or not the request should automatically be re-
* requested after the response becomes stale
* @param options the {@link FindListOptions} for the request
* @return {Observable<Bitstream | null>}
* Return an observable that constains primary bitstream information or null
*/
public findPrimaryBitstreamByItemAndName(item: Item, bundleName: string, useCachedVersionIfAvailable = true, reRequestOnStale = true): Observable<Bitstream | null> {
return this.bundleService.findByItemAndName(item, bundleName, useCachedVersionIfAvailable, reRequestOnStale, followLink('primaryBitstream')).pipe(
public findPrimaryBitstreamByItemAndName(item: Item, bundleName: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, options?: FindListOptions): Observable<Bitstream | null> {
return this.bundleService.findByItemAndName(item, bundleName, useCachedVersionIfAvailable, reRequestOnStale, options, followLink('primaryBitstream')).pipe(
getFirstCompletedRemoteData(),
switchMap((rd: RemoteData<Bundle>) => {
if (!rd.hasSucceeded) {
Expand Down
8 changes: 6 additions & 2 deletions src/app/core/data/bundle-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,14 @@ export class BundleDataService extends IdentifiableDataService<Bundle> implement
* requested after the response becomes stale
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
* {@link HALLink}s should be automatically resolved
* @param options the {@link FindListOptions} for the request
*/
// TODO should be implemented rest side
findByItemAndName(item: Item, bundleName: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<Bundle>[]): Observable<RemoteData<Bundle>> {
return this.findAllByItem(item, { elementsPerPage: 9999 }, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow).pipe(
findByItemAndName(item: Item, bundleName: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, options?: FindListOptions, ...linksToFollow: FollowLinkConfig<Bundle>[]): Observable<RemoteData<Bundle>> {
//Since we filter by bundleName where the pagination options are not indicated we need to load all the possible bundles.
// This is a workaround, in substitution of the previously recursive call with expand
const paginationOptions = options ?? { elementsPerPage: 9999 };
return this.findAllByItem(item, paginationOptions, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow).pipe(
map((rd: RemoteData<PaginatedList<Bundle>>) => {
if (hasValue(rd.payload) && hasValue(rd.payload.page)) {
const matchingBundle = rd.payload.page.find((bundle: Bundle) =>
Expand Down
2 changes: 2 additions & 0 deletions src/app/core/metadata/head-tag.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import { coreSelector } from '../core.selectors';
import { CoreState } from '../core-state.model';
import { BundleDataService } from '../data/bundle-data.service';
import { AuthorizationDataService } from '../data/feature-authorization/authorization-data.service';
import { FindListOptions } from '../data/find-list-options.model';
import { PaginatedList } from '../data/paginated-list.model';
import { RemoteData } from '../data/remote-data';
import { RootDataService } from '../data/root-data.service';
Expand Down Expand Up @@ -331,6 +332,7 @@ export class HeadTagService {
'ORIGINAL',
true,
true,
new FindListOptions(),
followLink('primaryBitstream'),
followLink('bitstreams', {
findListOptions: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
[isFirstTable]="isFirst"
aria-describedby="reorder-description">
</ds-item-edit-bitstream-bundle>
<div class="d-flex justify-content-center" *ngIf="showLoadMoreLink$ | async">
<button class="btn btn-link my-3" (click)="loadBundles()"> {{'item.edit.bitstreams.load-more.link' | translate}}</button>
</div>
</div>
<div *ngIf="bundles?.length === 0"
class="alert alert-info w-100 d-inline-block mt-4" role="alert">
Expand Down
Loading

0 comments on commit 2d7c0cc

Please sign in to comment.