Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/app/app.menus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { EditCMSMetadataMenuProvider } from './shared/menu/providers/edit-cms-me
import { EditItemMenuProvider } from './shared/menu/providers/edit-item-details.menu';
import { EditUserAgreementMenuProvider } from './shared/menu/providers/edit-user-agreement.menu';
import { ExportMenuProvider } from './shared/menu/providers/export.menu';
import { ExportItemMenuProvider } from './shared/menu/providers/export-item.menu';
import { HealthMenuProvider } from './shared/menu/providers/health.menu';
import { ImportMenuProvider } from './shared/menu/providers/import.menu';
import { ClaimMenuProvider } from './shared/menu/providers/item-claim.menu';
Expand All @@ -50,6 +51,7 @@ import { WorkflowMenuProvider } from './shared/menu/providers/workflow.menu';
* - `MenuID.PUBLIC`: Defines menus accessible by the public in the navigation bar.
* - `MenuID.ADMIN`: Defines menus for administrative users in the sidebar.
* - `MenuID.DSO_EDIT`: Defines dynamic menu options for DSpace Objects that will be present on the DSpace Object's page.
* - `MenuID.DSO_PUBLIC`: Defines dynamic menu options for DSpace Objects available to unauthenticated users.
*
* To add more menu sections to a menu (public navbar, admin sidebar or the dso edit menus),
* a new provider can be added to the list with the corresponding menu ID.
Expand Down Expand Up @@ -118,4 +120,9 @@ export const MENUS = buildMenuStructure({
),
]),
],
[MenuID.DSO_PUBLIC]: [
ExportItemMenuProvider.onRoute(
MenuRoute.ITEM_PAGE,
),
],
});
53 changes: 51 additions & 2 deletions src/app/core/data/collection-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,55 @@ export class CollectionDataService extends ComColDataService<Collection> {
);
}

/**
* Get all collections the user is admin
*
* @param query limit the returned collection to those with metadata values matching the query terms.
* @param options The [[FindListOptions]] object
* @param reRequestOnStale Whether or not the request should automatically be re-requested after
* the response becomes stale
* @param linksToFollow The array of [[FollowLinkConfig]]
* @return Observable<RemoteData<PaginatedList<Collection>>>
* collection list
*/
getAdministeredCollection(query: string, options: FindListOptions = {}, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<Collection>[]): Observable<RemoteData<PaginatedList<Collection>>> {
const searchHref = 'findAdministered';
options = Object.assign({}, options, {
searchParams: [new RequestParam('query', query)],
});

return this.searchBy(searchHref, options, true, reRequestOnStale, ...linksToFollow).pipe(
getAllCompletedRemoteData(),
);
}

/**
* Get all collections the user is admin selected by entityType
*
* @param query limit the returned collection to those with metadata values matching the query terms.
* @param entityType mandatory, the label of the entity type field the collection must have.
* @param options The [[FindListOptions]] object
* @param reRequestOnStale Whether or not the request should automatically be re-requested after
* the response becomes stale
* @param linksToFollow The array of [[FollowLinkConfig]]
* @return Observable<RemoteData<PaginatedList<Collection>>>
* collection list
*/
getAdministeredCollectionByEntityType(query: string, entityType: string, options: FindListOptions = {}, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<Collection>[]): Observable<RemoteData<PaginatedList<Collection>>> {

const searchHref = 'findAdminAuthorizedByEntityType';
options = Object.assign({}, options, {
searchParams: [
new RequestParam('query', query),
new RequestParam('entityType', entityType),
],
});

return this.searchBy(searchHref, options, true, reRequestOnStale, ...linksToFollow).pipe(
getAllCompletedRemoteData(),
);
}

