Skip to content

Commit 6e6b775

Browse files
committed
Merge remote-tracking branch '4sciencebitbucket/feature/CST-9636' into feature/CST-9636
2 parents 9a74190 + e720c77 commit 6e6b775

13 files changed

Lines changed: 460 additions & 393 deletions

File tree

cypress/e2e/homepage.cy.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ describe('Homepage', () => {
66
cy.visit('/');
77
});
88

9-
it('should display translated title "DSpace Angular :: Home"', () => {
10-
cy.title().should('eq', 'DSpace Angular :: Home');
9+
it('should display translated title "DSpace Repository :: Home"', () => {
10+
cy.title().should('eq', 'DSpace Repository :: Home');
1111
});
1212

1313
it('should contain a news section', () => {

src/app/admin/admin-import-batch-page/batch-import-page.component.html

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,29 @@ <h2 id="header">{{'admin.batch-import.page.header' | translate}}</h2>
2020
</small>
2121
</div>
2222

23+
<ui-switch color="#ebebeb"
24+
[checkedLabel]="'admin.metadata-import.page.toggle.upload' | translate"
25+
[uncheckedLabel]="'admin.metadata-import.page.toggle.url' | translate"
26+
[checked]="isUpload"
27+
(change)="toggleUpload()" ></ui-switch>
28+
<small class="form-text text-muted">
29+
{{'admin.batch-import.page.toggle.help' | translate}}
30+
</small>
31+
32+
2333
<ds-file-dropzone-no-uploader
34+
*ngIf="isUpload"
35+
data-test="file-dropzone"
2436
(onFileAdded)="setFile($event)"
2537
[dropMessageLabel]="'admin.batch-import.page.dropMsg'"
2638
[dropMessageLabelReplacement]="'admin.batch-import.page.dropMsgReplace'">
2739
</ds-file-dropzone-no-uploader>
2840

41+
<div class="form-group mt-2" *ngIf="!isUpload">
42+
<input class="form-control" type="text" placeholder="{{'admin.metadata-import.page.urlMsg' | translate}}"
43+
data-test="file-url-input" [(ngModel)]="fileURL">
44+
</div>
45+
2946
<div class="space-children-mr">
3047
<button class="btn btn-secondary" id="backButton"
3148
(click)="this.onReturn();">{{'admin.metadata-import.page.button.return' | translate}}</button>

src/app/admin/admin-import-batch-page/batch-import-page.component.spec.ts

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,18 @@ describe('BatchImportPageComponent', () => {
8686
let fileMock: File;
8787

8888
beforeEach(() => {
89+
component.isUpload = true;
8990
fileMock = new File([''], 'filename.zip', { type: 'application/zip' });
9091
component.setFile(fileMock);
9192
});
9293

94+
it('should show the file dropzone', () => {
95+
const fileDropzone = fixture.debugElement.query(By.css('[data-test="file-dropzone"]'));
96+
const fileUrlInput = fixture.debugElement.query(By.css('[data-test="file-url-input"]'));
97+
expect(fileDropzone).toBeTruthy();
98+
expect(fileUrlInput).toBeFalsy();
99+
});
100+
93101
describe('if proceed button is pressed without validate only', () => {
94102
beforeEach(fakeAsync(() => {
95103
component.validateOnly = false;
@@ -99,9 +107,9 @@ describe('BatchImportPageComponent', () => {
99107
}));
100108
it('metadata-import script is invoked with --zip fileName and the mockFile', () => {
101109
const parameterValues: ProcessParameter[] = [
102-
Object.assign(new ProcessParameter(), { name: '--zip', value: 'filename.zip' }),
110+
Object.assign(new ProcessParameter(), { name: '--add' }),
111+
Object.assign(new ProcessParameter(), { name: '--zip', value: 'filename.zip' })
103112
];
104-
parameterValues.push(Object.assign(new ProcessParameter(), { name: '--add' }));
105113
expect(scriptService.invoke).toHaveBeenCalledWith(BATCH_IMPORT_SCRIPT_NAME, parameterValues, [fileMock]);
106114
});
107115
it('success notification is shown', () => {
@@ -121,8 +129,8 @@ describe('BatchImportPageComponent', () => {
121129
}));
122130
it('metadata-import script is invoked with --zip fileName and the mockFile and -v validate-only', () => {
123131
const parameterValues: ProcessParameter[] = [
124-
Object.assign(new ProcessParameter(), { name: '--zip', value: 'filename.zip' }),
125132
Object.assign(new ProcessParameter(), { name: '--add' }),
133+
Object.assign(new ProcessParameter(), { name: '--zip', value: 'filename.zip' }),
126134
Object.assign(new ProcessParameter(), { name: '-v', value: true }),
127135
];
128136
expect(scriptService.invoke).toHaveBeenCalledWith(BATCH_IMPORT_SCRIPT_NAME, parameterValues, [fileMock]);
@@ -148,4 +156,77 @@ describe('BatchImportPageComponent', () => {
148156
});
149157
});
150158
});
159+
160+
describe('if url is set', () => {
161+
beforeEach(fakeAsync(() => {
162+
component.isUpload = false;
163+
component.fileURL = 'example.fileURL.com';
164+
fixture.detectChanges();
165+
}));
166+
167+
it('should show the file url input', () => {
168+
const fileDropzone = fixture.debugElement.query(By.css('[data-test="file-dropzone"]'));
169+
const fileUrlInput = fixture.debugElement.query(By.css('[data-test="file-url-input"]'));
170+
expect(fileDropzone).toBeFalsy();
171+
expect(fileUrlInput).toBeTruthy();
172+
});
173+
174+
describe('if proceed button is pressed without validate only', () => {
175+
beforeEach(fakeAsync(() => {
176+
component.validateOnly = false;
177+
const proceed = fixture.debugElement.query(By.css('#proceedButton')).nativeElement;
178+
proceed.click();
179+
fixture.detectChanges();
180+
}));
181+
it('metadata-import script is invoked with --url and the file url', () => {
182+
const parameterValues: ProcessParameter[] = [
183+
Object.assign(new ProcessParameter(), { name: '--add' }),
184+
Object.assign(new ProcessParameter(), { name: '--url', value: 'example.fileURL.com' })
185+
];
186+
expect(scriptService.invoke).toHaveBeenCalledWith(BATCH_IMPORT_SCRIPT_NAME, parameterValues, [null]);
187+
});
188+
it('success notification is shown', () => {
189+
expect(notificationService.success).toHaveBeenCalled();
190+
});
191+
it('redirected to process page', () => {
192+
expect(router.navigateByUrl).toHaveBeenCalledWith('/processes/46');
193+
});
194+
});
195+
196+
describe('if proceed button is pressed with validate only', () => {
197+
beforeEach(fakeAsync(() => {
198+
component.validateOnly = true;
199+
const proceed = fixture.debugElement.query(By.css('#proceedButton')).nativeElement;
200+
proceed.click();
201+
fixture.detectChanges();
202+
}));
203+
it('metadata-import script is invoked with --url and the file url and -v validate-only', () => {
204+
const parameterValues: ProcessParameter[] = [
205+
Object.assign(new ProcessParameter(), { name: '--add' }),
206+
Object.assign(new ProcessParameter(), { name: '--url', value: 'example.fileURL.com' }),
207+
Object.assign(new ProcessParameter(), { name: '-v', value: true }),
208+
];
209+
expect(scriptService.invoke).toHaveBeenCalledWith(BATCH_IMPORT_SCRIPT_NAME, parameterValues, [null]);
210+
});
211+
it('success notification is shown', () => {
212+
expect(notificationService.success).toHaveBeenCalled();
213+
});
214+
it('redirected to process page', () => {
215+
expect(router.navigateByUrl).toHaveBeenCalledWith('/processes/46');
216+
});
217+
});
218+
219+
describe('if proceed is pressed; but script invoke fails', () => {
220+
beforeEach(fakeAsync(() => {
221+
jasmine.getEnv().allowRespy(true);
222+
spyOn(scriptService, 'invoke').and.returnValue(createFailedRemoteDataObject$('Error', 500));
223+
const proceed = fixture.debugElement.query(By.css('#proceedButton')).nativeElement;
224+
proceed.click();
225+
fixture.detectChanges();
226+
}));
227+
it('error notification is shown', () => {
228+
expect(notificationService.error).toHaveBeenCalled();
229+
});
230+
});
231+
});
151232
});

src/app/admin/admin-import-batch-page/batch-import-page.component.ts

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { ProcessParameter } from '../../process-page/processes/process-parameter
88
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
99
import { RemoteData } from '../../core/data/remote-data';
1010
import { Process } from '../../process-page/processes/process.model';
11-
import { isNotEmpty } from '../../shared/empty.util';
11+
import { isEmpty, isNotEmpty } from '../../shared/empty.util';
1212
import { getProcessDetailRoute } from '../../process-page/process-page-routing.paths';
1313
import {
1414
ImportBatchSelectorComponent
@@ -32,11 +32,22 @@ export class BatchImportPageComponent {
3232
* The validate only flag
3333
*/
3434
validateOnly = true;
35+
3536
/**
3637
* dso object for community or collection
3738
*/
3839
dso: DSpaceObject = null;
3940

41+
/**
42+
* The flag between upload and url
43+
*/
44+
isUpload = true;
45+
46+
/**
47+
* File URL when flag is for url
48+
*/
49+
fileURL: string;
50+
4051
public constructor(private location: Location,
4152
protected translate: TranslateService,
4253
protected notificationsService: NotificationsService,
@@ -72,13 +83,22 @@ export class BatchImportPageComponent {
7283
* Starts import-metadata script with --zip fileName (and the selected file)
7384
*/
7485
public importMetadata() {
75-
if (this.fileObject == null) {
76-
this.notificationsService.error(this.translate.get('admin.metadata-import.page.error.addFile'));
86+
if (this.fileObject == null && isEmpty(this.fileURL)) {
87+
if (this.isUpload) {
88+
this.notificationsService.error(this.translate.get('admin.metadata-import.page.error.addFile'));
89+
} else {
90+
this.notificationsService.error(this.translate.get('admin.metadata-import.page.error.addFileUrl'));
91+
}
7792
} else {
7893
const parameterValues: ProcessParameter[] = [
79-
Object.assign(new ProcessParameter(), { name: '--zip', value: this.fileObject.name }),
8094
Object.assign(new ProcessParameter(), { name: '--add' })
8195
];
96+
if (this.isUpload) {
97+
parameterValues.push(Object.assign(new ProcessParameter(), { name: '--zip', value: this.fileObject.name }));
98+
} else {
99+
this.fileObject = null;
100+
parameterValues.push(Object.assign(new ProcessParameter(), { name: '--url', value: this.fileURL }));
101+
}
82102
if (this.dso) {
83103
parameterValues.push(Object.assign(new ProcessParameter(), { name: '--collection', value: this.dso.uuid }));
84104
}
@@ -127,4 +147,11 @@ export class BatchImportPageComponent {
127147
removeDspaceObject(): void {
128148
this.dso = null;
129149
}
150+
151+
/**
152+
* toggle the flag between upload and url
153+
*/
154+
toggleUpload() {
155+
this.isUpload = !this.isUpload;
156+
}
130157
}

src/app/admin/admin.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { AdminSearchModule } from './admin-search-page/admin-search.module';
1010
import { AdminSidebarSectionComponent } from './admin-sidebar/admin-sidebar-section/admin-sidebar-section.component';
1111
import { ExpandableAdminSidebarSectionComponent } from './admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component';
1212
import { BatchImportPageComponent } from './admin-import-batch-page/batch-import-page.component';
13+
import { UiSwitchModule } from 'ngx-ui-switch';
1314
import { UploadModule } from '../shared/upload/upload.module';
1415

1516
const ENTRY_COMPONENTS = [
@@ -27,6 +28,7 @@ const ENTRY_COMPONENTS = [
2728
AdminSearchModule.withEntryComponents(),
2829
AdminWorkflowModuleModule.withEntryComponents(),
2930
SharedModule,
31+
UiSwitchModule,
3032
UploadModule,
3133
],
3234
declarations: [

src/app/browse-by/browse-by-guard.spec.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
import { first } from 'rxjs/operators';
22
import { BrowseByGuard } from './browse-by-guard';
33
import { of as observableOf } from 'rxjs';
4-
import { createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils';
4+
import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils';
55
import { BrowseByDataType } from './browse-by-switcher/browse-by-decorator';
66
import { ValueListBrowseDefinition } from '../core/shared/value-list-browse-definition.model';
77
import { DSONameServiceMock } from '../shared/mocks/dso-name.service.mock';
88
import { DSONameService } from '../core/breadcrumbs/dso-name.service';
9+
import { RouterStub } from '../shared/testing/router.stub';
910

1011
describe('BrowseByGuard', () => {
1112
describe('canActivate', () => {
1213
let guard: BrowseByGuard;
1314
let dsoService: any;
1415
let translateService: any;
1516
let browseDefinitionService: any;
17+
let router: any;
1618

1719
const name = 'An interesting DSO';
1820
const title = 'Author';
@@ -35,7 +37,9 @@ describe('BrowseByGuard', () => {
3537
findById: () => createSuccessfulRemoteDataObject$(browseDefinition)
3638
};
3739

38-
guard = new BrowseByGuard(dsoService, translateService, browseDefinitionService, new DSONameServiceMock() as DSONameService);
40+
router = new RouterStub() as any;
41+
42+
guard = new BrowseByGuard(dsoService, translateService, browseDefinitionService, new DSONameServiceMock() as DSONameService, router);
3943
});
4044

4145
it('should return true, and sets up the data correctly, with a scope and value', () => {
@@ -65,6 +69,7 @@ describe('BrowseByGuard', () => {
6569
value: '"' + value + '"'
6670
};
6771
expect(scopedRoute.data).toEqual(result);
72+
expect(router.navigate).not.toHaveBeenCalled();
6873
expect(canActivate).toEqual(true);
6974
}
7075
);
@@ -97,6 +102,7 @@ describe('BrowseByGuard', () => {
97102
value: ''
98103
};
99104
expect(scopedNoValueRoute.data).toEqual(result);
105+
expect(router.navigate).not.toHaveBeenCalled();
100106
expect(canActivate).toEqual(true);
101107
}
102108
);
@@ -128,9 +134,33 @@ describe('BrowseByGuard', () => {
128134
value: '"' + value + '"'
129135
};
130136
expect(route.data).toEqual(result);
137+
expect(router.navigate).not.toHaveBeenCalled();
131138
expect(canActivate).toEqual(true);
132139
}
133140
);
134141
});
142+
143+
it('should return false, and sets up the data correctly, without a scope and with a value', () => {
144+
jasmine.getEnv().allowRespy(true);
145+
spyOn(browseDefinitionService, 'findById').and.returnValue(createFailedRemoteDataObject$());
146+
const scopedRoute = {
147+
data: {
148+
title: field,
149+
},
150+
params: {
151+
id,
152+
},
153+
queryParams: {
154+
scope,
155+
value
156+
}
157+
};
158+
guard.canActivate(scopedRoute as any, undefined)
159+
.pipe(first())
160+
.subscribe((canActivate) => {
161+
expect(router.navigate).toHaveBeenCalled();
162+
expect(canActivate).toEqual(false);
163+
});
164+
});
135165
});
136166
});

0 commit comments

Comments
 (0)