From e7302bd8af62163cee8ef1e3779ac49a94d02830 Mon Sep 17 00:00:00 2001 From: Michael W Spalti Date: Fri, 8 Nov 2019 12:04:54 -0800 Subject: [PATCH] Clear cache in mydspace redirect and reload methods. --- .../my-dspace-page.component.spec.ts | 7 ---- .../my-dspace-page.component.ts | 11 +---- src/app/shared/mocks/mock-search-service.ts | 12 ++++++ .../claimed-task-actions.component.spec.ts | 10 +++++ .../claimed-task-actions.component.ts | 10 ++++- .../item/item-actions.component.spec.ts | 10 +++++ .../item/item-actions.component.ts | 10 ++++- .../mydspace-actions/mydspace-actions.ts | 24 ++++++++--- .../pool-task-actions.component.spec.ts | 20 ++++++++++ .../pool-task/pool-task-actions.component.ts | 10 ++++- .../workflowitem-actions.component.spec.ts | 10 +++++ .../workflowitem-actions.component.ts | 11 +++-- .../workspaceitem-actions.component.spec.ts | 21 ++++++++++ .../workspaceitem-actions.component.ts | 12 ++++-- src/app/submission/submission.service.spec.ts | 11 +++++ src/app/submission/submission.service.ts | 40 ++++++++++++------- 16 files changed, 181 insertions(+), 48 deletions(-) create mode 100644 src/app/shared/mocks/mock-search-service.ts diff --git a/src/app/+my-dspace-page/my-dspace-page.component.spec.ts b/src/app/+my-dspace-page/my-dspace-page.component.spec.ts index f4b043f873..653f4a4844 100644 --- a/src/app/+my-dspace-page/my-dspace-page.component.spec.ts +++ b/src/app/+my-dspace-page/my-dspace-page.component.spec.ts @@ -15,7 +15,6 @@ import { SortDirection, SortOptions } from '../core/cache/models/sort-options.mo import { CommunityDataService } from '../core/data/community-data.service'; import { HostWindowService } from '../shared/host-window.service'; import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model'; -import { RemoteData } from '../core/data/remote-data'; import { MyDSpacePageComponent, SEARCH_CONFIG_SERVICE } from './my-dspace-page.component'; import { RouteService } from '../core/services/route.service'; import { routeServiceStub } from '../shared/testing/route-service-stub'; @@ -30,8 +29,6 @@ import { RoleService } from '../core/roles/role.service'; import { MockRoleService } from '../shared/mocks/mock-role-service'; import { SearchFixedFilterService } from '../+search-page/search-filters/search-filter/search-fixed-filter.service'; import { createSuccessfulRemoteDataObject$ } from '../shared/testing/utils'; -import { RequestService } from '../core/data/request.service'; -import { getMockRequestService } from '../shared/mocks/mock-request.service'; describe('MyDSpacePageComponent', () => { let comp: MyDSpacePageComponent; @@ -129,10 +126,6 @@ describe('MyDSpacePageComponent', () => { { provide: SearchFixedFilterService, useValue: mockFixedFilterService - }, - { - provide: RequestService, - useValue: getMockRequestService() } ], schemas: [NO_ERRORS_SCHEMA] diff --git a/src/app/+my-dspace-page/my-dspace-page.component.ts b/src/app/+my-dspace-page/my-dspace-page.component.ts index f4f813b3e6..8be9455b78 100644 --- a/src/app/+my-dspace-page/my-dspace-page.component.ts +++ b/src/app/+my-dspace-page/my-dspace-page.component.ts @@ -97,7 +97,6 @@ export class MyDSpacePageComponent implements OnInit { viewModeList = [ViewMode.List, ViewMode.Detail]; constructor(private service: SearchService, - private requestService: RequestService, private sidebarService: SearchSidebarService, private windowService: HostWindowService, @Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: MyDSpaceConfigurationService) { @@ -117,20 +116,12 @@ export class MyDSpacePageComponent implements OnInit { ngOnInit(): void { this.configurationList$ = this.searchConfigService.getAvailableConfigurationOptions(); this.searchOptions$ = this.searchConfigService.paginatedSearchOptions; - - this.sub = new Subscription(); - // This assures that the search cache is empty for each onInit. - // See https://github.com/DSpace/dspace-angular/pull/468 - const removeSub = this.service.getEndpoint() - .subscribe((url) => this.requestService.removeByHrefSubstring(url)); - const searchSub = this.searchOptions$.pipe( + this.sub = this.searchOptions$.pipe( tap(() => this.resultsRD$.next(null)), switchMap((options: PaginatedSearchOptions) => this.service.search(options).pipe(getSucceededRemoteData()))) .subscribe((results) => { this.resultsRD$.next(results); }); - this.sub.add(removeSub); - this.sub.add(searchSub); this.scopeListRD$ = this.searchConfigService.getCurrentScope('').pipe( switchMap((scopeId) => this.service.getScopes(scopeId)) diff --git a/src/app/shared/mocks/mock-search-service.ts b/src/app/shared/mocks/mock-search-service.ts new file mode 100644 index 0000000000..20da2049d1 --- /dev/null +++ b/src/app/shared/mocks/mock-search-service.ts @@ -0,0 +1,12 @@ +import { of as observableOf } from 'rxjs'; +import { SearchService } from '../../+search-page/search-service/search.service'; + +export function getMockSearchService(): SearchService { + return jasmine.createSpyObj('searchService', { + search: '', + getEndpoint: observableOf('discover/search/objects'), + getSearchLink: '/mydspace', + getScopes: observableOf(['test-scope']), + setServiceOptions: {} + }); +} diff --git a/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.spec.ts b/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.spec.ts index 5084b3e9fe..5f62d733f4 100644 --- a/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.spec.ts +++ b/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.spec.ts @@ -18,6 +18,10 @@ import { ClaimedTask } from '../../../core/tasks/models/claimed-task-object.mode import { WorkflowItem } from '../../../core/submission/models/workflowitem.model'; import { createSuccessfulRemoteDataObject } from '../../testing/utils'; import { CoreModule } from '../../../core/core.module'; +import { getMockSearchService } from '../../mocks/mock-search-service'; +import { getMockRequestService } from '../../mocks/mock-request.service'; +import { SearchService } from '../../../+search-page/search-service/search.service'; +import { RequestService } from '../../../core/data/request.service'; let component: ClaimedTaskActionsComponent; let fixture: ComponentFixture; @@ -32,6 +36,10 @@ const mockDataService = jasmine.createSpyObj('ClaimedTaskDataService', { returnToPoolTask: jasmine.createSpy('returnToPoolTask'), }); +const searchService = getMockSearchService(); + +const requestServce = getMockRequestService(); + const item = Object.assign(new Item(), { bitstreams: observableOf({}), metadata: { @@ -83,6 +91,8 @@ describe('ClaimedTaskActionsComponent', () => { { provide: NotificationsService, useValue: new NotificationsServiceStub() }, { provide: Router, useValue: new RouterStub() }, { provide: ClaimedTaskDataService, useValue: mockDataService }, + { provide: SearchService, useValue: searchService }, + { provide: RequestService, useValue: requestServce } ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(ClaimedTaskActionsComponent, { diff --git a/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.ts b/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.ts index 0ddb24ec2f..a5c236d859 100644 --- a/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.ts +++ b/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.ts @@ -13,6 +13,8 @@ import { WorkflowItem } from '../../../core/submission/models/workflowitem.model import { RemoteData } from '../../../core/data/remote-data'; import { MyDSpaceActionsComponent } from '../mydspace-actions'; import { NotificationsService } from '../../notifications/notifications.service'; +import { SearchService } from '../../../+search-page/search-service/search.service'; +import { RequestService } from '../../../core/data/request.service'; /** * This component represents mydspace actions related to ClaimedTask object. @@ -56,12 +58,16 @@ export class ClaimedTaskActionsComponent extends MyDSpaceActionsComponent; @@ -50,6 +54,10 @@ mockObject = Object.assign(new Item(), { } }); +const searchService = getMockSearchService() + +const requestServce = getMockRequestService(); + describe('ItemActionsComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ @@ -67,6 +75,8 @@ describe('ItemActionsComponent', () => { { provide: Router, useValue: new RouterStub() }, { provide: ItemDataService, useValue: mockDataService }, { provide: NotificationsService, useValue: new NotificationsServiceStub() }, + { provide: SearchService, useValue: searchService }, + { provide: RequestService, useValue: requestServce } ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(ItemActionsComponent, { diff --git a/src/app/shared/mydspace-actions/item/item-actions.component.ts b/src/app/shared/mydspace-actions/item/item-actions.component.ts index eeb6e49ad9..7f6307c5ec 100644 --- a/src/app/shared/mydspace-actions/item/item-actions.component.ts +++ b/src/app/shared/mydspace-actions/item/item-actions.component.ts @@ -7,6 +7,8 @@ import { MyDSpaceActionsComponent } from '../mydspace-actions'; import { ItemDataService } from '../../../core/data/item-data.service'; import { Item } from '../../../core/shared/item.model'; import { NotificationsService } from '../../notifications/notifications.service'; +import { SearchService } from '../../../+search-page/search-service/search.service'; +import { RequestService } from '../../../core/data/request.service'; /** * This component represents mydspace actions related to Item object. @@ -31,12 +33,16 @@ export class ItemActionsComponent extends MyDSpaceActionsComponent(); this.objectDataService = injector.get(factory.getConstructor(objectType)); } @@ -57,13 +66,18 @@ export abstract class MyDSpaceActionsComponent { return false; }; - this.router.navigated = false; - const url = decodeURIComponent(this.router.url); - this.router.navigateByUrl(url); + // This assures that the search cache is empty before reloading mydspace. + // See https://github.com/DSpace/dspace-angular/pull/468 + this.searchService.getEndpoint().pipe( + take(1), + tap((cachedHref) => this.requestService.removeByHrefSubstring(cachedHref)) + ).subscribe(() => this.router.navigateByUrl(url)); } /** diff --git a/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.spec.ts b/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.spec.ts index c06cec3422..55dcb7f8c2 100644 --- a/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.spec.ts +++ b/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.spec.ts @@ -17,6 +17,10 @@ import { PoolTaskActionsComponent } from './pool-task-actions.component'; import { PoolTask } from '../../../core/tasks/models/pool-task-object.model'; import { WorkflowItem } from '../../../core/submission/models/workflowitem.model'; import { createSuccessfulRemoteDataObject } from '../../testing/utils'; +import { getMockRequestService } from '../../mocks/mock-request.service'; +import { SearchService } from '../../../+search-page/search-service/search.service'; +import { RequestService } from '../../../core/data/request.service'; +import { getMockSearchService } from '../../mocks/mock-search-service'; let component: PoolTaskActionsComponent; let fixture: ComponentFixture; @@ -29,6 +33,10 @@ const mockDataService = jasmine.createSpyObj('PoolTaskDataService', { claimTask: jasmine.createSpy('claimTask') }); +const searchService = getMockSearchService(); + +const requestServce = getMockRequestService(); + const item = Object.assign(new Item(), { bitstreams: observableOf({}), metadata: { @@ -80,6 +88,8 @@ describe('PoolTaskActionsComponent', () => { { provide: NotificationsService, useValue: new NotificationsServiceStub() }, { provide: Router, useValue: new RouterStub() }, { provide: PoolTaskDataService, useValue: mockDataService }, + { provide: SearchService, useValue: searchService }, + { provide: RequestService, useValue: requestServce } ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(PoolTaskActionsComponent, { @@ -167,4 +177,14 @@ describe('PoolTaskActionsComponent', () => { }); })); + it('should clear the object cache by href', async(() => { + component.reload(); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + expect(searchService.getEndpoint).toHaveBeenCalled(); + expect(requestServce.removeByHrefSubstring).toHaveBeenCalledWith('discover/search/objects'); + }); + })); + }); diff --git a/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.ts b/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.ts index 2124c0d9b6..b284be6f0b 100644 --- a/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.ts +++ b/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.ts @@ -13,6 +13,8 @@ import { PoolTaskDataService } from '../../../core/tasks/pool-task-data.service' import { isNotUndefined } from '../../empty.util'; import { MyDSpaceActionsComponent } from '../mydspace-actions'; import { NotificationsService } from '../../notifications/notifications.service'; +import { SearchService } from '../../../+search-page/search-service/search.service'; +import { RequestService } from '../../../core/data/request.service'; /** * This component represents mydspace actions related to PoolTask object. @@ -47,12 +49,16 @@ export class PoolTaskActionsComponent extends MyDSpaceActionsComponent; @@ -23,6 +27,10 @@ let mockObject: WorkflowItem; const mockDataService = {}; +const searchService = getMockSearchService(); + +const requestServce = getMockRequestService(); + const item = Object.assign(new Item(), { bitstreams: observableOf({}), metadata: { @@ -72,6 +80,8 @@ describe('WorkflowitemActionsComponent', () => { { provide: Router, useValue: new RouterStub() }, { provide: WorkflowItemDataService, useValue: mockDataService }, { provide: NotificationsService, useValue: new NotificationsServiceStub() }, + { provide: SearchService, useValue: searchService }, + { provide: RequestService, useValue: requestServce } ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(WorkflowitemActionsComponent, { diff --git a/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.ts b/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.ts index 71f854c5e7..b1482b43be 100644 --- a/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.ts +++ b/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.ts @@ -7,6 +7,8 @@ import { MyDSpaceActionsComponent } from '../mydspace-actions'; import { WorkflowItem } from '../../../core/submission/models/workflowitem.model'; import { WorkflowItemDataService } from '../../../core/submission/workflowitem-data.service'; import { NotificationsService } from '../../notifications/notifications.service'; +import { SearchService } from '../../../+search-page/search-service/search.service'; +import { RequestService } from '../../../core/data/request.service'; /** * This component represents mydspace actions related to WorkflowItem object. @@ -30,12 +32,16 @@ export class WorkflowitemActionsComponent extends MyDSpaceActionsComponent; @@ -28,6 +32,10 @@ const mockDataService = jasmine.createSpyObj('WorkspaceitemDataService', { delete: jasmine.createSpy('delete') }); +const searchService = getMockSearchService(); + +const requestServce = getMockRequestService(); + const item = Object.assign(new Item(), { bitstreams: observableOf({}), metadata: { @@ -62,6 +70,7 @@ mockObject = Object.assign(new WorkspaceItem(), { item: observableOf(rd), id: '1 describe('WorkspaceitemActionsComponent', () => { beforeEach(async(() => { + TestBed.configureTestingModule({ imports: [ NgbModule.forRoot(), @@ -78,6 +87,8 @@ describe('WorkspaceitemActionsComponent', () => { { provide: NotificationsService, useValue: new NotificationsServiceStub() }, { provide: Router, useValue: new RouterStub() }, { provide: WorkspaceitemDataService, useValue: mockDataService }, + { provide: SearchService, useValue: searchService }, + { provide: RequestService, useValue: requestServce }, NgbModal ], schemas: [NO_ERRORS_SCHEMA] @@ -161,4 +172,14 @@ describe('WorkspaceitemActionsComponent', () => { expect(notificationsServiceStub.error).toHaveBeenCalled(); }); })); + + it('should clear the object cache by href', async(() => { + component.reload(); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + expect(searchService.getEndpoint).toHaveBeenCalled(); + expect(requestServce.removeByHrefSubstring).toHaveBeenCalledWith('discover/search/objects'); + }); + })); }); diff --git a/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts b/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts index 69214e800e..0c5c377490 100644 --- a/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts +++ b/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts @@ -1,4 +1,4 @@ -import { Component, Injector, Input } from '@angular/core'; +import { Component, Injector, Input, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { BehaviorSubject } from 'rxjs'; @@ -10,6 +10,8 @@ import { MyDSpaceActionsComponent } from '../mydspace-actions'; import { WorkspaceitemDataService } from '../../../core/submission/workspaceitem-data.service'; import { ResourceType } from '../../../core/shared/resource-type'; import { NotificationsService } from '../../notifications/notifications.service'; +import { SearchService } from '../../../+search-page/search-service/search.service'; +import { RequestService } from '../../../core/data/request.service'; /** * This component represents mydspace actions related to WorkspaceItem object. @@ -40,13 +42,17 @@ export class WorkspaceitemActionsComponent extends MyDSpaceActionsComponent { const config = MOCK_SUBMISSION_CONFIG; @@ -349,7 +353,12 @@ describe('SubmissionService test suite', () => { let scheduler: TestScheduler; let service: SubmissionService; + const searchService = getMockSearchService(); + + const requestServce = getMockRequestService(); + beforeEach(async(() => { + TestBed.configureTestingModule({ imports: [ StoreModule.forRoot({ submissionReducers } as any), @@ -365,6 +374,8 @@ describe('SubmissionService test suite', () => { { provide: Router, useValue: router }, { provide: SubmissionRestService, useValue: restService }, { provide: ActivatedRoute, useValue: new MockActivatedRoute() }, + { provide: SearchService, useValue: searchService }, + { provide: RequestService, useValue: requestServce }, NotificationsService, RouteService, SubmissionService, diff --git a/src/app/submission/submission.service.ts b/src/app/submission/submission.service.ts index 7605f1c73a..c9be658b31 100644 --- a/src/app/submission/submission.service.ts +++ b/src/app/submission/submission.service.ts @@ -4,13 +4,12 @@ import { Router } from '@angular/router'; import { Observable, of as observableOf, Subscription, timer as observableTimer } from 'rxjs'; import { - catchError, + catchError, concatMap, distinctUntilChanged, filter, find, - first, map, - startWith + startWith, take, tap } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { TranslateService } from '@ngx-translate/core'; @@ -56,6 +55,8 @@ import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../shared/testing/utils'; +import { SearchService } from '../+search-page/search-service/search.service'; +import { RequestService } from '../core/data/request.service'; /** * A service that provides methods used in submission process. @@ -82,6 +83,8 @@ export class SubmissionService { * @param {RouteService} routeService * @param {Store} store * @param {TranslateService} translate + * @param {SearchService} searchService + * @param {RequestService} requestService */ constructor(@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig, protected notificationsService: NotificationsService, @@ -89,7 +92,9 @@ export class SubmissionService { protected router: Router, protected routeService: RouteService, protected store: Store, - protected translate: TranslateService) { + protected translate: TranslateService, + protected searchService: SearchService, + protected requestService: RequestService) { } /** @@ -460,16 +465,23 @@ export class SubmissionService { * Redirect to MyDspace page */ redirectToMyDSpace() { - this.routeService.getPreviousUrl().pipe( - first() - ).subscribe((previousUrl: string) => { - if (isEmpty(previousUrl) || !previousUrl.startsWith('/mydspace')) { - this.router.navigate(['/mydspace']); - } else { - this.router.navigateByUrl(previousUrl); - } - }); - + // This assures that the cache is empty before redirecting to mydspace. + // See https://github.com/DSpace/dspace-angular/pull/468 + this.searchService.getEndpoint().pipe( + take(1), + tap((url) => this.requestService.removeByHrefSubstring(url)), + // Now, do redirect. + concatMap( + () => this.routeService.getPreviousUrl().pipe( + take(1), + tap((previousUrl) => { + if (isEmpty(previousUrl) || !previousUrl.startsWith('/mydspace')) { + this.router.navigate(['/mydspace']); + } else { + this.router.navigateByUrl(previousUrl); + } + }))) + ).subscribe(); } /**