/**
* Get all collections the user is authorized to submit to
*
Expand Down Expand Up @@ -254,8 +303,8 @@ export class CollectionDataService extends ComColDataService<Collection> {
options.elementsPerPage = 1;

return this.searchBy(searchHref, options).pipe(
getFirstCompletedRemoteData(),
map((collections: RemoteData<PaginatedList<Collection>>) => collections?.payload?.totalElements > 0),
getAllCompletedRemoteData(),
map((collections: RemoteData<PaginatedList<Collection>>) => collections.payload.totalElements > 0),
);
}

Expand Down
8 changes: 8 additions & 0 deletions src/app/core/data/processes/process-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,4 +294,12 @@ export class ProcessDataService extends IdentifiableDataService<Process> impleme
),
);
}

/**
* Get process' details
* @param processId The ID of the process
*/
getProcess(processId: string): Observable<RemoteData<Process>> {
return this.findById(processId, false);
}
}
2 changes: 2 additions & 0 deletions src/app/core/data/processes/script-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export const METADATA_EXPORT_SCRIPT_NAME = 'metadata-export';
export const BATCH_IMPORT_SCRIPT_NAME = 'import';
export const BATCH_EXPORT_SCRIPT_NAME = 'export';
export const DSPACE_OBJECT_DELETION_SCRIPT_NAME = 'object-deletion';
export const ITEM_EXPORT_SCRIPT_NAME = 'item-export';
export const BULK_ITEM_EXPORT_SCRIPT_NAME = 'bulk-item-export';

@Injectable({ providedIn: 'root' })
@dataService(SCRIPT)
Expand Down
191 changes: 191 additions & 0 deletions src/app/core/itemexportformat/item-export-format.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import { EventEmitter } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { of } from 'rxjs';

import { RequestParam } from '../cache/models/request-param.model';
import {
SortDirection,
SortOptions,
} from '../cache/models/sort-options.model';
import { PaginatedList } from '../data/paginated-list.model';
import {
BULK_ITEM_EXPORT_SCRIPT_NAME,
ITEM_EXPORT_SCRIPT_NAME,
ScriptDataService,
} from '../data/processes/script-data.service';
import { NotificationsService } from '../notification-system/notifications.service';
import { Process } from '../processes/process.model';
import { ProcessParameter } from '../processes/process-parameter.model';
import { PaginatedSearchOptions } from '../shared/search/models/paginated-search-options.model';
import { SearchFilter } from '../shared/search/models/search-filter.model';
import { NotificationsServiceStub } from '../testing/notifications-service.stub';
import { createPaginatedList } from '../testing/utils.test';
import { createSuccessfulRemoteDataObject$ } from '../utilities/remote-data.utils';
import {
ItemExportFormatMolteplicity,
ItemExportFormatService,
} from './item-export-format.service';
import { ItemExportFormat } from './model/item-export-format.model';
import createSpyObj = jasmine.createSpyObj;

const ItemExportFormatsMap = {
Publication: [
Object.assign(new ItemExportFormat(), { id: 'publication-xml', entityType: 'Publication', molteplicity: 'MULTIPLE' }),
Object.assign(new ItemExportFormat(), { id: 'publication-csv', entityType: 'Publication', molteplicity: 'MULTIPLE' }),
],
Project: [
Object.assign(new ItemExportFormat(), { id: 'project-xml', entityType: 'Project', molteplicity: 'MULTIPLE' }),
],
};

