< Summary

Information
Class: OzonOrdersWeb.Areas.Admin.Controllers.FieldsController
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Admin/Controllers/FieldsController.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 168
Coverable lines: 168
Total lines: 265
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 66
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
Index()0%4260%
SyncOrderListRegistry()0%620%
Create()0%2040%
Create()0%420200%
Edit()0%4260%
Edit()0%210140%
Delete()0%7280%
ApplyOrderList(...)100%210%
ApplyFree(...)100%210%
PopulateLookups()0%2040%
BuildCatalogSelectList(...)100%210%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Admin/Controllers/FieldsController.cs

#LineLine coverage
 1using Microsoft.AspNetCore.Mvc;
 2using Microsoft.AspNetCore.Mvc.Rendering;
 3using Microsoft.EntityFrameworkCore;
 4using OzonDomains.Models.Authorization;
 5using OzonDomains.Models.Authorization.Enums;
 6using OzonOrdersWeb.Areas.Admin.Models;
 7using OzonOrdersWeb.Areas.Admin.OrderList;
 8using OzonOrdersWeb.Authorization;
 9using OzonRepositories.Context;
 10using Services.Authorization.Services;
 11
 12namespace OzonOrdersWeb.Areas.Admin.Controllers;
 13
 14/// <summary>
 15/// Реестр колонок списка заказов (главная, транзакции, журналы в том же формате) — только сущность OrderList, фиксирова
 16/// </summary>
 17public class FieldsController : AdminAreaControllerBase
 18{
 19    private readonly ApplicationDbContext _db;
 20    private readonly IPermissionService _permissions;
 21
 022    public FieldsController(ApplicationDbContext db, IPermissionService permissions)
 23    {
 024        _db = db;
 025        _permissions = permissions;
 026    }
 27
 28    public async Task<IActionResult> Index(CancellationToken ct)
 29    {
 030        ViewData["Title"] = "Колонки списка заказов";
 031        ViewData["Breadcrumb"] = new List<(string, string?)> { ("Админка", Url.Action("Index", "Home")), ("Колонки заказ
 32
 033        var existing = await _db.AppFields
 034            .Where(f => f.EntityName == OrderListColumnCatalog.EntityName)
 035            .Select(f => f.FieldName)
 036            .ToListAsync(ct);
 037        var existingSet = new HashSet<string>(existing, StringComparer.OrdinalIgnoreCase);
 038        var missingForCreate = OrderListColumnCatalog.All.Where(c => !existingSet.Contains(c.FieldName)).ToList();
 039        ViewBag.MissingForCreate = missingForCreate;
 040        ViewBag.ShowCreate = missingForCreate.Count > 0;
 41
 042        var items = await _db.AppFields
 043            .Include(f => f.Page)
 044            .Where(f => f.EntityName == OrderListColumnCatalog.EntityName)
 045            .OrderBy(f => f.SortOrder).ThenBy(f => f.FieldName)
 046            .Select(f => new FieldListItemVm
 047            {
 048                Id = f.Id, EntityName = f.EntityName, FieldName = f.FieldName,
 049                DisplayName = f.DisplayName, FieldTypeName = f.FieldType.ToString(),
 050                PageId = f.PageId, PageCode = f.Page != null ? f.Page.Code : null,
 051                IsActive = f.IsActive, SortOrder = f.SortOrder,
 052            })
 053            .ToListAsync(ct);
 054        var catalogNames = new HashSet<string>(OrderListColumnCatalog.All.Select(c => c.FieldName), StringComparer.Ordin
 055        foreach (var it in items) it.IsRegistryColumn = catalogNames.Contains(it.FieldName);
 56
 057        return View(items);
 058    }
 59
 60    [HttpPost]
 61    [ValidateAntiForgeryToken]
 62    public async Task<IActionResult> SyncOrderListRegistry(CancellationToken ct)
 63    {
 064        var n = await OrderListFieldSync.EnsureInDatabaseAsync(_db, ct);
 065        _permissions.InvalidateAll();
 066        TempData["SuccessMessage"] = n > 0
 067            ? $"Реестр обновлён, изменений: {n}."
 068            : "Реестр уже соответствует коду, изменений нет.";
 069        return RedirectToAction(nameof(Index));
 070    }
 71
 72    [HttpGet]
 73    public async Task<IActionResult> Create(CancellationToken ct)
 74    {
 075        await OrderListFieldSync.EnsureInDatabaseAsync(_db, ct);
 076        var existing = await _db.AppFields
 077            .Where(f => f.EntityName == OrderListColumnCatalog.EntityName)
 078            .Select(f => f.FieldName)
 079            .ToListAsync(ct);
 080        var existingSet = new HashSet<string>(existing, StringComparer.OrdinalIgnoreCase);
 081        var missing = OrderListColumnCatalog.All.Where(c => !existingSet.Contains(c.FieldName)).ToList();
 082        if (missing.Count == 0)
 83        {
 084            TempData["SuccessMessage"] = "Все колонки из реестра уже добавлены. При необходимости нажмите «Синхронизиров
 085            return RedirectToAction(nameof(Index));
 86        }
 87
 088        ViewData["Title"] = "Колонка из реестра";
 089        await PopulateLookups(null, ct);
 090        ViewBag.CatalogOptions = BuildCatalogSelectList(missing, selectedValue: null);
 091        return View("Edit", new FieldEditVm
 092        {
 093            IsActive = true,
 094            EntityName = OrderListColumnCatalog.EntityName,
 095            FieldType = (int)FieldType.FormField,
 096        });
 097    }
 98
 99    [HttpPost]
 100    [ValidateAntiForgeryToken]
 101    public async Task<IActionResult> Create(FieldEditVm model, CancellationToken ct)
 102    {
 0103        if (!string.IsNullOrWhiteSpace(model.SelectedCatalogFieldName))
 104        {
 0105            var pre = OrderListColumnCatalog.All.FirstOrDefault(c =>
 0106                c.FieldName.Equals(model.SelectedCatalogFieldName.Trim(), StringComparison.OrdinalIgnoreCase));
 0107            if (pre is not null && string.IsNullOrWhiteSpace(model.DisplayName))
 0108                model.DisplayName = pre.DisplayName;
 109        }
 110
 0111        var col = OrderListColumnCatalog.All.FirstOrDefault(c =>
 0112            c.FieldName.Equals(model.SelectedCatalogFieldName?.Trim(), StringComparison.OrdinalIgnoreCase));
 0113        if (col is null)
 114        {
 0115            ModelState.AddModelError(nameof(model.SelectedCatalogFieldName), "Выберите колонку из списка.");
 116        }
 0117        if (col is not null)
 118        {
 0119            var dup = await _db.AppFields
 0120                .AnyAsync(f => f.EntityName == OrderListColumnCatalog.EntityName && f.FieldName == col.FieldName, ct);
 0121            if (dup) ModelState.AddModelError(nameof(model.SelectedCatalogFieldName), "Эта колонка уже в реестре.");
 122        }
 0123        if (!ModelState.IsValid)
 124        {
 0125            await PopulateLookups(model.PageId, ct);
 0126            var existing = await _db.AppFields
 0127                .Where(f => f.EntityName == OrderListColumnCatalog.EntityName)
 0128                .Select(f => f.FieldName)
 0129                .ToListAsync(ct);
 0130            var existingSet = new HashSet<string>(existing, StringComparer.OrdinalIgnoreCase);
 0131            var missing = OrderListColumnCatalog.All.Where(c => !existingSet.Contains(c.FieldName)).ToList();
 0132            ViewBag.CatalogOptions = BuildCatalogSelectList(missing, model.SelectedCatalogFieldName);
 0133            return View("Edit", model);
 134        }
 135
 0136        _db.AppFields.Add(new AppField
 0137        {
 0138            EntityName = OrderListColumnCatalog.EntityName,
 0139            FieldName = col!.FieldName,
 0140            DisplayName = string.IsNullOrWhiteSpace(model.DisplayName) ? col.DisplayName : model.DisplayName.Trim(),
 0141            FieldType = (FieldType)model.FieldType,
 0142            PageId = model.PageId,
 0143            SortOrder = model.SortOrder != 0 ? model.SortOrder : col.SortOrder,
 0144            IsActive = model.IsActive,
 0145        });
 0146        await _db.SaveChangesAsync(ct);
 0147        _permissions.InvalidateAll();
 0148        TempData["SuccessMessage"] = "Колонка добавлена";
 0149        return RedirectToAction(nameof(Index));
 0150    }
 151
 152    [HttpGet]
 153    public async Task<IActionResult> Edit(int id, CancellationToken ct)
 154    {
 0155        var f = await _db.AppFields.FirstOrDefaultAsync(x => x.Id == id, ct);
 0156        if (f == null) return NotFound();
 0157        if (f.EntityName != OrderListColumnCatalog.EntityName) return NotFound();
 158
 0159        var fromCatalog = OrderListColumnCatalog.IsCatalogFieldName(f.FieldName);
 0160        ViewData["Title"] = fromCatalog
 0161            ? $"Колонка: {f.DisplayName}"
 0162            : $"Поле: {f.DisplayName}";
 163
 0164        await PopulateLookups(f.PageId, ct);
 0165        return View(new FieldEditVm
 0166        {
 0167            Id = f.Id, EntityName = f.EntityName, FieldName = f.FieldName,
 0168            DisplayName = f.DisplayName, FieldType = (int)f.FieldType,
 0169            PageId = f.PageId, SortOrder = f.SortOrder, IsActive = f.IsActive,
 0170            FromOrderListCatalog = fromCatalog,
 0171        });
 0172    }
 173
 174    [HttpPost]
 175    [ValidateAntiForgeryToken]
 176    public async Task<IActionResult> Edit(int id, FieldEditVm model, CancellationToken ct)
 177    {
 0178        var f = await _db.AppFields.FirstOrDefaultAsync(x => x.Id == id, ct);
 0179        if (f == null) return NotFound();
 0180        if (f.EntityName != OrderListColumnCatalog.EntityName) return NotFound();
 0181        if (!ModelState.IsValid) { await PopulateLookups(model.PageId, ct); return View(model); }
 182
 0183        var isCatalogRow = OrderListColumnCatalog.IsCatalogFieldName(f.FieldName);
 0184        if (!isCatalogRow)
 185        {
 0186            if (string.IsNullOrWhiteSpace(model.EntityName) || string.IsNullOrWhiteSpace(model.FieldName))
 187            {
 0188                ModelState.AddModelError(string.Empty, "Укажите сущность и имя поля.");
 0189                await PopulateLookups(model.PageId, ct);
 0190                return View(model);
 191            }
 192        }
 0193        if (isCatalogRow) ApplyOrderList(f, model);
 0194        else ApplyFree(f, model);
 195
 0196        f.UpdatedAt = DateTime.UtcNow;
 0197        await _db.SaveChangesAsync(ct);
 0198        _permissions.InvalidateAll();
 0199        TempData["SuccessMessage"] = "Сохранено";
 0200        return RedirectToAction(nameof(Index));
 0201    }
 202
 203    [HttpPost]
 204    [ValidateAntiForgeryToken]
 205    public async Task<IActionResult> Delete(int id, CancellationToken ct)
 206    {
 0207        var f = await _db.AppFields.FirstOrDefaultAsync(x => x.Id == id, ct);
 0208        if (f == null) return NotFound();
 0209        if (f.EntityName == OrderListColumnCatalog.EntityName && OrderListColumnCatalog.IsCatalogFieldName(f.FieldName))
 210        {
 0211            TempData["ErrorMessage"] = "Колонку из фиксированного реестра нельзя удалить. Снимите «Активно», чтобы скрыт
 0212            return RedirectToAction(nameof(Index));
 213        }
 0214        if (f.EntityName == OrderListColumnCatalog.EntityName)
 215        {
 0216            _db.AppFields.Remove(f);
 0217            await _db.SaveChangesAsync(ct);
 0218            _permissions.InvalidateAll();
 0219            TempData["SuccessMessage"] = "Удалено";
 0220            return RedirectToAction(nameof(Index));
 221        }
 0222        return NotFound();
 0223    }
 224
 225    private static void ApplyOrderList(AppField target, FieldEditVm vm)
 226    {
 0227        target.DisplayName = vm.DisplayName.Trim();
 0228        target.FieldType = (FieldType)vm.FieldType;
 0229        target.PageId = vm.PageId;
 0230        target.SortOrder = vm.SortOrder;
 0231        target.IsActive = vm.IsActive;
 0232    }
 233
 234    private static void ApplyFree(AppField target, FieldEditVm vm)
 235    {
 0236        target.EntityName = vm.EntityName.Trim();
 0237        target.FieldName = vm.FieldName.Trim();
 0238        target.DisplayName = vm.DisplayName.Trim();
 0239        target.FieldType = (FieldType)vm.FieldType;
 0240        target.PageId = vm.PageId;
 0241        target.SortOrder = vm.SortOrder;
 0242        target.IsActive = vm.IsActive;
 0243    }
 244
 245    private async Task PopulateLookups(int? selectedPageId, CancellationToken ct)
 246    {
 0247        var pages = await _db.AppPages.OrderBy(p => p.DisplayName).Select(p => new { p.Id, p.DisplayName }).ToListAsync(
 0248        ViewBag.Pages = new SelectList(pages, "Id", "DisplayName", selectedPageId);
 0249        ViewBag.FieldTypes = Enum.GetValues<FieldType>()
 0250            .Select(ft => new SelectListItem(ft.ToString(), ((int)ft).ToString())).ToList();
 0251    }
 252
 253    private static SelectList BuildCatalogSelectList(
 254        IReadOnlyList<OrderListColumnCatalog.OrderListColumn> missing,
 255        string? selectedValue)
 256    {
 0257        var items = new List<SelectListItem> { new() { Value = "", Text = "— выберите колонку —" } };
 0258        items.AddRange(missing.Select(m => new SelectListItem
 0259        {
 0260            Value = m.FieldName,
 0261            Text = $"{m.DisplayName} ({m.FieldName})",
 0262        }));
 0263        return new SelectList(items, "Value", "Text", selectedValue);
 264    }
 265}