Feature/vacation edo signing #23
@@ -0,0 +1,27 @@
|
||||
import { trimPickerQuery } from './pickerContext';
|
||||
|
||||
const body = (q: unknown): string => JSON.stringify({ queryParams: { QueryString: q, PrincipalType: 1 } });
|
||||
const query = (b: unknown): unknown => (JSON.parse(b as string) as { queryParams: { QueryString: unknown } }).queryParams.QueryString;
|
||||
|
||||
describe('trimPickerQuery', () => {
|
||||
it('убирает пробел в конце и в начале', () => {
|
||||
expect(query(trimPickerQuery(body('Иван ')))).toBe('Иван');
|
||||
expect(query(trimPickerQuery(body(' Иван Петров ')))).toBe('Иван Петров');
|
||||
});
|
||||
|
||||
it('схлопывает двойные пробелы внутри', () => {
|
||||
expect(query(trimPickerQuery(body('Иван Петров')))).toBe('Иван Петров');
|
||||
});
|
||||
|
||||
it('не трогает остальные поля запроса', () => {
|
||||
const parsed = JSON.parse(trimPickerQuery(body('a ')) as string) as { queryParams: { PrincipalType: number } };
|
||||
expect(parsed.queryParams.PrincipalType).toBe(1);
|
||||
});
|
||||
|
||||
it('чужие тела возвращает как есть', () => {
|
||||
expect(trimPickerQuery('не json QueryString')).toBe('не json QueryString');
|
||||
expect(trimPickerQuery(undefined)).toBeUndefined();
|
||||
const other = JSON.stringify({ a: 1 });
|
||||
expect(trimPickerQuery(other)).toBe(other);
|
||||
});
|
||||
});
|
||||
@@ -18,6 +18,43 @@ export function pickedLogin(user: IPickedUser): string {
|
||||
return user.secondaryText || user.loginName || user.id || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Убирает пробелы по краям (и схлопывает внутренние) у QueryString в теле запроса
|
||||
* поиска сотрудника. PeoplePicker из @pnp/spfx-controls-react шлёт введённый
|
||||
* текст как есть, а SharePoint с «Иван » (пробел в конце, обычное дело при вводе
|
||||
* «имя фамилия») ничего не находит. Тело не JSON или без QueryString — возвращается как было.
|
||||
*/
|
||||
export function trimPickerQuery(body: unknown): unknown {
|
||||
if (typeof body !== 'string' || body.indexOf('QueryString') < 0) return body;
|
||||
try {
|
||||
const parsed = JSON.parse(body) as { queryParams?: { QueryString?: unknown } };
|
||||
const query = parsed.queryParams?.QueryString;
|
||||
if (typeof query !== 'string') return body;
|
||||
parsed.queryParams!.QueryString = query.trim().replace(/\s+/g, ' ');
|
||||
return JSON.stringify(parsed);
|
||||
} catch {
|
||||
return body;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* spHttpClient с подчисткой запроса поиска (см. trimPickerQuery): прокси, чтобы
|
||||
* остальные методы клиента работали как прежде, подменяется только post.
|
||||
*/
|
||||
function withTrimmedSearch(client: WebPartContext['spHttpClient']): WebPartContext['spHttpClient'] {
|
||||
return new Proxy(client, {
|
||||
get(target, prop, receiver) {
|
||||
if (prop !== 'post') return Reflect.get(target, prop, receiver);
|
||||
return (url: string, config: unknown, options?: { body?: unknown }) =>
|
||||
(target.post as (u: string, c: unknown, o?: unknown) => unknown)(
|
||||
url,
|
||||
config,
|
||||
options ? { ...options, body: trimPickerQuery(options.body) } : options
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Контекст для PeoplePicker из WebPartContext.
|
||||
* as unknown: @pnp/spfx-controls-react тянет свою копию sp-http-msgraph,
|
||||
@@ -27,6 +64,6 @@ export function buildPickerContext(context: WebPartContext): IPeoplePickerContex
|
||||
return {
|
||||
absoluteUrl: context.pageContext.web.absoluteUrl,
|
||||
msGraphClientFactory: context.msGraphClientFactory,
|
||||
spHttpClient: context.spHttpClient
|
||||
spHttpClient: withTrimmedSearch(context.spHttpClient)
|
||||
} as unknown as IPeoplePickerContext;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user