diff --git a/resources/i18n/en.json b/resources/i18n/en.json
index 5e8450eb80..bc466c54b0 100644
--- a/resources/i18n/en.json
+++ b/resources/i18n/en.json
@@ -29,11 +29,22 @@
}
},
"edit": {
- "head": "Edit Collection"
+ "head": "Edit Collection",
+ "delete": "Delete this collection"
},
"create": {
"head": "Create a Collection",
"sub-head": "Create a Collection for Community {{ parent }}"
+ },
+ "delete": {
+ "head": "Delete Collection",
+ "text": "Are you sure you want to delete collection \"{{ dso }}\"",
+ "confirm": "Confirm",
+ "cancel": "Cancel",
+ "notification": {
+ "success": "Successfully deleted collection",
+ "fail": "Collection could not be deleted"
+ }
}
},
"community": {
@@ -60,11 +71,22 @@
}
},
"edit": {
- "head": "Edit Community"
+ "head": "Edit Community",
+ "delete": "Delete this community"
},
"create": {
"head": "Create a Community",
"sub-head": "Create a Sub-Community for Community {{ parent }}"
+ },
+ "delete": {
+ "head": "Delete Community",
+ "text": "Are you sure you want to delete community \"{{ dso }}\"",
+ "confirm": "Confirm",
+ "cancel": "Cancel",
+ "notification": {
+ "success": "Successfully deleted community",
+ "fail": "Community could not be deleted"
+ }
}
},
"item": {
diff --git a/src/app/+collection-page/collection-page-routing.module.ts b/src/app/+collection-page/collection-page-routing.module.ts
index ec53796e61..ddcf36a0cc 100644
--- a/src/app/+collection-page/collection-page-routing.module.ts
+++ b/src/app/+collection-page/collection-page-routing.module.ts
@@ -7,6 +7,7 @@ import { CreateCollectionPageComponent } from './create-collection-page/create-c
import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
import { EditCollectionPageComponent } from './edit-collection-page/edit-collection-page.component';
import { CreateCollectionPageGuard } from './create-collection-page/create-collection-page.guard';
+import { DeleteCollectionPageComponent } from './delete-collection-page/delete-collection-page.component';
@NgModule({
imports: [
@@ -25,6 +26,15 @@ import { CreateCollectionPageGuard } from './create-collection-page/create-colle
dso: CollectionPageResolver
}
},
+ {
+ path: ':id/delete',
+ pathMatch: 'full',
+ component: DeleteCollectionPageComponent,
+ canActivate: [AuthenticatedGuard],
+ resolve: {
+ dso: CollectionPageResolver
+ }
+ },
{
path: ':id',
component: CollectionPageComponent,
diff --git a/src/app/+collection-page/collection-page.module.ts b/src/app/+collection-page/collection-page.module.ts
index 63a03f4299..8424cc02a4 100644
--- a/src/app/+collection-page/collection-page.module.ts
+++ b/src/app/+collection-page/collection-page.module.ts
@@ -9,6 +9,7 @@ import { CreateCollectionPageComponent } from './create-collection-page/create-c
import { CollectionFormComponent } from './collection-form/collection-form.component';
import { SearchPageModule } from '../+search-page/search-page.module';
import { EditCollectionPageComponent } from './edit-collection-page/edit-collection-page.component';
+import { DeleteCollectionPageComponent } from './delete-collection-page/delete-collection-page.component';
@NgModule({
imports: [
@@ -21,6 +22,7 @@ import { EditCollectionPageComponent } from './edit-collection-page/edit-collect
CollectionPageComponent,
CreateCollectionPageComponent,
EditCollectionPageComponent,
+ DeleteCollectionPageComponent,
CollectionFormComponent
]
})
diff --git a/src/app/+collection-page/delete-collection-page/delete-collection-page.component.html b/src/app/+collection-page/delete-collection-page/delete-collection-page.component.html
new file mode 100644
index 0000000000..cfd09f2bbd
--- /dev/null
+++ b/src/app/+collection-page/delete-collection-page/delete-collection-page.component.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
{{ 'community.delete.text' | translate:{ dso: dso.name } }}
+
+
+
+
+
+
+
+
diff --git a/src/app/+collection-page/delete-collection-page/delete-collection-page.component.scss b/src/app/+collection-page/delete-collection-page/delete-collection-page.component.scss
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/src/app/+collection-page/delete-collection-page/delete-collection-page.component.scss
@@ -0,0 +1 @@
+
diff --git a/src/app/+collection-page/delete-collection-page/delete-collection-page.component.spec.ts b/src/app/+collection-page/delete-collection-page/delete-collection-page.component.spec.ts
new file mode 100644
index 0000000000..d64c1d1915
--- /dev/null
+++ b/src/app/+collection-page/delete-collection-page/delete-collection-page.component.spec.ts
@@ -0,0 +1,41 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ActivatedRoute, Router } from '@angular/router';
+import { TranslateModule } from '@ngx-translate/core';
+import { CommonModule } from '@angular/common';
+import { RouterTestingModule } from '@angular/router/testing';
+import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { SharedModule } from '../../shared/shared.module';
+import { of as observableOf } from 'rxjs';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { DeleteCollectionPageComponent } from './delete-collection-page.component';
+import { CollectionDataService } from '../../core/data/collection-data.service';
+
+describe('DeleteCollectionPageComponent', () => {
+ let comp: DeleteCollectionPageComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
+ declarations: [DeleteCollectionPageComponent],
+ providers: [
+ { provide: CollectionDataService, useValue: {} },
+ { provide: ActivatedRoute, useValue: { data: observableOf({ dso: { payload: {} } }) } },
+ { provide: NotificationsService, useValue: {} },
+ ],
+ schemas: [NO_ERRORS_SCHEMA]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(DeleteCollectionPageComponent);
+ comp = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ describe('frontendURL', () => {
+ it('should have the right frontendURL set', () => {
+ expect((comp as any).frontendURL).toEqual('/collections/');
+ })
+ });
+});
diff --git a/src/app/+collection-page/delete-collection-page/delete-collection-page.component.ts b/src/app/+collection-page/delete-collection-page/delete-collection-page.component.ts
new file mode 100644
index 0000000000..80abb83694
--- /dev/null
+++ b/src/app/+collection-page/delete-collection-page/delete-collection-page.component.ts
@@ -0,0 +1,33 @@
+import { Component } from '@angular/core';
+import { Community } from '../../core/shared/community.model';
+import { CommunityDataService } from '../../core/data/community-data.service';
+import { ActivatedRoute, Router } from '@angular/router';
+import { NormalizedCommunity } from '../../core/cache/models/normalized-community.model';
+import { DeleteComColPageComponent } from '../../shared/comcol-forms/delete-comcol-page/delete-comcol-page.component';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { CollectionDataService } from '../../core/data/collection-data.service';
+import { NormalizedCollection } from '../../core/cache/models/normalized-collection.model';
+import { Collection } from '../../core/shared/collection.model';
+import { TranslateService } from '@ngx-translate/core';
+
+/**
+ * Component that represents the page where a user can delete an existing Collection
+ */
+@Component({
+ selector: 'ds-delete-collection',
+ styleUrls: ['./delete-collection-page.component.scss'],
+ templateUrl: './delete-collection-page.component.html'
+})
+export class DeleteCollectionPageComponent extends DeleteComColPageComponent {
+ protected frontendURL = '/collections/';
+
+ public constructor(
+ protected dsoDataService: CollectionDataService,
+ protected router: Router,
+ protected route: ActivatedRoute,
+ protected notifications: NotificationsService,
+ protected translate: TranslateService
+ ) {
+ super(dsoDataService, router, route, notifications, translate);
+ }
+}
diff --git a/src/app/+collection-page/edit-collection-page/edit-collection-page.component.html b/src/app/+collection-page/edit-collection-page/edit-collection-page.component.html
index 1308af919f..c389c681ce 100644
--- a/src/app/+collection-page/edit-collection-page/edit-collection-page.component.html
+++ b/src/app/+collection-page/edit-collection-page/edit-collection-page.component.html
@@ -1,8 +1,11 @@
diff --git a/src/app/+collection-page/edit-collection-page/edit-collection-page.component.spec.ts b/src/app/+collection-page/edit-collection-page/edit-collection-page.component.spec.ts
index 6b01f13574..193cb293e4 100644
--- a/src/app/+collection-page/edit-collection-page/edit-collection-page.component.spec.ts
+++ b/src/app/+collection-page/edit-collection-page/edit-collection-page.component.spec.ts
@@ -1,11 +1,10 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { ActivatedRoute, Router } from '@angular/router';
+import { ActivatedRoute } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
import { CommonModule } from '@angular/common';
import { RouterTestingModule } from '@angular/router/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { EditCollectionPageComponent } from './edit-collection-page.component';
-import { RouteService } from '../../shared/services/route.service';
import { SharedModule } from '../../shared/shared.module';
import { CollectionDataService } from '../../core/data/collection-data.service';
import { of as observableOf } from 'rxjs';
@@ -20,9 +19,7 @@ describe('EditCollectionPageComponent', () => {
declarations: [EditCollectionPageComponent],
providers: [
{ provide: CollectionDataService, useValue: {} },
- { provide: RouteService, useValue: {} },
- { provide: Router, useValue: {} },
- { provide: ActivatedRoute, useValue: { data: observableOf({dso: undefined}) } },
+ { provide: ActivatedRoute, useValue: { data: observableOf({ dso: { payload: {} } }) } },
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
diff --git a/src/app/+collection-page/edit-collection-page/edit-collection-page.component.ts b/src/app/+collection-page/edit-collection-page/edit-collection-page.component.ts
index 2ffb4925a0..9bbdbfb9a1 100644
--- a/src/app/+collection-page/edit-collection-page/edit-collection-page.component.ts
+++ b/src/app/+collection-page/edit-collection-page/edit-collection-page.component.ts
@@ -1,5 +1,4 @@
import { Component } from '@angular/core';
-import { RouteService } from '../../shared/services/route.service';
import { ActivatedRoute, Router } from '@angular/router';
import { EditComColPageComponent } from '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component';
import { NormalizedCollection } from '../../core/cache/models/normalized-collection.model';
@@ -19,10 +18,9 @@ export class EditCollectionPageComponent extends EditComColPageComponent
+
+
+
+
+
{{ 'community.delete.text' | translate:{ dso: dso.name } }}
+
+
+
+
+
+
+
+
diff --git a/src/app/+community-page/delete-community-page/delete-community-page.component.scss b/src/app/+community-page/delete-community-page/delete-community-page.component.scss
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/src/app/+community-page/delete-community-page/delete-community-page.component.scss
@@ -0,0 +1 @@
+
diff --git a/src/app/+community-page/delete-community-page/delete-community-page.component.spec.ts b/src/app/+community-page/delete-community-page/delete-community-page.component.spec.ts
new file mode 100644
index 0000000000..f18c4fb1f1
--- /dev/null
+++ b/src/app/+community-page/delete-community-page/delete-community-page.component.spec.ts
@@ -0,0 +1,42 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ActivatedRoute, Router } from '@angular/router';
+import { TranslateModule } from '@ngx-translate/core';
+import { CommonModule } from '@angular/common';
+import { RouterTestingModule } from '@angular/router/testing';
+import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { RouteService } from '../../shared/services/route.service';
+import { SharedModule } from '../../shared/shared.module';
+import { of as observableOf } from 'rxjs';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { DeleteCommunityPageComponent } from './delete-community-page.component';
+import { CommunityDataService } from '../../core/data/community-data.service';
+
+describe('DeleteCommunityPageComponent', () => {
+ let comp: DeleteCommunityPageComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
+ declarations: [DeleteCommunityPageComponent],
+ providers: [
+ { provide: CommunityDataService, useValue: {} },
+ { provide: ActivatedRoute, useValue: { data: observableOf({ dso: { payload: {} } }) } },
+ { provide: NotificationsService, useValue: {} },
+ ],
+ schemas: [NO_ERRORS_SCHEMA]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(DeleteCommunityPageComponent);
+ comp = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ describe('frontendURL', () => {
+ it('should have the right frontendURL set', () => {
+ expect((comp as any).frontendURL).toEqual('/communities/');
+ })
+ });
+});
diff --git a/src/app/+community-page/delete-community-page/delete-community-page.component.ts b/src/app/+community-page/delete-community-page/delete-community-page.component.ts
new file mode 100644
index 0000000000..01741a7577
--- /dev/null
+++ b/src/app/+community-page/delete-community-page/delete-community-page.component.ts
@@ -0,0 +1,30 @@
+import { Component } from '@angular/core';
+import { Community } from '../../core/shared/community.model';
+import { CommunityDataService } from '../../core/data/community-data.service';
+import { ActivatedRoute, Router } from '@angular/router';
+import { NormalizedCommunity } from '../../core/cache/models/normalized-community.model';
+import { DeleteComColPageComponent } from '../../shared/comcol-forms/delete-comcol-page/delete-comcol-page.component';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { TranslateService } from '@ngx-translate/core';
+
+/**
+ * Component that represents the page where a user can delete an existing Community
+ */
+@Component({
+ selector: 'ds-delete-community',
+ styleUrls: ['./delete-community-page.component.scss'],
+ templateUrl: './delete-community-page.component.html'
+})
+export class DeleteCommunityPageComponent extends DeleteComColPageComponent {
+ protected frontendURL = '/communities/';
+
+ public constructor(
+ protected dsoDataService: CommunityDataService,
+ protected router: Router,
+ protected route: ActivatedRoute,
+ protected notifications: NotificationsService,
+ protected translate: TranslateService
+ ) {
+ super(dsoDataService, router, route, notifications, translate);
+ }
+}
diff --git a/src/app/+community-page/edit-community-page/edit-community-page.component.html b/src/app/+community-page/edit-community-page/edit-community-page.component.html
index 98649243cc..cedb771c14 100644
--- a/src/app/+community-page/edit-community-page/edit-community-page.component.html
+++ b/src/app/+community-page/edit-community-page/edit-community-page.component.html
@@ -1,8 +1,12 @@
-
diff --git a/src/app/+community-page/edit-community-page/edit-community-page.component.spec.ts b/src/app/+community-page/edit-community-page/edit-community-page.component.spec.ts
index 764cffe8b5..54f2133ce7 100644
--- a/src/app/+community-page/edit-community-page/edit-community-page.component.spec.ts
+++ b/src/app/+community-page/edit-community-page/edit-community-page.component.spec.ts
@@ -1,10 +1,9 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { ActivatedRoute, Router } from '@angular/router';
+import { ActivatedRoute } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
import { CommonModule } from '@angular/common';
import { RouterTestingModule } from '@angular/router/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
-import { RouteService } from '../../shared/services/route.service';
import { SharedModule } from '../../shared/shared.module';
import { of as observableOf } from 'rxjs';
import { EditCommunityPageComponent } from './edit-community-page.component';
@@ -20,9 +19,7 @@ describe('EditCommunityPageComponent', () => {
declarations: [EditCommunityPageComponent],
providers: [
{ provide: CommunityDataService, useValue: {} },
- { provide: RouteService, useValue: {} },
- { provide: Router, useValue: {} },
- { provide: ActivatedRoute, useValue: { data: observableOf({dso: undefined}) } },
+ { provide: ActivatedRoute, useValue: { data: observableOf({ dso: { payload: {} } }) } },
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
diff --git a/src/app/+community-page/edit-community-page/edit-community-page.component.ts b/src/app/+community-page/edit-community-page/edit-community-page.component.ts
index 8db5eab204..68f092e915 100644
--- a/src/app/+community-page/edit-community-page/edit-community-page.component.ts
+++ b/src/app/+community-page/edit-community-page/edit-community-page.component.ts
@@ -1,7 +1,6 @@
import { Component } from '@angular/core';
import { Community } from '../../core/shared/community.model';
import { CommunityDataService } from '../../core/data/community-data.service';
-import { RouteService } from '../../shared/services/route.service';
import { ActivatedRoute, Router } from '@angular/router';
import { NormalizedCommunity } from '../../core/cache/models/normalized-community.model';
import { EditComColPageComponent } from '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component';
@@ -19,10 +18,9 @@ export class EditCommunityPageComponent extends EditComColPageComponent
{
beforeEach(async(() => {
@@ -46,14 +44,12 @@ describe('ItemDeleteComponent', () => {
});
mockItemDataService = jasmine.createSpyObj('mockItemDataService', {
- delete: observableOf(new RestResponse(true, '200'))
+ delete: observableOf(true)
});
routeStub = {
data: observableOf({
- item: new RemoteData(false, false, true, null, {
- id: 'fake-id'
- })
+ item: new RemoteData(false, false, true, null, mockItem)
})
};
@@ -63,10 +59,10 @@ describe('ItemDeleteComponent', () => {
imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
declarations: [ItemDeleteComponent],
providers: [
- {provide: ActivatedRoute, useValue: routeStub},
- {provide: Router, useValue: routerStub},
- {provide: ItemDataService, useValue: mockItemDataService},
- {provide: NotificationsService, useValue: notificationsServiceStub},
+ { provide: ActivatedRoute, useValue: routeStub },
+ { provide: Router, useValue: routerStub },
+ { provide: ItemDataService, useValue: mockItemDataService },
+ { provide: NotificationsService, useValue: notificationsServiceStub },
], schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
@@ -74,9 +70,6 @@ describe('ItemDeleteComponent', () => {
}));
beforeEach(() => {
- successfulRestResponse = new RestResponse(true, '200');
- failRestResponse = new RestResponse(false, '500');
-
fixture = TestBed.createComponent(ItemDeleteComponent);
comp = fixture.componentInstance;
fixture.detectChanges();
@@ -95,22 +88,21 @@ describe('ItemDeleteComponent', () => {
describe('performAction', () => {
it('should call delete function from the ItemDataService', () => {
- spyOn(comp, 'processRestResponse');
+ spyOn(comp, 'notify');
comp.performAction();
-
- expect(mockItemDataService.delete).toHaveBeenCalledWith(mockItem.id);
- expect(comp.processRestResponse).toHaveBeenCalled();
+ expect(mockItemDataService.delete).toHaveBeenCalledWith(mockItem);
+ expect(comp.notify).toHaveBeenCalled();
});
});
- describe('processRestResponse', () => {
+ describe('notify', () => {
it('should navigate to the homepage on successful deletion of the item', () => {
- comp.processRestResponse(successfulRestResponse);
+ comp.notify(true);
expect(routerStub.navigate).toHaveBeenCalledWith(['']);
});
});
- describe('processRestResponse', () => {
+ describe('notify', () => {
it('should navigate to the item edit page on failed deletion of the item', () => {
- comp.processRestResponse(failRestResponse);
+ comp.notify(false);
expect(routerStub.navigate).toHaveBeenCalledWith([getItemEditPath('fake-id')]);
});
});
diff --git a/src/app/+item-page/edit-item-page/item-delete/item-delete.component.ts b/src/app/+item-page/edit-item-page/item-delete/item-delete.component.ts
index 95f25c67bc..2700b45475 100644
--- a/src/app/+item-page/edit-item-page/item-delete/item-delete.component.ts
+++ b/src/app/+item-page/edit-item-page/item-delete/item-delete.component.ts
@@ -19,20 +19,19 @@ export class ItemDeleteComponent extends AbstractSimpleItemActionComponent {
* Perform the delete action to the item
*/
performAction() {
- this.itemDataService.delete(this.item.id).pipe(first()).subscribe(
- (response: RestResponse) => {
- this.processRestResponse(response);
+ this.itemDataService.delete(this.item).pipe(first()).subscribe(
+ (succeeded: boolean) => {
+ this.notify(succeeded);
}
);
}
/**
- * Process the RestResponse retrieved from the server.
* When the item is successfully delete, navigate to the homepage, otherwise navigate back to the item edit page
* @param response
*/
- processRestResponse(response: RestResponse) {
- if (response.isSuccessful) {
+ notify(succeeded: boolean) {
+ if (succeeded) {
this.notificationsService.success(this.translateService.get('item.edit.' + this.messageKey + '.success'));
this.router.navigate(['']);
} else {
diff --git a/src/app/core/data/comcol-data.service.spec.ts b/src/app/core/data/comcol-data.service.spec.ts
index 1b520d83ce..4c20a4cfeb 100644
--- a/src/app/core/data/comcol-data.service.spec.ts
+++ b/src/app/core/data/comcol-data.service.spec.ts
@@ -86,7 +86,7 @@ describe('ComColDataService', () => {
function initMockCommunityDataService(): CommunityDataService {
return jasmine.createSpyObj('responseCache', {
getEndpoint: hot('--a-', { a: communitiesEndpoint }),
- getFindByIDHref: cold('b-', { b: communityEndpoint })
+ getIDHref: cold('b-', { b: communityEndpoint })
});
}
diff --git a/src/app/core/data/comcol-data.service.ts b/src/app/core/data/comcol-data.service.ts
index 0616e9c2ed..8a1ea51bb3 100644
--- a/src/app/core/data/comcol-data.service.ts
+++ b/src/app/core/data/comcol-data.service.ts
@@ -42,7 +42,7 @@ export abstract class ComColDataService this.cds.getFindByIDHref(endpoint, options.scopeID)),
+ mergeMap((endpoint: string) => this.cds.getIDHref(endpoint, options.scopeID)),
filter((href: string) => isNotEmpty(href)),
take(1),
tap((href: string) => {
diff --git a/src/app/core/data/data.service.ts b/src/app/core/data/data.service.ts
index c164ca8b56..136879ba7e 100644
--- a/src/app/core/data/data.service.ts
+++ b/src/app/core/data/data.service.ts
@@ -1,12 +1,12 @@
import {
- delay,
distinctUntilChanged,
filter,
find,
- switchMap,
+ first,
map,
- take,
- tap, first, mergeMap
+ mergeMap,
+ switchMap,
+ take
} from 'rxjs/operators';
import { Observable } from 'rxjs';
import { Store } from '@ngrx/store';
@@ -19,28 +19,26 @@ import { PaginatedList } from './paginated-list';
import { RemoteData } from './remote-data';
import {
CreateRequest,
+ DeleteByIDRequest,
FindAllOptions,
FindAllRequest,
FindByIDRequest,
- GetRequest, RestRequest
+ GetRequest
} from './request.models';
import { RequestService } from './request.service';
import { NormalizedObject } from '../cache/models/normalized-object.model';
-import { compare, Operation } from 'fast-json-patch';
+import { Operation } from 'fast-json-patch';
import { ObjectCacheService } from '../cache/object-cache.service';
import { DSpaceObject } from '../shared/dspace-object.model';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { HttpClient } from '@angular/common/http';
-import {
- configureRequest,
- filterSuccessfulResponses, getResourceLinksFromResponse,
- getResponseFromEntry
-} from '../shared/operators';
-import { DSOSuccessResponse, ErrorResponse, RestResponse } from '../cache/response.models';
+import { configureRequest, getResponseFromEntry } from '../shared/operators';
+import { ErrorResponse, RestResponse } from '../cache/response.models';
import { NotificationOptions } from '../../shared/notifications/models/notification-options.model';
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
import { NormalizedObjectFactory } from '../cache/models/normalized-object-factory';
import { CacheableObject } from '../cache/object-cache.reducer';
+import { RequestEntry } from './request.reducer';
import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
import { ChangeAnalyzer } from './change-analyzer';
@@ -97,13 +95,18 @@ export abstract class DataService(hrefObs) as Observable>>;
}
- getFindByIDHref(endpoint, resourceID): string {
+ /**
+ * Create the HREF for a specific object based on its identifier
+ * @param endpoint The base endpoint for the type of object
+ * @param resourceID The identifier for the object
+ */
+ getIDHref(endpoint, resourceID): string {
return `${endpoint}/${resourceID}`;
}
findById(id: string): Observable> {
const hrefObs = this.halService.getEndpoint(this.linkPath).pipe(
- map((endpoint: string) => this.getFindByIDHref(endpoint, id)));
+ map((endpoint: string) => this.getIDHref(endpoint, id)));
hrefObs.pipe(
find((href: string) => hasValue(href)))
@@ -201,4 +204,29 @@ export abstract class DataService {
+ const requestId = this.requestService.generateRequestId();
+
+ const hrefObs = this.halService.getEndpoint(this.linkPath).pipe(
+ map((endpoint: string) => this.getIDHref(endpoint, dso.uuid)));
+
+ hrefObs.pipe(
+ find((href: string) => hasValue(href)),
+ map((href: string) => {
+ const request = new DeleteByIDRequest(requestId, href, dso.uuid);
+ this.requestService.configure(request);
+ })
+ ).subscribe();
+
+ return this.requestService.getByUUID(requestId).pipe(
+ find((request: RequestEntry) => request.completed),
+ map((request: RequestEntry) => request.response.isSuccessful)
+ );
+ }
+
}
diff --git a/src/app/core/data/dspace-object-data.service.ts b/src/app/core/data/dspace-object-data.service.ts
index d485fd0bc4..86ce9be7a9 100644
--- a/src/app/core/data/dspace-object-data.service.ts
+++ b/src/app/core/data/dspace-object-data.service.ts
@@ -37,7 +37,7 @@ class DataServiceImpl extends DataService
return this.halService.getEndpoint(linkPath);
}
- getFindByIDHref(endpoint, resourceID): string {
+ getIDHref(endpoint, resourceID): string {
return endpoint.replace(/\{\?uuid\}/,`?uuid=${resourceID}`);
}
}
diff --git a/src/app/core/data/item-data.service.spec.ts b/src/app/core/data/item-data.service.spec.ts
index 6cf7e503d3..02c70791b5 100644
--- a/src/app/core/data/item-data.service.spec.ts
+++ b/src/app/core/data/item-data.service.spec.ts
@@ -162,25 +162,4 @@ describe('ItemDataService', () => {
});
});
- describe('getItemDeleteEndpoint', () => {
- beforeEach(() => {
- scheduler = getTestScheduler();
- service = initTestService();
- });
-
- it('should return the endpoint to make an item private or public', () => {
- const result = service.getItemDeleteEndpoint(scopeID);
- const expected = cold('a', {a: ScopedItemEndpoint});
-
- expect(result).toBeObservable(expected);
- });
-
- it('should delete the item', () => {
- const expected = new RestResponse(true, '200');
- const result = service.delete(scopeID);
- result.subscribe((v) => expect(v).toEqual(expected));
-
- });
- });
-
});
diff --git a/src/app/core/data/item-data.service.ts b/src/app/core/data/item-data.service.ts
index c67b49f70d..bd3c42a67c 100644
--- a/src/app/core/data/item-data.service.ts
+++ b/src/app/core/data/item-data.service.ts
@@ -14,7 +14,7 @@ import { URLCombiner } from '../url-combiner/url-combiner';
import { DataService } from './data.service';
import { RequestService } from './request.service';
import { HALEndpointService } from '../shared/hal-endpoint.service';
-import { DeleteRequest, FindAllOptions, PatchRequest, RestRequest } from './request.models';
+import { FindAllOptions, PatchRequest, RestRequest } from './request.models';
import { ObjectCacheService } from '../cache/object-cache.service';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { HttpClient } from '@angular/common/http';
@@ -64,7 +64,7 @@ export class ItemDataService extends DataService {
*/
public getItemWithdrawEndpoint(itemId: string): Observable {
return this.halService.getEndpoint(this.linkPath).pipe(
- map((endpoint: string) => this.getFindByIDHref(endpoint, itemId))
+ map((endpoint: string) => this.getIDHref(endpoint, itemId))
);
}
@@ -74,17 +74,7 @@ export class ItemDataService extends DataService {
*/
public getItemDiscoverableEndpoint(itemId: string): Observable {
return this.halService.getEndpoint(this.linkPath).pipe(
- map((endpoint: string) => this.getFindByIDHref(endpoint, itemId))
- );
- }
-
- /**
- * Get the endpoint to delete the item
- * @param itemId
- */
- public getItemDeleteEndpoint(itemId: string): Observable {
- return this.halService.getEndpoint(this.linkPath).pipe(
- map((endpoint: string) => this.getFindByIDHref(endpoint, itemId))
+ map((endpoint: string) => this.getIDHref(endpoint, itemId))
);
}
@@ -129,22 +119,4 @@ export class ItemDataService extends DataService {
map((requestEntry: RequestEntry) => requestEntry.response)
);
}
-
- /**
- * Delete the item
- * @param itemId
- */
- public delete(itemId: string) {
- return this.getItemDeleteEndpoint(itemId).pipe(
- distinctUntilChanged(),
- map((endpointURL: string) =>
- new DeleteRequest(this.requestService.generateRequestId(), endpointURL)
- ),
- configureRequest(this.requestService),
- map((request: RestRequest) => request.href),
- getRequestFromRequestHref(this.requestService),
- map((requestEntry: RequestEntry) => requestEntry.response)
- );
- }
-
}
diff --git a/src/app/core/data/request.models.ts b/src/app/core/data/request.models.ts
index 6c4c89e492..e4920058ac 100644
--- a/src/app/core/data/request.models.ts
+++ b/src/app/core/data/request.models.ts
@@ -227,6 +227,19 @@ export class CreateRequest extends PostRequest {
}
}
+/**
+ * Request to delete an object based on its identifier
+ */
+export class DeleteByIDRequest extends DeleteRequest {
+ constructor(
+ uuid: string,
+ href: string,
+ public resourceID: string
+ ) {
+ super(uuid, href);
+ }
+}
+
export class RequestError extends Error {
statusText: string;
}
diff --git a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts
index f8bed5b814..fc7ee3ee70 100644
--- a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts
+++ b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts
@@ -21,7 +21,7 @@ import { NormalizedDSpaceObject } from '../../../core/cache/models/normalized-ds
})
export class CreateComColPageComponent implements OnInit {
/**
- * Frontend endpoint where for this type of DSP
+ * Frontend endpoint for this type of DSO
*/
protected frontendURL: string;
diff --git a/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.spec.ts b/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.spec.ts
new file mode 100644
index 0000000000..81ec9c47a0
--- /dev/null
+++ b/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.spec.ts
@@ -0,0 +1,155 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { CommunityDataService } from '../../../core/data/community-data.service';
+import { ActivatedRoute, Router } from '@angular/router';
+import { TranslateModule } from '@ngx-translate/core';
+import { of as observableOf } from 'rxjs';
+import { Community } from '../../../core/shared/community.model';
+import { SharedModule } from '../../shared.module';
+import { CommonModule } from '@angular/common';
+import { RouterTestingModule } from '@angular/router/testing';
+import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { DSpaceObject } from '../../../core/shared/dspace-object.model';
+import { NormalizedDSpaceObject } from '../../../core/cache/models/normalized-dspace-object.model';
+import { DataService } from '../../../core/data/data.service';
+import { DeleteComColPageComponent } from './delete-comcol-page.component';
+import { NotificationsService } from '../../notifications/notifications.service';
+import { NotificationsServiceStub } from '../../testing/notifications-service-stub';
+
+describe('DeleteComColPageComponent', () => {
+ let comp: DeleteComColPageComponent;
+ let fixture: ComponentFixture>;
+ let dsoDataService: CommunityDataService;
+ let router: Router;
+
+ let community;
+ let newCommunity;
+ let routerStub;
+ let routeStub;
+ let notificationsService;
+ const validUUID = 'valid-uuid';
+ const invalidUUID = 'invalid-uuid';
+ const frontendURL = '/testType';
+ function initializeVars() {
+ community = Object.assign(new Community(), {
+ uuid: 'a20da287-e174-466a-9926-f66b9300d347',
+ metadata: [{
+ key: 'dc.title',
+ value: 'test community'
+ }]
+ });
+
+ newCommunity = Object.assign(new Community(), {
+ uuid: '1ff59938-a69a-4e62-b9a4-718569c55d48',
+ metadata: [{
+ key: 'dc.title',
+ value: 'new community'
+ }]
+ });
+
+ dsoDataService = jasmine.createSpyObj(
+ 'dsoDataService',
+ {
+ delete: observableOf(true)
+ });
+
+ routerStub = {
+ navigate: (commands) => commands
+ };
+
+ routeStub = {
+ data: observableOf(community)
+ };
+
+ }
+
+ beforeEach(async(() => {
+ initializeVars();
+ TestBed.configureTestingModule({
+ imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
+ providers: [
+ { provide: DataService, useValue: dsoDataService },
+ { provide: Router, useValue: routerStub },
+ { provide: ActivatedRoute, useValue: routeStub },
+ { provide: NotificationsService, useValue: new NotificationsServiceStub() },
+ ],
+ schemas: [NO_ERRORS_SCHEMA]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(DeleteComColPageComponent);
+ comp = fixture.componentInstance;
+ fixture.detectChanges();
+ notificationsService = (comp as any).notifications;
+ (comp as any).frontendURL = frontendURL;
+ router = (comp as any).router;
+ });
+
+ describe('onConfirm', () => {
+ let data1;
+ let data2;
+ beforeEach(() => {
+ data1 = Object.assign(new Community(), {
+ uuid: validUUID,
+ metadata: [{
+ key: 'dc.title',
+ value: 'test'
+ }]
+ });
+
+ data2 = Object.assign(new Community(), {
+ uuid: invalidUUID,
+ metadata: [{
+ key: 'dc.title',
+ value: 'test'
+ }]
+ });
+ });
+
+ it('should show an error notification on failure', () => {
+ (dsoDataService.delete as any).and.returnValue(observableOf(false));
+ spyOn(notificationsService, 'error');
+ spyOn(router, 'navigate');
+ comp.onConfirm(data2);
+ fixture.detectChanges();
+ expect(notificationsService.error).toHaveBeenCalled();
+ expect(router.navigate).toHaveBeenCalled();
+ });
+
+ it('should show a success notification on success and navigate', () => {
+ spyOn(notificationsService, 'success');
+ spyOn(router, 'navigate');
+ comp.onConfirm(data1);
+ fixture.detectChanges();
+ expect(notificationsService.success).toHaveBeenCalled();
+ expect(router.navigate).toHaveBeenCalled();
+ });
+
+ it('should call delete on the data service', () => {
+ comp.onConfirm(data1);
+ fixture.detectChanges();
+ expect(dsoDataService.delete).toHaveBeenCalledWith(data1);
+ });
+ });
+
+ describe('onCancel', () => {
+ let data1;
+ beforeEach(() => {
+ data1 = Object.assign(new Community(), {
+ uuid: validUUID,
+ metadata: [{
+ key: 'dc.title',
+ value: 'test'
+ }]
+ });
+ });
+
+ it('should redirect to the edit page', () => {
+ const redirectURL = frontendURL + '/' + validUUID + '/edit';
+ spyOn(router, 'navigate');
+ comp.onCancel(data1);
+ fixture.detectChanges();
+ expect(router.navigate).toHaveBeenCalledWith([redirectURL]);
+ });
+ });
+});
diff --git a/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.ts b/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.ts
new file mode 100644
index 0000000000..6e3a826e87
--- /dev/null
+++ b/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.ts
@@ -0,0 +1,71 @@
+import { Component, OnInit } from '@angular/core';
+import { Observable } from 'rxjs';
+import { RouteService } from '../../services/route.service';
+import { ActivatedRoute, Router } from '@angular/router';
+import { RemoteData } from '../../../core/data/remote-data';
+import { isNotUndefined } from '../../empty.util';
+import { first, map } from 'rxjs/operators';
+import { getSucceededRemoteData } from '../../../core/shared/operators';
+import { DataService } from '../../../core/data/data.service';
+import { NormalizedDSpaceObject } from '../../../core/cache/models/normalized-dspace-object.model';
+import { DSpaceObject } from '../../../core/shared/dspace-object.model';
+import { NotificationsService } from '../../notifications/notifications.service';
+import { TranslateService } from '@ngx-translate/core';
+
+/**
+ * Component representing the delete page for communities and collections
+ */
+@Component({
+ selector: 'ds-delete-comcol',
+ template: ''
+})
+export class DeleteComColPageComponent implements OnInit {
+ /**
+ * Frontend endpoint for this type of DSO
+ */
+ protected frontendURL: string;
+ /**
+ * The initial DSO object
+ */
+ public dsoRD$: Observable>;
+
+ public constructor(
+ protected dsoDataService: DataService,
+ protected router: Router,
+ protected route: ActivatedRoute,
+ protected notifications: NotificationsService,
+ protected translate: TranslateService
+ ) {
+ }
+
+ ngOnInit(): void {
+ this.dsoRD$ = this.route.data.pipe(first(), map((data) => data.dso));
+ }
+
+ /**
+ * @param {TDomain} dso The DSO to delete
+ * Deletes an existing DSO and redirects to the home page afterwards, showing a notification that states whether or not the deletion was successful
+ */
+ onConfirm(dso: TDomain) {
+ this.dsoDataService.delete(dso)
+ .pipe(first())
+ .subscribe((success: boolean) => {
+ if (success) {
+ const successMessage = this.translate.instant(dso.type + '.delete.notification.success');
+ this.notifications.success(successMessage)
+ } else {
+ const errorMessage = this.translate.instant(dso.type + '.delete.notification.fail');
+ this.notifications.error(errorMessage)
+ }
+ this.router.navigate(['/']);
+ });
+ }
+
+ /**
+ * @param {TDomain} dso The DSO for which the delete action was canceled
+ * When a delete is canceled, the user is redirected to the DSO's edit page
+ */
+ onCancel(dso: TDomain) {
+ this.router.navigate([this.frontendURL + '/' + dso.uuid + '/edit']);
+ }
+}
diff --git a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts
index ae59e185a3..88c11a0b4d 100644
--- a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts
+++ b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts
@@ -1,6 +1,5 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CommunityDataService } from '../../../core/data/community-data.service';
-import { RouteService } from '../../services/route.service';
import { ActivatedRoute, Router } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
import { of as observableOf } from 'rxjs';
@@ -18,15 +17,12 @@ import { DataService } from '../../../core/data/data.service';
describe('EditComColPageComponent', () => {
let comp: EditComColPageComponent;
let fixture: ComponentFixture>;
- let communityDataService: CommunityDataService;
let dsoDataService: CommunityDataService;
- let routeService: RouteService;
let router: Router;
let community;
let newCommunity;
let communityDataServiceStub;
- let routeServiceStub;
let routerStub;
let routeStub;
@@ -48,20 +44,10 @@ describe('EditComColPageComponent', () => {
});
communityDataServiceStub = {
- findById: (uuid) => observableOf(new RemoteData(false, false, true, null, Object.assign(new Community(), {
- uuid: uuid,
- metadata: [{
- key: 'dc.title',
- value: community.name
- }]
- }))),
update: (com, uuid?) => observableOf(new RemoteData(false, false, true, undefined, newCommunity))
};
- routeServiceStub = {
- getQueryParameterValue: (param) => observableOf(community.uuid)
- };
routerStub = {
navigate: (commands) => commands
};
@@ -78,7 +64,6 @@ describe('EditComColPageComponent', () => {
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
providers: [
{ provide: DataService, useValue: communityDataServiceStub },
- { provide: RouteService, useValue: routeServiceStub },
{ provide: Router, useValue: routerStub },
{ provide: ActivatedRoute, useValue: routeStub },
],
@@ -91,8 +76,6 @@ describe('EditComColPageComponent', () => {
comp = fixture.componentInstance;
fixture.detectChanges();
dsoDataService = (comp as any).dsoDataService;
- communityDataService = (comp as any).communityDataService;
- routeService = (comp as any).routeService;
router = (comp as any).router;
});
diff --git a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts
index 5ccbcfcc66..b669fcea54 100644
--- a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts
+++ b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts
@@ -1,6 +1,5 @@
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
-import { RouteService } from '../../services/route.service';
import { ActivatedRoute, Router } from '@angular/router';
import { RemoteData } from '../../../core/data/remote-data';
import { isNotUndefined } from '../../empty.util';
@@ -19,7 +18,7 @@ import { DSpaceObject } from '../../../core/shared/dspace-object.model';
})
export class EditComColPageComponent implements OnInit {
/**
- * Frontend endpoint where for this type of DSP
+ * Frontend endpoint for this type of DSO
*/
protected frontendURL: string;
/**
@@ -29,7 +28,6 @@ export class EditComColPageComponent,
- protected routeService: RouteService,
protected router: Router,
protected route: ActivatedRoute
) {
diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts
index a7a45ccfd7..53cf15ab6e 100644
--- a/src/app/shared/shared.module.ts
+++ b/src/app/shared/shared.module.ts
@@ -89,6 +89,7 @@ import { MenuModule } from './menu/menu.module';
import { ComColFormComponent } from './comcol-forms/comcol-form/comcol-form.component';
import { CreateComColPageComponent } from './comcol-forms/create-comcol-page/create-comcol-page.component';
import { EditComColPageComponent } from './comcol-forms/edit-comcol-page/edit-comcol-page.component';
+import { DeleteComColPageComponent } from './comcol-forms/delete-comcol-page/delete-comcol-page.component';
import { LangSwitchComponent } from './lang-switch/lang-switch.component';
const MODULES = [
@@ -136,6 +137,7 @@ const COMPONENTS = [
ComColFormComponent,
CreateComColPageComponent,
EditComColPageComponent,
+ DeleteComColPageComponent,
DsDynamicFormComponent,
DsDynamicFormControlComponent,
DsDynamicListComponent,