< Summary

Information
Class: Services.Authorization.Services.ScopeFilterValuesService
Assembly: Services
File(s): /home/runner/work/Studio2Prod/Studio2Prod/AppRepository/Authorization/Services/ScopeFilterValuesService.cs
Line coverage
100%
Covered lines: 33
Uncovered lines: 0
Coverable lines: 33
Total lines: 71
Line coverage: 100%
Branch coverage
100%
Covered branches: 22
Total branches: 22
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
.ctor(...)100%11100%
GetAllowedValuesAsync()100%1616100%
GetBundleIfRestrictedAsync()100%66100%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/AppRepository/Authorization/Services/ScopeFilterValuesService.cs

#LineLine coverage
 1using System.Text.RegularExpressions;
 2using Services.Authorization.Dtos;
 3
 4namespace Services.Authorization.Services;
 5
 6/// <summary>
 7/// Парсит Dynamic LINQ выражения DataScope-ов и достаёт допустимые значения FK-полей.
 8/// Поддерживает шаблонный формат «(Field == val)» / «(Field == val || Field == val2)»
 9/// (то, что генерирует мастер создания набора из шаблона).
 10/// </summary>
 11public sealed class ScopeFilterValuesService : IScopeFilterValuesService
 12{
 13    private readonly IPermissionService _permissions;
 14
 115    private static readonly Regex FieldEqRegex = new(
 116        @"(?<field>[A-Za-z_][A-Za-z0-9_]*)\s*==\s*(?:""(?<sv>[^""]*)""|(?<nv>-?\d+))",
 117        RegexOptions.Compiled);
 18
 2919    public ScopeFilterValuesService(IPermissionService permissions)
 20    {
 2921        _permissions = permissions;
 2922    }
 23
 24    public async Task<IReadOnlyDictionary<string, HashSet<string>>> GetAllowedValuesAsync(
 25        string userId, string entityName, CancellationToken ct = default)
 26    {
 2327        if (string.IsNullOrWhiteSpace(userId) || string.IsNullOrWhiteSpace(entityName))
 628            return new Dictionary<string, HashSet<string>>();
 29
 1730        var bundle = await _permissions.GetUserPermissionsAsync(userId, ct);
 1831        if (bundle.IsSuperAdmin) return new Dictionary<string, HashSet<string>>();
 32
 1633        var exprs = bundle.DataScopes
 1634            .Where(s => string.Equals(s.EntityName, entityName, StringComparison.OrdinalIgnoreCase))
 1535            .Select(s => s.FilterExpression)
 1536            .Where(s => !string.IsNullOrWhiteSpace(s))
 1637            .ToList();
 38
 2039        if (exprs.Count == 0) return new Dictionary<string, HashSet<string>>();
 40
 1241        var result = new Dictionary<string, HashSet<string>>(StringComparer.OrdinalIgnoreCase);
 5042        foreach (var expr in exprs)
 43        {
 44            // ВАЖНО: разные scope-ы объединяются по OR. Но ограничения ПО ПОЛЮ — пересечение множеств
 45            // допустимых значений невозможно трактовать однозначно (ибо OR делается на уровне всей строки).
 46            // Поэтому считаем, что разные scope'ы перечисляют разрешённые значения одного поля аддитивно.
 6247            foreach (Match m in FieldEqRegex.Matches(expr))
 48            {
 1849                var field = m.Groups["field"].Value;
 1850                var value = m.Groups["sv"].Success ? m.Groups["sv"].Value : m.Groups["nv"].Value;
 1851                if (!result.TryGetValue(field, out var set))
 52                {
 1453                    set = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
 1454                    result[field] = set;
 55                }
 1856                set.Add(value);
 57            }
 58        }
 59
 1260        return result;
 2361    }
 62
 63    public async Task<UserPermissionsBundle?> GetBundleIfRestrictedAsync(string userId, CancellationToken ct = default)
 64    {
 1065        if (string.IsNullOrWhiteSpace(userId)) return null;
 466        var bundle = await _permissions.GetUserPermissionsAsync(userId, ct);
 567        if (bundle.IsSuperAdmin) return null;
 568        if (bundle.DataScopes.Count == 0) return null;
 169        return bundle;
 770    }
 71}