< Summary

Information
Class: OzonOrdersWeb.ViewComponents.DynamicTableModel
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/ViewComponents/DynamicTableViewComponent.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 6
Coverable lines: 6
Total lines: 91
Line coverage: 0%
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_EntityName()100%210%
get_Columns()100%210%
get_Rows()100%210%
get_TableCssClass()100%210%
get_EmptyMessage()100%210%
get_PropertyAccessors()100%210%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/ViewComponents/DynamicTableViewComponent.cs

#LineLine coverage
 1using System.Collections;
 2using System.Reflection;
 3using System.Security.Claims;
 4using Microsoft.AspNetCore.Mvc;
 5using Microsoft.EntityFrameworkCore;
 6using OzonDomains.Models.Authorization.Enums;
 7using OzonRepositories.Context;
 8using Services.Authorization.Services;
 9
 10namespace OzonOrdersWeb.ViewComponents;
 11
 12/// <summary>
 13/// Отображает таблицу только с теми столбцами, на которые у текущего пользователя есть CanRead.
 14/// Источник метаданных столбцов — AppField (EntityName, FieldType=Column).
 15/// </summary>
 16public sealed class DynamicTableViewComponent : ViewComponent
 17{
 18    private readonly IPermissionService _permissions;
 19    private readonly ApplicationDbContext _db;
 20
 21    public DynamicTableViewComponent(IPermissionService permissions, ApplicationDbContext db)
 22    {
 23        _permissions = permissions;
 24        _db = db;
 25    }
 26
 27    public async Task<IViewComponentResult> InvokeAsync(string entityName, IEnumerable data, string? tableCssClass = nul
 28    {
 29        var userId = ((ClaimsPrincipal)User).FindFirst(ClaimTypes.NameIdentifier)?.Value;
 30        var model = new DynamicTableModel
 31        {
 32            EntityName = entityName,
 33            Rows = data?.Cast<object?>().ToList() ?? new List<object?>(),
 34            TableCssClass = tableCssClass ?? "table table-sm table-bordered",
 35            EmptyMessage = emptyMessage ?? "Нет данных"
 36        };
 37
 38        // Получаем зарегистрированные столбцы из AppField
 39        var fields = await _db.AppFields.AsNoTracking()
 40            .Where(f => f.EntityName == entityName && f.IsActive && f.FieldType == FieldType.Column)
 41            .OrderBy(f => f.SortOrder).ThenBy(f => f.FieldName)
 42            .ToListAsync();
 43
 44        // Фильтруем по правам пользователя
 45        var allowed = new List<DynamicColumn>();
 46        if (!string.IsNullOrWhiteSpace(userId))
 47        {
 48            var perms = await _permissions.GetUserFieldPermissionsAsync(userId, entityName);
 49            var allowedNames = perms.Where(p => p.CanRead).Select(p => p.FieldName).ToHashSet(StringComparer.OrdinalIgno
 50            var bundle = await _permissions.GetUserPermissionsAsync(userId);
 51            foreach (var f in fields)
 52            {
 53                if (bundle.IsSuperAdmin || allowedNames.Contains(f.FieldName))
 54                    allowed.Add(new DynamicColumn(f.FieldName, f.DisplayName));
 55            }
 56        }
 57        else
 58        {
 59            // Неаутентифицированный — без столбцов
 60        }
 61
 62        model.Columns = allowed;
 63
 64        // Заранее получаем PropertyInfo для ускорения рендера
 65        if (model.Rows.Count > 0 && model.Rows[0] is not null)
 66        {
 67            var type = model.Rows[0]!.GetType();
 68            model.PropertyAccessors = allowed.ToDictionary(
 69                c => c.FieldName,
 70                c => type.GetProperty(c.FieldName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase
 71        }
 72        else
 73        {
 74            model.PropertyAccessors = new Dictionary<string, PropertyInfo?>();
 75        }
 76
 77        return View(model);
 78    }
 79}
 80
 81public sealed class DynamicTableModel
 82{
 083    public string EntityName { get; set; } = string.Empty;
 084    public List<DynamicColumn> Columns { get; set; } = new();
 085    public List<object?> Rows { get; set; } = new();
 086    public string TableCssClass { get; set; } = "table";
 087    public string EmptyMessage { get; set; } = "Нет данных";
 088    public Dictionary<string, PropertyInfo?> PropertyAccessors { get; set; } = new();
 89}
 90
 91public sealed record DynamicColumn(string FieldName, string DisplayName);