Skip to content

Commit 48ea7df

Browse files
authored
Merge pull request DSpace#2212 from enea4science/CST-7216
Import saf via URL
2 parents a377962 + 58a3ec3 commit 48ea7df

5 files changed

Lines changed: 144 additions & 7 deletions

File tree

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/assets/i18n/en.json5

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,8 @@
568568

569569
"admin.batch-import.page.help": "Select the Collection to import into. Then, drop or browse to a Simple Archive Format (SAF) zip file that includes the Items to import",
570570

571+
"admin.batch-import.page.toggle.help": "It is possible to perform import either with file upload or via URL, use above toggle to set the input source",
572+
571573
"admin.metadata-import.page.dropMsg": "Drop a metadata CSV to import",
572574

573575
"admin.batch-import.page.dropMsg": "Drop a batch ZIP to import",
@@ -584,8 +586,16 @@
584586

585587
"admin.metadata-import.page.error.addFile": "Select file first!",
586588

589+
"admin.metadata-import.page.error.addFileUrl": "Insert file url first!",
590+
587591
"admin.batch-import.page.error.addFile": "Select Zip file first!",
588592

593+
"admin.metadata-import.page.toggle.upload": "Upload",
594+
595+
"admin.metadata-import.page.toggle.url": "URL",
596+
597+
"admin.metadata-import.page.urlMsg": "Insert the batch ZIP url to import",
598+
589599
"admin.metadata-import.page.validateOnly": "Validate Only",
590600

591601
"admin.metadata-import.page.validateOnly.hint": "When selected, the uploaded CSV will be validated. You will receive a report of detected changes, but no changes will be saved.",

0 commit comments

Comments
 (0)