describe('ItemExportFormatService', () => {

let service: ItemExportFormatService;
const notificationsService: NotificationsService = new NotificationsServiceStub() as any;
const translateService: TranslateService = {
get: () => of('test-message'),
onLangChange: new EventEmitter(),
onTranslationChange: new EventEmitter(),
onDefaultLangChange: new EventEmitter(),
} as any;
let scriptDataService: ScriptDataService;
const TheProcess = Object.assign(new Process(), {
processId: 1234,
resourceSelfLinks: ['process/1234'],
});

beforeEach(() => {
scriptDataService = createSpyObj('scriptDataService', ['invoke']);
service = new ItemExportFormatService(
null,
null,
null,
null,
notificationsService,
null,
null,
translateService,
scriptDataService);
});

describe('byEntityTypeAndMolteplicity', () => {

beforeEach(() => {
const searchResult: any = [...ItemExportFormatsMap.Publication, ...ItemExportFormatsMap.Project];
const paginatedList: PaginatedList<ItemExportFormat> = createPaginatedList(searchResult);
spyOn((service as any).searchData, 'searchBy').and.returnValue(createSuccessfulRemoteDataObject$(paginatedList));
});

it('should configure and call dataService.searchBy and map results by entityType', (done) => {
const entityTypeId = 'Publication';
const molteplicity = ItemExportFormatMolteplicity.MULTIPLE;

const searchParams = [
new RequestParam('molteplicity', molteplicity),
new RequestParam('entityTypeId', entityTypeId),
];

service.byEntityTypeAndMolteplicity(entityTypeId, molteplicity).subscribe((result) => {
expect((service as any).searchData.searchBy).toHaveBeenCalledWith('byEntityTypeAndMolteplicity', { searchParams, elementsPerPage: 100 });
expect(result).toEqual(ItemExportFormatsMap);
done();
});

expect(service).toBeTruthy();
});

});

describe('doExport', () => {

beforeEach(() => {
(scriptDataService as any).invoke.and.returnValue(createSuccessfulRemoteDataObject$(TheProcess));
});

it('should invoke a configured single item export', (done) => {
const format = Object.assign(new ItemExportFormat(), { id: 'publication-xml' });
const uuid = 'itemUUID';
const expectedParameters = [
Object.assign(new ProcessParameter(), { name: '-i', value: 'itemUUID' }),
Object.assign(new ProcessParameter(), { name: '-f', value: 'publication-xml' }),
];
service.doExport(uuid, format).subscribe((result) => {
expect(result).toEqual(1234);
expect((service as any).scriptDataService.invoke).toHaveBeenCalledWith(ITEM_EXPORT_SCRIPT_NAME, expectedParameters, []);
done();
});

});

});

describe('doExportMulti', () => {

beforeEach(() => {
(scriptDataService as any).invoke.and.returnValue(createSuccessfulRemoteDataObject$(TheProcess));
});

it('should invoke a configured bulk item export', (done) => {
const entityType = 'Publication';
const format = Object.assign(new ItemExportFormat(), { id: 'publication-xml' });
const searchOptions = new PaginatedSearchOptions({
query: 'queryX',
filters: [
new SearchFilter('f.name', ['nameX', 'nameY']),
new SearchFilter('f.type', ['typeX']),
new SearchFilter('other.name', ['nameY']),
],
fixedFilter: 'scope=scopeX',
configuration: 'configurationX',
sort: new SortOptions('fieldX', SortDirection.ASC),
});

const expectedParameters = [
Object.assign(new ProcessParameter(), { name: '-f', value: 'publication-xml' }),
Object.assign(new ProcessParameter(), { name: '-t', value: 'Publication' }),
Object.assign(new ProcessParameter(), { name: '-q', value: 'queryX' }),
Object.assign(new ProcessParameter(), { name: '-sf', value: 'name=nameX&name=nameY&type=typeX' }),
Object.assign(new ProcessParameter(), { name: '-s', value: 'scopeX' }),
Object.assign(new ProcessParameter(), { name: '-c', value: 'configurationX' }),
Object.assign(new ProcessParameter(), { name: '-so', value: 'fieldX,ASC' }),
];

service.doExportMulti(entityType, format, searchOptions).subscribe((result) => {
expect(result).toEqual(1234);
expect((service as any).scriptDataService.invoke).toHaveBeenCalledWith(BULK_ITEM_EXPORT_SCRIPT_NAME, expectedParameters, []);
done();
});

});

it('should invoke a configured bulk item export with a list', (done) => {
const entityType = 'Publication';
const format = Object.assign(new ItemExportFormat(), { id: 'publication-xml' });
const searchOptions = new PaginatedSearchOptions({
query: 'queryX',
filters: [
new SearchFilter('f.name', ['nameX']),
new SearchFilter('f.type', ['typeX']),
new SearchFilter('other.name', ['nameY']),
],
fixedFilter: 'scope=scopeX',
configuration: 'configurationX',
sort: new SortOptions('fieldX', SortDirection.ASC),
});

const expectedParameters = [
Object.assign(new ProcessParameter(), { name: '-f', value: 'publication-xml' }),
Object.assign(new ProcessParameter(), { name: '-si', value: 'item1;item2' }),
];

service.doExportMulti(entityType, format, searchOptions, ['item1', 'item2']).subscribe((result) => {
expect(result).toEqual(1234);
expect((service as any).scriptDataService.invoke).toHaveBeenCalledWith(BULK_ITEM_EXPORT_SCRIPT_NAME, expectedParameters, []);
done();
});

});

});

});
Loading
Loading