66 lines
3.0 KiB
TypeScript
66 lines
3.0 KiB
TypeScript
import { WebPartContext } from '@microsoft/sp-webpart-base';
|
||
import { spForSite } from '../pnp/pnpjs';
|
||
import '@pnp/sp/webs';
|
||
import '@pnp/sp/site-users/web';
|
||
|
||
/**
|
||
* Числовой Id пользователя НА КОНКРЕТНОМ САЙТЕ — с кешом на сессию.
|
||
*
|
||
* Зачем: почти все фильтры SharePoint REST по Person-полям строятся по числовому
|
||
* Id (`AuthorId eq N`, `TansuSiteApproverId eq N`) — фильтр по EMail у Person-поля
|
||
* ненадёжен. Id свой на каждом сайте, поэтому его приходится резолвить, но
|
||
* в пределах сессии он не меняется.
|
||
*
|
||
* Раньше резолв стоял ВНУТРИ функций, которые вызываются в цикле по типам заявок
|
||
* (getOwnRowsForType / getRecentlyChangedOwnRowsForType): при восьми типах это
|
||
* восемь одинаковых GET /_api/web/currentuser подряд, и каждый — лишний
|
||
* round-trip ПЕРЕД основным запросом. ensureUser в очереди согласования — то же
|
||
* самое, только POST.
|
||
*
|
||
* Ошибку НЕ кешируем: упавший на холодном старте запрос должен повториться,
|
||
* а не залипнуть до конца сессии (тот же принцип, что у requestTypesPromise
|
||
* в approvalRoute.service.ts).
|
||
*/
|
||
|
||
const byKey = new Map<string, Promise<number>>();
|
||
|
||
function remember(key: string, load: () => Promise<number>): Promise<number> {
|
||
const pending = byKey.get(key);
|
||
if (pending) return pending;
|
||
|
||
const promise = load().catch((e) => {
|
||
byKey.delete(key);
|
||
throw e;
|
||
});
|
||
byKey.set(key, promise);
|
||
return promise;
|
||
}
|
||
|
||
/** Полный сброс — на случай смены личности (отладочная подмена) или реинициализации. */
|
||
export function resetSiteUserCache(): void {
|
||
byKey.clear();
|
||
}
|
||
|
||
/** Id ТЕКУЩЕГО (реального) пользователя на сайте. */
|
||
export async function currentUserIdFor(context: WebPartContext, siteUrl: string): Promise<number> {
|
||
return remember(`current|${siteUrl.toLowerCase()}`, async () => {
|
||
const me = await spForSite(siteUrl, context).web.currentUser.select('Id')();
|
||
return me.Id as number;
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Id пользователя по claims-логину. ensureUser — это POST (он при необходимости
|
||
* заводит пользователя в коллекции сайта), поэтому повторять его особенно жаль.
|
||
*/
|
||
export async function ensureUserIdFor(
|
||
context: WebPartContext,
|
||
siteUrl: string,
|
||
claimsLogin: string
|
||
): Promise<number> {
|
||
return remember(`ensure|${siteUrl.toLowerCase()}|${claimsLogin.toLowerCase()}`, async () => {
|
||
const user = await spForSite(siteUrl, context).web.ensureUser(claimsLogin);
|
||
return user.Id;
|
||
});
|
||
}
|