mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
disregard embed url params when indexing and checking indexed request urls
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import { NgZone } from '@angular/core';
|
||||||
import * as ngrx from '@ngrx/store';
|
import * as ngrx from '@ngrx/store';
|
||||||
import { ActionsSubject, Store } from '@ngrx/store';
|
import { ActionsSubject, Store } from '@ngrx/store';
|
||||||
import { cold, getTestScheduler, hot } from 'jasmine-marbles';
|
import { cold, getTestScheduler, hot } from 'jasmine-marbles';
|
||||||
@@ -62,6 +63,7 @@ describe('RequestService', () => {
|
|||||||
objectCache,
|
objectCache,
|
||||||
uuidService,
|
uuidService,
|
||||||
store,
|
store,
|
||||||
|
new NgZone({}),
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
serviceAsAny = service as any;
|
serviceAsAny = service as any;
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable, NgZone } from '@angular/core';
|
||||||
import { HttpHeaders } from '@angular/common/http';
|
import { HttpHeaders } from '@angular/common/http';
|
||||||
|
|
||||||
import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store';
|
import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store';
|
||||||
import { Observable, race as observableRace } from 'rxjs';
|
import { Observable, race as observableRace } from 'rxjs';
|
||||||
import { filter, map, mergeMap, switchMap, take } from 'rxjs/operators';
|
import { filter, map, mergeMap, take } from 'rxjs/operators';
|
||||||
import { cloneDeep, remove } from 'lodash';
|
import { cloneDeep, remove } from 'lodash';
|
||||||
import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util';
|
import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util';
|
||||||
import { CacheableObject } from '../cache/object-cache.reducer';
|
import { CacheableObject } from '../cache/object-cache.reducer';
|
||||||
@@ -80,6 +80,7 @@ export class RequestService {
|
|||||||
constructor(private objectCache: ObjectCacheService,
|
constructor(private objectCache: ObjectCacheService,
|
||||||
private uuidService: UUIDService,
|
private uuidService: UUIDService,
|
||||||
private store: Store<CoreState>,
|
private store: Store<CoreState>,
|
||||||
|
private zone: NgZone,
|
||||||
private indexStore: Store<MetaIndexState>) {
|
private indexStore: Store<MetaIndexState>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,21 +148,23 @@ export class RequestService {
|
|||||||
* @param {RestRequest} request The request to send out
|
* @param {RestRequest} request The request to send out
|
||||||
*/
|
*/
|
||||||
configure<T extends CacheableObject>(request: RestRequest): void {
|
configure<T extends CacheableObject>(request: RestRequest): void {
|
||||||
const isGetRequest = request.method === RestRequestMethod.GET;
|
this.zone.runOutsideAngular(() => {
|
||||||
if (!isGetRequest || request.forceBypassCache || !this.isCachedOrPending(request)) {
|
const isGetRequest = request.method === RestRequestMethod.GET;
|
||||||
this.dispatchRequest(request);
|
if (!isGetRequest || request.forceBypassCache || !this.isCachedOrPending(request)) {
|
||||||
if (isGetRequest) {
|
this.dispatchRequest(request);
|
||||||
this.trackRequestsOnTheirWayToTheStore(request);
|
if (isGetRequest) {
|
||||||
}
|
this.trackRequestsOnTheirWayToTheStore(request);
|
||||||
} else {
|
|
||||||
this.getByHref(request.href).pipe(
|
|
||||||
filter((entry) => hasValue(entry)),
|
|
||||||
take(1)
|
|
||||||
).subscribe((entry) => {
|
|
||||||
return this.store.dispatch(new AddToIndexAction(IndexName.UUID_MAPPING, request.uuid, entry.request.uuid))
|
|
||||||
}
|
}
|
||||||
)
|
} else {
|
||||||
}
|
this.getByHref(request.href).pipe(
|
||||||
|
filter((entry) => hasValue(entry)),
|
||||||
|
take(1)
|
||||||
|
).subscribe((entry) => {
|
||||||
|
return this.store.dispatch(new AddToIndexAction(IndexName.UUID_MAPPING, request.uuid, entry.request.uuid))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -12,6 +12,7 @@ import { AddToIndexAction, RemoveFromIndexByValueAction } from './index.actions'
|
|||||||
import { hasValue } from '../../shared/empty.util';
|
import { hasValue } from '../../shared/empty.util';
|
||||||
import { IndexName } from './index.reducer';
|
import { IndexName } from './index.reducer';
|
||||||
import { RestRequestMethod } from '../data/rest-request-method';
|
import { RestRequestMethod } from '../data/rest-request-method';
|
||||||
|
import { getUrlWithoutEmbedParams } from './index.selectors';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UUIDIndexEffects {
|
export class UUIDIndexEffects {
|
||||||
@@ -47,7 +48,7 @@ export class UUIDIndexEffects {
|
|||||||
map((action: RequestConfigureAction) => {
|
map((action: RequestConfigureAction) => {
|
||||||
return new AddToIndexAction(
|
return new AddToIndexAction(
|
||||||
IndexName.REQUEST,
|
IndexName.REQUEST,
|
||||||
action.payload.href,
|
getUrlWithoutEmbedParams(action.payload.href),
|
||||||
action.payload.uuid
|
action.payload.uuid
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
32
src/app/core/index/index.selectors.spec.ts
Normal file
32
src/app/core/index/index.selectors.spec.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { getUrlWithoutEmbedParams } from './index.selectors';
|
||||||
|
|
||||||
|
describe(`index selectors`, () => {
|
||||||
|
|
||||||
|
describe(`getUrlWithoutEmbedParams`, () => {
|
||||||
|
|
||||||
|
it(`should return a url without its embed params`, () => {
|
||||||
|
const source = 'https://rest.api/resource?a=1&embed=2&b=3&embed=4/5&c=6&embed=7/8/9';
|
||||||
|
const result = getUrlWithoutEmbedParams(source);
|
||||||
|
expect(result).toBe('https://rest.api/resource?a=1&b=3&c=6');
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should return a url without embed params unmodified`, () => {
|
||||||
|
const source = 'https://rest.api/resource?a=1&b=3&c=6';
|
||||||
|
const result = getUrlWithoutEmbedParams(source);
|
||||||
|
expect(result).toBe(source);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should return a string that isn't a url unmodified`, () => {
|
||||||
|
const source = 'a=1&embed=2&b=3&embed=4/5&c=6&embed=7/8/9';
|
||||||
|
const result = getUrlWithoutEmbedParams(source);
|
||||||
|
expect(result).toBe(source);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should return undefined or null unmodified`, () => {
|
||||||
|
expect(getUrlWithoutEmbedParams(undefined)).toBe(undefined);
|
||||||
|
expect(getUrlWithoutEmbedParams(null)).toBe(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@@ -1,8 +1,41 @@
|
|||||||
import { createSelector, MemoizedSelector } from '@ngrx/store';
|
import { createSelector, MemoizedSelector } from '@ngrx/store';
|
||||||
import { hasValue } from '../../shared/empty.util';
|
import { hasValue, isNotEmpty } from '../../shared/empty.util';
|
||||||
import { CoreState } from '../core.reducers';
|
import { CoreState } from '../core.reducers';
|
||||||
import { coreSelector } from '../core.selectors';
|
import { coreSelector } from '../core.selectors';
|
||||||
|
import { URLCombiner } from '../url-combiner/url-combiner';
|
||||||
import { IndexName, IndexState, MetaIndexState } from './index.reducer';
|
import { IndexName, IndexState, MetaIndexState } from './index.reducer';
|
||||||
|
import * as parse from 'url-parse';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the given url without `embed` params.
|
||||||
|
*
|
||||||
|
* E.g. https://rest.api/resource?size=5&embed=subresource&rpp=3
|
||||||
|
* becomes https://rest.api/resource?size=5&rpp=3
|
||||||
|
*
|
||||||
|
* When you index a request url you don't want to include
|
||||||
|
* embed params because embedded data isn't relevant when
|
||||||
|
* you want to know
|
||||||
|
*
|
||||||
|
* @param url The url to use
|
||||||
|
*/
|
||||||
|
export const getUrlWithoutEmbedParams = (url: string): string => {
|
||||||
|
if (isNotEmpty(url)) {
|
||||||
|
const parsed = parse(url);
|
||||||
|
if (isNotEmpty(parsed.query)) {
|
||||||
|
const parts = parsed.query.split(/[?|&]/)
|
||||||
|
.filter((part: string) => isNotEmpty(part))
|
||||||
|
.filter((part: string) => !part.startsWith('embed='));
|
||||||
|
let args = '';
|
||||||
|
if (isNotEmpty(parts)) {
|
||||||
|
args = `?${parts.join('&')}`;
|
||||||
|
}
|
||||||
|
url = new URLCombiner(parsed.origin, parsed.pathname, args).toString();
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the MetaIndexState based on the CoreSate
|
* Return the MetaIndexState based on the CoreSate
|
||||||
@@ -74,7 +107,7 @@ export const selfLinkFromUuidSelector =
|
|||||||
export const uuidFromHrefSelector =
|
export const uuidFromHrefSelector =
|
||||||
(href: string): MemoizedSelector<CoreState, string> => createSelector(
|
(href: string): MemoizedSelector<CoreState, string> => createSelector(
|
||||||
requestIndexSelector,
|
requestIndexSelector,
|
||||||
(state: IndexState) => hasValue(state) ? state[href] : undefined
|
(state: IndexState) => hasValue(state) ? state[getUrlWithoutEmbedParams(href)] : undefined
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -41,8 +41,8 @@ export class URLCombiner {
|
|||||||
// remove consecutive slashes
|
// remove consecutive slashes
|
||||||
url = url.replace(/([^:\s])\/+/g, '$1/');
|
url = url.replace(/([^:\s])\/+/g, '$1/');
|
||||||
|
|
||||||
// remove trailing slash before parameters or hash
|
// remove trailing slash
|
||||||
url = url.replace(/\/(\?|&|#[^!])/g, '$1');
|
url = url.replace(/\/($|\?|&|#[^!])/g, '$1');
|
||||||
|
|
||||||
// replace ? in parameters with &
|
// replace ? in parameters with &
|
||||||
url = url.replace(/(\?.+)\?/g, '$1&');
|
url = url.replace(/(\?.+)\?/g, '$1&');
|
||||||
|
Reference in New Issue
Block a user