diff --git a/src/app/+admin/admin-curation-tasks/admin-curation-tasks.component.html b/src/app/+admin/admin-curation-tasks/admin-curation-tasks.component.html
new file mode 100644
index 0000000000..a702a7e6b0
--- /dev/null
+++ b/src/app/+admin/admin-curation-tasks/admin-curation-tasks.component.html
@@ -0,0 +1,4 @@
+
+
{{'admin.curation-tasks.header' |translate }}
+
+
diff --git a/src/app/+admin/admin-curation-tasks/admin-curation-tasks.component.spec.ts b/src/app/+admin/admin-curation-tasks/admin-curation-tasks.component.spec.ts
new file mode 100644
index 0000000000..b84f619ff1
--- /dev/null
+++ b/src/app/+admin/admin-curation-tasks/admin-curation-tasks.component.spec.ts
@@ -0,0 +1,28 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { AdminCurationTasksComponent } from './admin-curation-tasks.component';
+import { TranslateModule } from '@ngx-translate/core';
+import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+
+describe('AdminCurationTasksComponent', () => {
+ let comp: AdminCurationTasksComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [TranslateModule.forRoot()],
+ declarations: [AdminCurationTasksComponent],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(AdminCurationTasksComponent);
+ comp = fixture.componentInstance;
+ });
+ describe('init', () => {
+ it('should initialise the comp', () => {
+ expect(comp).toBeDefined();
+ expect(fixture.debugElement.nativeElement.innerHTML).toContain('ds-curation-form');
+ });
+ });
+});
diff --git a/src/app/+admin/admin-curation-tasks/admin-curation-tasks.component.ts b/src/app/+admin/admin-curation-tasks/admin-curation-tasks.component.ts
new file mode 100644
index 0000000000..9a80f341b9
--- /dev/null
+++ b/src/app/+admin/admin-curation-tasks/admin-curation-tasks.component.ts
@@ -0,0 +1,12 @@
+import { Component } from '@angular/core';
+
+/**
+ * Component responsible for rendering the system wide Curation Task UI
+ */
+@Component({
+ selector: 'ds-admin-curation-task',
+ templateUrl: './admin-curation-tasks.component.html',
+})
+export class AdminCurationTasksComponent {
+
+}
diff --git a/src/app/+admin/admin-routing.module.ts b/src/app/+admin/admin-routing.module.ts
index b199129c4e..43b3a4ab34 100644
--- a/src/app/+admin/admin-routing.module.ts
+++ b/src/app/+admin/admin-routing.module.ts
@@ -6,6 +6,7 @@ import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.reso
import { AdminWorkflowPageComponent } from './admin-workflow-page/admin-workflow-page.component';
import { I18nBreadcrumbsService } from '../core/breadcrumbs/i18n-breadcrumbs.service';
import { URLCombiner } from '../core/url-combiner/url-combiner';
+import { AdminCurationTasksComponent } from './admin-curation-tasks/admin-curation-tasks.component';
const REGISTRIES_MODULE_PATH = 'registries';
export const ACCESS_CONTROL_MODULE_PATH = 'access-control';
@@ -41,6 +42,12 @@ export function getAccessControlModulePath() {
component: AdminWorkflowPageComponent,
data: { title: 'admin.workflow.title', breadcrumbKey: 'admin.workflow' }
},
+ {
+ path: 'curation-tasks',
+ resolve: { breadcrumb: I18nBreadcrumbResolver },
+ component: AdminCurationTasksComponent,
+ data: { title: 'admin.curation-tasks.title', breadcrumbKey: 'admin.curation-tasks' }
+ },
])
],
providers: [
diff --git a/src/app/+admin/admin-sidebar/admin-sidebar.component.ts b/src/app/+admin/admin-sidebar/admin-sidebar.component.ts
index ade3e33aed..eb86de5f3c 100644
--- a/src/app/+admin/admin-sidebar/admin-sidebar.component.ts
+++ b/src/app/+admin/admin-sidebar/admin-sidebar.component.ts
@@ -469,7 +469,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
model: {
type: MenuItemType.LINK,
text: 'menu.section.curation_task',
- link: ''
+ link: 'admin/curation-tasks'
} as LinkMenuItemModel,
icon: 'filter',
index: 7
diff --git a/src/app/+admin/admin.module.ts b/src/app/+admin/admin.module.ts
index 25b8bd4648..85749afe03 100644
--- a/src/app/+admin/admin.module.ts
+++ b/src/app/+admin/admin.module.ts
@@ -16,6 +16,7 @@ import { WorkflowItemSearchResultAdminWorkflowGridElementComponent } from './adm
import { WorkflowItemAdminWorkflowActionsComponent } from './admin-workflow-page/admin-workflow-search-results/workflow-item-admin-workflow-actions.component';
import { WorkflowItemSearchResultAdminWorkflowListElementComponent } from './admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/workflow-item/workflow-item-search-result-admin-workflow-list-element.component';
import { AdminWorkflowPageComponent } from './admin-workflow-page/admin-workflow-page.component';
+import { AdminCurationTasksComponent } from './admin-curation-tasks/admin-curation-tasks.component';
@NgModule({
imports: [
@@ -35,6 +36,7 @@ import { AdminWorkflowPageComponent } from './admin-workflow-page/admin-workflow
CommunityAdminSearchResultGridElementComponent,
CollectionAdminSearchResultGridElementComponent,
ItemAdminSearchResultActionsComponent,
+ AdminCurationTasksComponent,
WorkflowItemSearchResultAdminWorkflowListElementComponent,
WorkflowItemSearchResultAdminWorkflowGridElementComponent,
diff --git a/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.html b/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.html
index e69de29bb2..38c9d22f4e 100644
--- a/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.html
+++ b/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.html
@@ -0,0 +1,6 @@
+
+
{{'collection.curate.header' |translate:{collection: (collectionName$ |async)} }}
+
+
diff --git a/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.spec.ts b/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.spec.ts
new file mode 100644
index 0000000000..91c264cd0f
--- /dev/null
+++ b/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.spec.ts
@@ -0,0 +1,69 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { TranslateModule } from '@ngx-translate/core';
+import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '@angular/core';
+import { CollectionCurateComponent } from './collection-curate.component';
+import { of as observableOf } from 'rxjs';
+import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils';
+import { Collection } from '../../../core/shared/collection.model';
+import { ActivatedRoute } from '@angular/router';
+import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
+
+describe('CollectionCurateComponent', () => {
+ let comp: CollectionCurateComponent;
+ let fixture: ComponentFixture;
+ let debugEl: DebugElement;
+
+ let routeStub;
+ let dsoNameService;
+
+ const collection = Object.assign(new Collection(), {
+ handle: '123456789/1', metadata: {'dc.title': ['Collection Name']}
+ });
+
+ beforeEach(async(() => {
+ routeStub = {
+ parent: {
+ data: observableOf({
+ dso: createSuccessfulRemoteDataObject(collection)
+ })
+ }
+ };
+
+ dsoNameService = jasmine.createSpyObj('dsoNameService', {
+ getName: 'Collection Name'
+ });
+
+ TestBed.configureTestingModule({
+ imports: [TranslateModule.forRoot()],
+ declarations: [CollectionCurateComponent],
+ providers: [
+ {provide: ActivatedRoute, useValue: routeStub},
+ {provide: DSONameService, useValue: dsoNameService}
+ ],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CollectionCurateComponent);
+ comp = fixture.componentInstance;
+ debugEl = fixture.debugElement;
+
+ fixture.detectChanges();
+ });
+ describe('init', () => {
+ it('should initialise the comp', () => {
+ expect(comp).toBeDefined();
+ expect(debugEl.nativeElement.innerHTML).toContain('ds-curation-form');
+ });
+ it('should contain the collection information provided in the route', () => {
+ comp.dsoRD$.subscribe((value) => {
+ expect(value.payload.handle
+ ).toEqual('123456789/1');
+ });
+ comp.collectionName$.subscribe((value) => {
+ expect(value).toEqual('Collection Name');
+ });
+ });
+ });
+});
diff --git a/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.ts b/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.ts
index d7deaea982..e20f229cd6 100644
--- a/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.ts
+++ b/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.ts
@@ -1,4 +1,11 @@
import { Component } from '@angular/core';
+import { filter, map, take } from 'rxjs/operators';
+import { RemoteData } from '../../../core/data/remote-data';
+import { Observable } from 'rxjs';
+import { ActivatedRoute } from '@angular/router';
+import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
+import { Collection } from '../../../core/shared/collection.model';
+import { hasValue } from '../../../shared/empty.util';
/**
* Component for managing a collection's curation tasks
@@ -8,5 +15,26 @@ import { Component } from '@angular/core';
templateUrl: './collection-curate.component.html',
})
export class CollectionCurateComponent {
- /* TODO: Implement Collection Edit - Curate */
+ dsoRD$: Observable>;
+ collectionName$: Observable;
+
+ constructor(
+ private route: ActivatedRoute,
+ private dsoNameService: DSONameService,
+ ) {
+ }
+
+ ngOnInit(): void {
+ this.dsoRD$ = this.route.parent.data.pipe(
+ take(1),
+ map((data) => data.dso),
+ );
+
+ this.collectionName$ = this.dsoRD$.pipe(
+ filter((rd: RemoteData) => hasValue(rd)),
+ map((rd: RemoteData) => {
+ return this.dsoNameService.getName(rd.payload);
+ })
+ );
+ }
}
diff --git a/src/app/+community-page/edit-community-page/community-curate/community-curate.component.html b/src/app/+community-page/edit-community-page/community-curate/community-curate.component.html
index e69de29bb2..6c041d1725 100644
--- a/src/app/+community-page/edit-community-page/community-curate/community-curate.component.html
+++ b/src/app/+community-page/edit-community-page/community-curate/community-curate.component.html
@@ -0,0 +1,6 @@
+
+
{{'community.curate.header' |translate:{community: (communityName$ |async)} }}
+
+
diff --git a/src/app/+community-page/edit-community-page/community-curate/community-curate.component.spec.ts b/src/app/+community-page/edit-community-page/community-curate/community-curate.component.spec.ts
new file mode 100644
index 0000000000..42dc0f08a9
--- /dev/null
+++ b/src/app/+community-page/edit-community-page/community-curate/community-curate.component.spec.ts
@@ -0,0 +1,69 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { TranslateModule } from '@ngx-translate/core';
+import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '@angular/core';
+import { of as observableOf } from 'rxjs';
+import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils';
+import { ActivatedRoute } from '@angular/router';
+import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
+import { CommunityCurateComponent } from './community-curate.component';
+import { Community } from '../../../core/shared/community.model';
+
+describe('CommunityCurateComponent', () => {
+ let comp: CommunityCurateComponent;
+ let fixture: ComponentFixture;
+ let debugEl: DebugElement;
+
+ let routeStub;
+ let dsoNameService;
+
+ const community = Object.assign(new Community(), {
+ handle: '123456789/1', metadata: {'dc.title': ['Community Name']}
+ });
+
+ beforeEach(async(() => {
+ routeStub = {
+ parent: {
+ data: observableOf({
+ dso: createSuccessfulRemoteDataObject(community)
+ })
+ }
+ };
+
+ dsoNameService = jasmine.createSpyObj('dsoNameService', {
+ getName: 'Community Name'
+ });
+
+ TestBed.configureTestingModule({
+ imports: [TranslateModule.forRoot()],
+ declarations: [CommunityCurateComponent],
+ providers: [
+ {provide: ActivatedRoute, useValue: routeStub},
+ {provide: DSONameService, useValue: dsoNameService}
+ ],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CommunityCurateComponent);
+ comp = fixture.componentInstance;
+ debugEl = fixture.debugElement;
+
+ fixture.detectChanges();
+ });
+ describe('init', () => {
+ it('should initialise the comp', () => {
+ expect(comp).toBeDefined();
+ expect(debugEl.nativeElement.innerHTML).toContain('ds-curation-form');
+ });
+ it('should contain the community information provided in the route', () => {
+ comp.dsoRD$.subscribe((value) => {
+ expect(value.payload.handle
+ ).toEqual('123456789/1');
+ });
+ comp.communityName$.subscribe((value) => {
+ expect(value).toEqual('Community Name');
+ });
+ });
+ });
+});
diff --git a/src/app/+community-page/edit-community-page/community-curate/community-curate.component.ts b/src/app/+community-page/edit-community-page/community-curate/community-curate.component.ts
index 6151d3fe9a..5954b3e95e 100644
--- a/src/app/+community-page/edit-community-page/community-curate/community-curate.component.ts
+++ b/src/app/+community-page/edit-community-page/community-curate/community-curate.component.ts
@@ -1,4 +1,12 @@
-import { Component } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
+import { Community } from '../../../core/shared/community.model';
+import { ActivatedRoute } from '@angular/router';
+import { map, take } from 'rxjs/operators';
+import { RemoteData } from '../../../core/data/remote-data';
+import { Observable } from 'rxjs';
+import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
+import { hasValue } from '../../../shared/empty.util';
+import { filter } from 'rxjs/internal/operators/filter';
/**
* Component for managing a community's curation tasks
@@ -7,6 +15,29 @@ import { Component } from '@angular/core';
selector: 'ds-community-curate',
templateUrl: './community-curate.component.html',
})
-export class CommunityCurateComponent {
- /* TODO: Implement Community Edit - Curate */
+export class CommunityCurateComponent implements OnInit {
+
+ dsoRD$: Observable>;
+ communityName$: Observable;
+
+ constructor(
+ private route: ActivatedRoute,
+ private dsoNameService: DSONameService,
+ ) {
+ }
+
+ ngOnInit(): void {
+ this.dsoRD$ = this.route.parent.data.pipe(
+ take(1),
+ map((data) => data.dso),
+ );
+
+ this.communityName$ = this.dsoRD$.pipe(
+ filter((rd: RemoteData) => hasValue(rd)),
+ map((rd: RemoteData) => {
+ return this.dsoNameService.getName(rd.payload);
+ })
+ );
+ }
+
}
diff --git a/src/app/curation-form/curation-form.component.html b/src/app/curation-form/curation-form.component.html
new file mode 100644
index 0000000000..129a51a037
--- /dev/null
+++ b/src/app/curation-form/curation-form.component.html
@@ -0,0 +1,20 @@
+
diff --git a/src/app/curation-form/curation-form.component.spec.ts b/src/app/curation-form/curation-form.component.spec.ts
new file mode 100644
index 0000000000..2fada44742
--- /dev/null
+++ b/src/app/curation-form/curation-form.component.spec.ts
@@ -0,0 +1,148 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { TranslateModule } from '@ngx-translate/core';
+import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+import { CurationFormComponent } from './curation-form.component';
+import { ScriptDataService } from '../core/data/processes/script-data.service';
+import { ProcessDataService } from '../core/data/processes/process-data.service';
+import { AuthService } from '../core/auth/auth.service';
+import { of as observableOf } from 'rxjs';
+import { RequestEntry } from '../core/data/request.reducer';
+import { DSOSuccessResponse, RestResponse } from '../core/cache/response.models';
+import { Process } from '../process-page/processes/process.model';
+import { createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils';
+import { EPerson } from '../core/eperson/models/eperson.model';
+import { NotificationsServiceStub } from '../shared/testing/notifications-service.stub';
+import { RouterStub } from '../shared/testing/router.stub';
+import { NotificationsService } from '../shared/notifications/notifications.service';
+import { Router } from '@angular/router';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { By } from '@angular/platform-browser';
+
+describe('CurationFormComponent', () => {
+ let comp: CurationFormComponent;
+ let fixture: ComponentFixture;
+
+ let scriptDataService: ScriptDataService;
+ let processDataService: ProcessDataService;
+ let authService: AuthService;
+ let notificationsService;
+ let router;
+
+ const requestEntry = Object.assign(new RequestEntry(),
+ {response: new DSOSuccessResponse(['process-link'], 200, 'success')});
+ const failedRequestEntry = Object.assign(new RequestEntry(),
+ {response: new RestResponse(false, 400, 'Bad Request')});
+
+ const process = Object.assign(new Process(), {processId: 'process-id'});
+
+ beforeEach(async(() => {
+
+ scriptDataService = jasmine.createSpyObj('scriptDataService', {
+ invoke: observableOf(requestEntry)
+ });
+
+ processDataService = jasmine.createSpyObj('processDataService', {
+ findByHref: createSuccessfulRemoteDataObject$(process)
+ });
+
+ authService = jasmine.createSpyObj('authService', {
+ getAuthenticatedUserFromStore: observableOf(Object.assign(new EPerson(), {email: 'test@mail'}))
+ });
+
+ notificationsService = new NotificationsServiceStub();
+ router = new RouterStub();
+
+ TestBed.configureTestingModule({
+ imports: [TranslateModule.forRoot(), FormsModule, ReactiveFormsModule],
+ declarations: [CurationFormComponent],
+ providers: [
+ {provide: ScriptDataService, useValue: scriptDataService},
+ {provide: ProcessDataService, useValue: processDataService},
+ {provide: AuthService, useValue: authService},
+ {provide: NotificationsService, useValue: notificationsService},
+ {provide: Router, useValue: router},
+ ],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CurationFormComponent);
+ comp = fixture.componentInstance;
+
+ fixture.detectChanges();
+ });
+ describe('init', () => {
+ it('should initialise the comp and contain the different tasks', () => {
+ expect(comp).toBeDefined();
+
+ const elements = fixture.debugElement.queryAll(By.css('option'));
+ expect(elements.length).toEqual(3);
+ expect(elements[0].nativeElement.innerHTML).toContain('curation-task.task.profileformats.label');
+ expect(elements[1].nativeElement.innerHTML).toContain('curation-task.task.requiredmetadata.label');
+ expect(elements[2].nativeElement.innerHTML).toContain('curation-task.task.checklinks.label');
+ });
+ });
+ describe('hasHandleValue', () => {
+ it('should return true when a dsoHandle value was provided', () => {
+ comp.dsoHandle = 'some-handle';
+ fixture.detectChanges();
+
+ expect(comp.hasHandleValue()).toBeTrue();
+ });
+ it('should return false when no dsoHandle value was provided', () => {
+ expect(comp.hasHandleValue()).toBeFalse();
+ });
+ });
+ describe('submit', () => {
+ it('should submit the selected process and handle to the scriptservice and navigate to the corresponding process page', () => {
+ comp.dsoHandle = 'test-handle';
+ comp.submit();
+
+ expect(scriptDataService.invoke).toHaveBeenCalledWith('curate', [
+ {name: '-t', value: 'profileformats'},
+ {name: '-i', value: 'test-handle'},
+ {name: '-e', value: 'test@mail'},
+ ], []);
+ expect(notificationsService.success).toHaveBeenCalled();
+ expect(processDataService.findByHref).toHaveBeenCalledWith('process-link');
+ expect(router.navigate).toHaveBeenCalledWith(['/processes', 'process-id']);
+ });
+ it('should the selected process and handle to the scriptservice and stay on the page on error', () => {
+ (scriptDataService.invoke as jasmine.Spy).and.returnValue(observableOf(failedRequestEntry));
+
+ comp.dsoHandle = 'test-handle';
+ comp.submit();
+
+ expect(scriptDataService.invoke).toHaveBeenCalledWith('curate', [
+ {name: '-t', value: 'profileformats'},
+ {name: '-i', value: 'test-handle'},
+ {name: '-e', value: 'test@mail'},
+ ], []);
+ expect(notificationsService.error).toHaveBeenCalled();
+ expect(processDataService.findByHref).not.toHaveBeenCalled();
+ expect(router.navigate).not.toHaveBeenCalled();
+ });
+ });
+ it('should use the handle provided by the form when no dsoHandle is provided', () => {
+ comp.form.get('handle').patchValue('form-handle');
+
+ comp.submit();
+
+ expect(scriptDataService.invoke).toHaveBeenCalledWith('curate', [
+ {name: '-t', value: 'profileformats'},
+ {name: '-i', value: 'form-handle'},
+ {name: '-e', value: 'test@mail'},
+ ], []);
+ });
+ it('should use "all" when the handle provided by the form is empty and when no dsoHandle is provided', () => {
+
+ comp.submit();
+
+ expect(scriptDataService.invoke).toHaveBeenCalledWith('curate', [
+ {name: '-t', value: 'profileformats'},
+ {name: '-i', value: 'all'},
+ {name: '-e', value: 'test@mail'},
+ ], []);
+ });
+});
diff --git a/src/app/curation-form/curation-form.component.ts b/src/app/curation-form/curation-form.component.ts
new file mode 100644
index 0000000000..6f2d9f0b74
--- /dev/null
+++ b/src/app/curation-form/curation-form.component.ts
@@ -0,0 +1,103 @@
+import { Component, Input, OnInit } from '@angular/core';
+import { ScriptDataService } from '../core/data/processes/script-data.service';
+import { environment } from '../../environments/environment';
+import { CurationTask } from '../../config/curation-task.interface';
+import { FormControl, FormGroup } from '@angular/forms';
+import { getResponseFromEntry } from '../core/shared/operators';
+import { DSOSuccessResponse } from '../core/cache/response.models';
+import { AuthService } from '../core/auth/auth.service';
+import { filter, switchMap, take } from 'rxjs/operators';
+import { EPerson } from '../core/eperson/models/eperson.model';
+import { NotificationsService } from '../shared/notifications/notifications.service';
+import { TranslateService } from '@ngx-translate/core';
+import { hasValue, isEmpty } from '../shared/empty.util';
+import { RemoteData } from '../core/data/remote-data';
+import { Router } from '@angular/router';
+import { ProcessDataService } from '../core/data/processes/process-data.service';
+import { Process } from '../process-page/processes/process.model';
+
+/**
+ * Component responsible for rendering the Curation Task form
+ */
+@Component({
+ selector: 'ds-curation-form',
+ templateUrl: './curation-form.component.html'
+})
+export class CurationFormComponent implements OnInit {
+
+ tasks: CurationTask[];
+ form: FormGroup;
+
+ @Input()
+ dsoHandle: string;
+
+ constructor(
+ private scriptDataService: ScriptDataService,
+ private processDataService: ProcessDataService,
+ private authService: AuthService,
+ private notificationsService: NotificationsService,
+ private translateService: TranslateService,
+ private router: Router
+ ) {
+ }
+
+ ngOnInit(): void {
+ this.tasks = environment.curationTasks;
+
+ this.form = new FormGroup({
+ task: new FormControl(this.tasks[0]),
+ handle: new FormControl('')
+ });
+ }
+
+ /**
+ * Determines whether the inputted dsoHandle has a value
+ */
+ hasHandleValue() {
+ if (hasValue(this.dsoHandle)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Submit the selected taskName and handle to the script data service to run the corresponding curation script
+ * Navigate to the process page on success
+ */
+ submit() {
+ const taskName = (this.form.get('task').value as CurationTask).name;
+ let handle;
+ if (this.hasHandleValue()) {
+ handle = this.dsoHandle;
+ } else {
+ handle = this.form.get('handle').value;
+ if (isEmpty(handle)) {
+ handle = 'all';
+ }
+ }
+ this.authService.getAuthenticatedUserFromStore().pipe(
+ take(1),
+ switchMap((eperson: EPerson) => {
+ return this.scriptDataService.invoke('curate', [
+ {name: '-t', value: taskName},
+ {name: '-i', value: handle},
+ {name: '-e', value: eperson.email},
+ ], []).pipe(getResponseFromEntry());
+ })
+ ).subscribe((response: DSOSuccessResponse) => {
+ if (response.isSuccessful) {
+ this.notificationsService.success(this.translateService.get('curation.form.submit.success.head'),
+ this.translateService.get('curation.form.submit.success.content'));
+ this.processDataService.findByHref(response.resourceSelfLinks[0]).pipe(
+ filter((processRD: RemoteData) => hasValue(processRD) && hasValue(processRD.payload)),
+ take(1))
+ .subscribe((processRD: RemoteData) => {
+ this.router.navigate(['/processes', processRD.payload.processId]);
+ });
+ } else {
+ this.notificationsService.error(this.translateService.get('curation.form.submit.error.head'),
+ this.translateService.get('curation.form.submit.error.content'));
+ }
+ });
+ }
+}
diff --git a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html
index aa6290ea9f..ad270aab80 100644
--- a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html
+++ b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html
@@ -16,7 +16,9 @@
- {{ type + '.edit.return' | translate }}
+
diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts
index cc61a6d868..93192f6b72 100644
--- a/src/app/shared/shared.module.ts
+++ b/src/app/shared/shared.module.ts
@@ -207,6 +207,7 @@ import { GroupSearchBoxComponent } from './resource-policies/form/eperson-group-
import { FileDownloadLinkComponent } from './file-download-link/file-download-link.component';
import { CollectionDropdownComponent } from './collection-dropdown/collection-dropdown.component';
import { DsSelectComponent } from './ds-select/ds-select.component';
+import { CurationFormComponent } from '../curation-form/curation-form.component';
const MODULES = [
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
@@ -469,6 +470,7 @@ const ENTRY_COMPONENTS = [
ClaimedTaskActionsReturnToPoolComponent,
ClaimedTaskActionsEditMetadataComponent,
FileDownloadLinkComponent,
+ CurationFormComponent,
];
const SHARED_ITEM_PAGE_COMPONENTS = [
@@ -526,7 +528,8 @@ const DIRECTIVES = [
...PIPES,
...COMPONENTS,
...SHARED_ITEM_PAGE_COMPONENTS,
- ...DIRECTIVES
+ ...DIRECTIVES,
+ CurationFormComponent
],
entryComponents: [
...ENTRY_COMPONENTS
diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5
index b35ced7ce9..48fbe826e5 100644
--- a/src/assets/i18n/en.json5
+++ b/src/assets/i18n/en.json5
@@ -14,7 +14,11 @@
"404.page-not-found": "page not found",
+ "admin.curation-tasks.breadcrumbs": "System curation tasks",
+ "admin.curation-tasks.title": "System curation tasks",
+
+ "admin.curation-tasks.header": "System curation tasks",
"admin.registries.bitstream-formats.breadcrumbs": "Format registry",
@@ -560,6 +564,8 @@
"collection.create.sub-head": "Create a Collection for Community {{ parent }}",
+ "collection.curate.header": "Curate Collection: {{collection}}",
+
"collection.delete.cancel": "Cancel",
"collection.delete.confirm": "Confirm",
@@ -770,6 +776,8 @@
"community.create.sub-head": "Create a Sub-Community for Community {{ parent }}",
+ "community.curate.header": "Curate Community: {{community}}",
+
"community.delete.cancel": "Cancel",
"community.delete.confirm": "Confirm",
@@ -909,6 +917,32 @@
+ "curation-task.task.profileformats.label": "Profile Bitstream Formats",
+
+ "curation-task.task.requiredmetadata.label": "Check for Required Metadata",
+
+ "curation-task.task.checklinks.label": "Check Links in Metadata",
+
+
+
+ "curation.form.task-select.label": "Task: *",
+
+ "curation.form.submit": "Start",
+
+ "curation.form.submit.success.head": "The curation task has been started successfully",
+
+ "curation.form.submit.success.content": "You will be redirected to the corresponding process page.",
+
+ "curation.form.submit.error.head": "Running the curation task failed",
+
+ "curation.form.submit.error.content": "An error occured when trying to start the curation task.",
+
+ "curation.form.handle.label": "Handle of DSpace Object: *",
+
+ "curation.form.handle.hint": "Hint: Enter [your-handle-prefix]/0 to run a task across entire site (not all tasks may support this capability)",
+
+
+
"dso-selector.create.collection.head": "New collection",
"dso-selector.create.community.head": "New community",
diff --git a/src/config/curation-task.interface.ts b/src/config/curation-task.interface.ts
new file mode 100644
index 0000000000..bcdb595756
--- /dev/null
+++ b/src/config/curation-task.interface.ts
@@ -0,0 +1,9 @@
+import { Config } from './config.interface';
+
+/**
+ * An interface to represent a curation task in the configuration. A CurationTask has a name and a label.
+ */
+export interface CurationTask extends Config {
+ name: string;
+ label: string;
+}
diff --git a/src/config/global-config.interface.ts b/src/config/global-config.interface.ts
index acef3404eb..56f5f7e3c8 100644
--- a/src/config/global-config.interface.ts
+++ b/src/config/global-config.interface.ts
@@ -11,6 +11,7 @@ import { ItemPageConfig } from './item-page-config.interface';
import { CollectionPageConfig } from './collection-page-config.interface';
import { Theme } from './theme.inferface';
import {AuthConfig} from './auth-config.interfaces';
+import { CurationTask } from './curation-task.interface';
export interface GlobalConfig extends Config {
ui: ServerConfig;
@@ -31,4 +32,5 @@ export interface GlobalConfig extends Config {
item: ItemPageConfig;
collection: CollectionPageConfig;
theme: Theme;
+ curationTasks: CurationTask[];
}
diff --git a/src/environments/environment.common.ts b/src/environments/environment.common.ts
index 2b68eadcfb..bdd7e3c738 100644
--- a/src/environments/environment.common.ts
+++ b/src/environments/environment.common.ts
@@ -212,5 +212,19 @@ export const environment: GlobalConfig = {
},
theme: {
name: 'default',
- }
+ },
+ curationTasks: [
+ {
+ name: 'profileformats',
+ label: 'curation-task.task.profileformats.label'
+ },
+ {
+ name: 'requiredmetadata',
+ label: 'curation-task.task.requiredmetadata.label'
+ },
+ {
+ name: 'checklinks',
+ label: 'curation-task.task.checklinks.label'
+ }
+ ]
};
diff --git a/src/environments/mock-environment.ts b/src/environments/mock-environment.ts
index 7bf6d6c846..ad72277ed8 100644
--- a/src/environments/mock-environment.ts
+++ b/src/environments/mock-environment.ts
@@ -195,5 +195,19 @@ export const environment: Partial = {
},
theme: {
name: 'default',
- }
+ },
+ curationTasks: [
+ {
+ name: 'profileformats',
+ label: 'curation-task.task.profileformats.label'
+ },
+ {
+ name: 'requiredmetadata',
+ label: 'curation-task.task.requiredmetadata.label'
+ },
+ {
+ name: 'checklinks',
+ label: 'curation-task.task.checklinks.label'
+ }
+ ]
};