feat: эндпоинт заявок по основанию (СТ/потребность) с проверкой прав на открытие
GET /api/basis-requests?requestTypeId=&basisKey= читает заявки от имени приложения по всем партициям, а по каждой проверяет, может ли вызывающий её открыть. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -54,6 +54,14 @@ public interface ISharePointClient
|
||||
Task<IReadOnlyList<JsonElement>> GetItemsByListTitleAsync(
|
||||
string siteUrl, string listTitle, string odataQuery, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Может ли пользователь (по email) открыть элемент списка: эффективные права
|
||||
/// человека на элемент с учётом разорванного наследования, флаг ViewListItems.
|
||||
/// Неизвестный SharePoint логин — не ошибка, а «прав нет».
|
||||
/// </summary>
|
||||
Task<bool> CanUserViewItemAsync(
|
||||
string siteUrl, string listServerRelativeUrl, int itemId, string userEmail, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Запрос в SharePoint Search (postquery) от имени приложения — видит ВСЕ
|
||||
/// элементы, а не только доступные пользователю. Возвращает строки результата
|
||||
@@ -229,6 +237,22 @@ public sealed class SharePointClient(
|
||||
$"{siteUrl.TrimEnd('/')}/_api/web/lists/getByTitle('{Escape(listTitle)}')/items?{odataQuery}",
|
||||
cancellationToken);
|
||||
|
||||
public async Task<bool> CanUserViewItemAsync(
|
||||
string siteUrl, string listServerRelativeUrl, int itemId, string userEmail, CancellationToken cancellationToken)
|
||||
{
|
||||
// Claims-логин Entra ID в SharePoint Online. Передаём через параметр-псевдоним
|
||||
// @u: в пути функции «|» и «#» SharePoint не разбирает.
|
||||
var login = Uri.EscapeDataString($"i:0#.f|membership|{userEmail.Trim().ToLowerInvariant()}");
|
||||
var url = $"{siteUrl.TrimEnd('/')}/_api/web/getList('{Escape(listServerRelativeUrl)}')/items({itemId})" +
|
||||
$"/getUserEffectivePermissions(@u)?@u='{login}'";
|
||||
var json = await GetAsync(siteUrl, url, cancellationToken);
|
||||
|
||||
// BasePermissions приходит как {High, Low} — числа строками. ViewListItems — бит 0x1 в Low.
|
||||
return json.TryGetProperty("Low", out var low)
|
||||
&& ulong.TryParse(low.ValueKind == JsonValueKind.String ? low.GetString() : low.GetRawText(), out var bits)
|
||||
&& (bits & ViewListItemsMask) != 0;
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<IReadOnlyDictionary<string, string?>>> SearchAsync(
|
||||
string siteUrl, string queryText, IReadOnlyList<string> selectProperties, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -426,6 +450,8 @@ public sealed class SharePointClient(
|
||||
}
|
||||
}
|
||||
|
||||
private const ulong ViewListItemsMask = 0x1;
|
||||
|
||||
// Одинарная кавычка в OData-литерале экранируется её удвоением. Заголовки
|
||||
// списков содержат тире и кириллицу, но кавычка теоретически возможна —
|
||||
// без экранирования она сломала бы запрос.
|
||||
|
||||
Reference in New Issue
Block a user