< Summary

Information
Class: OzonOrdersWeb.WebServices.Orders.Grid.OrdersGridUserContext
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/Orders/Grid/OrdersGridScopedQuery.cs
Line coverage
100%
Covered lines: 1
Uncovered lines: 0
Coverable lines: 1
Total lines: 113
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_User()100%11100%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/Orders/Grid/OrdersGridScopedQuery.cs

#LineLine coverage
 1using System.Security.Claims;
 2using Microsoft.EntityFrameworkCore;
 3using OzonDomains.Models;
 4using OzonDomains.Models.AccessControl;
 5using OzonRepositories.Context;
 6using OzonRepositories.Context.Identity;
 7using Services.CacheServices.Cache.UserCacheService;
 8using Services.DataServices;
 9using Services.FiltersServices.SortModels;
 10
 11namespace OzonOrdersWeb.WebServices.Orders.Grid;
 12
 13/// <summary>Пользователь и его профиль доступа — то, от чего зависит RLS-скоуп запросов грида.</summary>
 814public sealed record OrdersGridUserContext(CustomIdentityUser User, AccessProfile? Profile);
 15
 16public interface IOrdersGridScopedQuery
 17{
 18    /// <summary>Пользователь из principal; null — не найден (запрос надо отклонить).</summary>
 19    Task<OrdersGridUserContext?> ResolveUserAsync(ClaimsPrincipal principal);
 20
 21    /// <summary>
 22    /// Базовый запрос заказов, доступных пользователю (профиль доступа + RLS-скоуп + архив). Все точечные чтения
 23    /// грида (карточка, история статусов, дельта автообновления, фасеты, счётчики пресетов) строятся поверх него.
 24    /// </summary>
 25    Task<IQueryable<Order>> BuildAsync(OrdersGridUserContext user, bool includeArchived, CancellationToken cancellationT
 26
 27    /// <summary>Тот же скоуп плюс фильтры грида (маппер, доп. фильтры, вычисляемые столбцы, onlyIds).</summary>
 28    Task<IQueryable<Order>> BuildFilteredAsync(OrdersGridUserContext user, AgGridRequestMapper.MappedRequest mapped,
 29        IReadOnlyList<(OrdersGridFormulaTranslator.Translation Translation, OrdersGridComputedFilters.ComputedFilter Fil
 30        IReadOnlyList<int>? onlyIds, CancellationToken cancellationToken);
 31
 32    /// <summary>Из запрошенных Id оставить только доступные пользователю (порядок сохраняется).</summary>
 33    Task<List<int>> FilterAccessibleAsync(OrdersGridUserContext user, IReadOnlyList<int> ids, bool includeArchived, Canc
 34}
 35
 36public sealed class OrdersGridScopedQuery : IOrdersGridScopedQuery
 37{
 38    private readonly IOrdersIndexQueryService _queryService;
 39    private readonly IUserCacheService _userCacheService;
 40    private readonly AccessProfileDataServices _accessProfileDataServices;
 41    private readonly ApplicationDbContext _context;
 42
 43    public OrdersGridScopedQuery(
 44        IOrdersIndexQueryService queryService,
 45        IUserCacheService userCacheService,
 46        AccessProfileDataServices accessProfileDataServices,
 47        ApplicationDbContext context)
 48    {
 49        _queryService = queryService;
 50        _userCacheService = userCacheService;
 51        _accessProfileDataServices = accessProfileDataServices;
 52        _context = context;
 53    }
 54
 55    public async Task<OrdersGridUserContext?> ResolveUserAsync(ClaimsPrincipal principal)
 56    {
 57        var user = await _userCacheService.GetCachedUserAsync(principal);
 58        if (user is null) return null;
 59        AccessProfile? profile = null;
 60        if (user.AccessProfileId is > 0)
 61        {
 62            profile = await _accessProfileDataServices.GetAccessProfileAsync(user.AccessProfileId.Value);
 63        }
 64
 65        return new OrdersGridUserContext(user, profile);
 66    }
 67
 68    public Task<IQueryable<Order>> BuildAsync(OrdersGridUserContext user, bool includeArchived, CancellationToken cancel
 69    {
 70        return _queryService.BuildFilteredQueryableAsync(new OrdersIndexQueryRequest
 71        {
 72            Filter = new OServices.FiltersServices.FilterModels.OrderFilterModel { IncludeArchived = includeArchived, Gr
 73            SortOrder = OrderSortState.StandardState,
 74            AccessProfile = user.Profile,
 75            HasFilters = true,
 76            UserId = user.User.Id,
 77            CancellationToken = cancellationToken
 78        });
 79    }
 80
 81    public Task<IQueryable<Order>> BuildFilteredAsync(OrdersGridUserContext user, AgGridRequestMapper.MappedRequest mapp
 82        IReadOnlyList<(OrdersGridFormulaTranslator.Translation Translation, OrdersGridComputedFilters.ComputedFilter Fil
 83        IReadOnlyList<int>? onlyIds, CancellationToken cancellationToken)
 84    {
 85        var hasPost = mapped.MultiValueFilters.Count > 0 || mapped.ExtraFilters.Count > 0 || computedFilters.Count > 0 |
 86        return _queryService.BuildFilteredQueryableAsync(new OrdersIndexQueryRequest
 87        {
 88            Filter = mapped.Filter,
 89            SortOrder = OrderSortState.StandardState,
 90            AccessProfile = user.Profile,
 91            HasFilters = true,
 92            UserId = user.User.Id,
 93            CancellationToken = cancellationToken,
 94            QueryPostProcessor = hasPost
 95                ? q =>
 96                {
 97                    var filtered = OrdersGridComputedFilters.Apply(OrdersGridExtraFilters.Apply(
 98                        OrdersGridMultiValueFilters.Apply(q, mapped.MultiValueFilters, _context), mapped.ExtraFilters), 
 99                    return onlyIds is { Count: > 0 } ? filtered.Where(o => onlyIds.Contains(o.Id)) : filtered;
 100                }
 101                : null
 102        });
 103    }
 104
 105    public async Task<List<int>> FilterAccessibleAsync(OrdersGridUserContext user, IReadOnlyList<int> ids, bool includeA
 106    {
 107        if (ids.Count == 0) return [];
 108        var query = await BuildAsync(user, includeArchived, cancellationToken);
 109        var list = ids.Distinct().ToList();
 110        var allowed = new HashSet<int>(await query.Where(o => list.Contains(o.Id)).Select(o => o.Id).ToListAsync(cancell
 111        return ids.Where(allowed.Contains).Distinct().ToList();
 112    }
 113}

Methods/Properties

get_User()