< Summary

Information
Class: OzonOrdersWeb.Areas.Studio2.Controllers.FidStatController
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Controllers/FidStatController.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 114
Coverable lines: 114
Total lines: 257
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 22
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%210%
.ctor(...)100%210%
Push()0%2040%
Index()0%620%
GetSnapshots()0%4260%
GetSnapshotDetail()0%620%
GetFidNames()100%210%
GetLatestSnapshot()0%4260%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Controllers/FidStatController.cs

#LineLine coverage
 1using Microsoft.AspNetCore.Authorization;
 2using Microsoft.AspNetCore.Mvc;
 3using OzonDomains.Models;
 4using Services.DataServices;
 5using System;
 6using System.Collections.Generic;
 7using System.ComponentModel.DataAnnotations;
 8using System.Linq;
 9using System.Text.Json;
 10using System.Threading;
 11using System.Threading.Tasks;
 12
 13namespace OzonOrdersWeb.Areas.Studio2.Controllers
 14{
 15    [Area("Studio2")]
 16    [Route("Studio2/FidStat")]
 17    [Route("FidStat")]
 18    public class FidStatController : Controller
 19    {
 020        private static readonly JsonSerializerOptions PushJsonOptions = new()
 021        {
 022            PropertyNameCaseInsensitive = true
 023        };
 24
 25        private readonly FidStatDataServices _fidStatDataServices;
 26
 027        public FidStatController(FidStatDataServices fidStatDataServices)
 28        {
 029            _fidStatDataServices = fidStatDataServices;
 030        }
 31
 32        // ──────────────────────────────────────────────────────────────────────
 33        // POST /Studio2/FidStat/Push (или /FidStat/Push)
 34        // Публичный endpoint — принимает данные статистики фида без авторизации.
 35        // Тело — JSON (Content-Type необязателен: внешние скрипты часто шлют без заголовка).
 36        // Возвращает JSON с подтверждением: { status, snapshotId, itemsCount, fidName }
 37        // ──────────────────────────────────────────────────────────────────────
 38        [HttpPost("Push")]
 39        [AllowAnonymous]
 40        public async Task<IActionResult> Push(CancellationToken cancellationToken)
 41        {
 42            FidStatRequest request;
 43            try
 44            {
 045                request = await JsonSerializer.DeserializeAsync<FidStatRequest>(
 046                             Request.Body, PushJsonOptions, cancellationToken)
 047                         ?? new FidStatRequest();
 048            }
 049            catch (JsonException)
 50            {
 051                return BadRequest(new { status = "error", errors = new[] { "Некорректный JSON в теле запроса" } });
 52            }
 53
 054            if (!TryValidateModel(request))
 055                return BadRequest(new { status = "error", errors = ModelState.Values
 056                    .SelectMany(v => v.Errors)
 057                    .Select(e => e.ErrorMessage) });
 58
 059            var snapshot = new FidStatSnapshot
 060            {
 061                FidName = request.FidName,
 062                PostTime = request.PostTime,
 063                ReceivedAt = DateTime.UtcNow,
 064                Items = request.Items.Select(i => new FidStatItem
 065                {
 066                    RowNumber = i.Id,
 067                    RangeFrom = i.RangeFrom,
 068                    RangeTo = i.RangeTo,
 069                    Count = i.Count,
 070                    Percentage = i.Percentage,
 071                    Indices = i.Indices ?? string.Empty
 072                }).ToList()
 073            };
 74
 075            await _fidStatDataServices.Add(snapshot);
 76
 077            return Ok(new
 078            {
 079                status = "ok",
 080                snapshotId = snapshot.Id,
 081                itemsCount = snapshot.Items.Count,
 082                fidName = snapshot.FidName
 083            });
 084        }
 85
 86        // ──────────────────────────────────────────────────────────────────────
 87        // GET /Studio2/FidStat/Index — страница просмотра статистики фидов
 88        // ──────────────────────────────────────────────────────────────────────
 89        [HttpGet("")]
 90        [HttpGet("Index")]
 91        [Authorize(Roles = "User,Admin,SuperAdmin")]
 92        public async Task<IActionResult> Index()
 93        {
 094            var fidNames = await _fidStatDataServices.GetDistinctFidNames();
 095            ViewBag.FidNames = fidNames;
 096            return View();
 097        }
 98
 99        // ──────────────────────────────────────────────────────────────────────
 100        // GET /Studio2/FidStat/GetSnapshots
 101        // AJAX: список снимков с фильтрацией, сортировкой и пагинацией
 102        // ──────────────────────────────────────────────────────────────────────
 103        [HttpGet("GetSnapshots")]
 104        [Authorize(Roles = "User,Admin,SuperAdmin")]
 105        public async Task<IActionResult> GetSnapshots(
 106            string? fidName,
 107            DateTime? dateFrom,
 108            DateTime? dateTo,
 109            int page = 1,
 110            int pageSize = 20)
 111        {
 0112            if (page < 1) page = 1;
 0113            if (pageSize < 1 || pageSize > 200) pageSize = 20;
 114
 0115            var skip = (page - 1) * pageSize;
 116
 0117            var items = await _fidStatDataServices.GetFiltered(fidName, dateFrom, dateTo, skip, pageSize);
 0118            var total = await _fidStatDataServices.GetFilteredCount(fidName, dateFrom, dateTo);
 119
 0120            return Ok(new
 0121            {
 0122                Items = items.Select(s => new
 0123                {
 0124                    s.Id,
 0125                    s.FidName,
 0126                    PostTime = s.PostTime.ToUniversalTime().ToString("o"),
 0127                    ReceivedAt = DateTime.SpecifyKind(s.ReceivedAt, DateTimeKind.Utc).ToString("o"),
 0128                }),
 0129                TotalCount = total,
 0130                Pages = (int)Math.Ceiling((double)total / pageSize),
 0131                Page = page
 0132            });
 0133        }
 134
 135        // ──────────────────────────────────────────────────────────────────────
 136        // GET /Studio2/FidStat/GetSnapshotDetail?id=N
 137        // AJAX: полный снимок с items для отображения таблицы диапазонов
 138        // ──────────────────────────────────────────────────────────────────────
 139        [HttpGet("GetSnapshotDetail")]
 140        [Authorize(Roles = "User,Admin,SuperAdmin")]
 141        public async Task<IActionResult> GetSnapshotDetail(int id)
 142        {
 0143            var snapshot = await _fidStatDataServices.GetByIdWithItems(id);
 0144            if (snapshot == null) return NotFound(new { status = "not_found" });
 145
 0146            return Ok(new
 0147            {
 0148                snapshot.Id,
 0149                snapshot.FidName,
 0150                PostTime = snapshot.PostTime.ToUniversalTime().ToString("o"),
 0151                ReceivedAt = DateTime.SpecifyKind(snapshot.ReceivedAt, DateTimeKind.Utc).ToString("o"),
 0152                TotalCount = snapshot.Items.Sum(i => i.Count),
 0153                Items = snapshot.Items.OrderBy(i => i.RangeFrom).Select(i => new
 0154                {
 0155                    i.RowNumber,
 0156                    RangeFrom = i.RangeFrom,
 0157                    RangeTo = i.RangeTo,
 0158                    i.Count,
 0159                    i.Percentage,
 0160                    i.Indices,
 0161                    RangeLabel = $"{i.RangeFrom:0.000} - {i.RangeTo:0.000}"
 0162                })
 0163            });
 0164        }
 165
 166        // ──────────────────────────────────────────────────────────────────────
 167        // GET /Studio2/FidStat/GetFidNames
 168        // AJAX: список уникальных FidName для фильтра-дропдауна
 169        // ──────────────────────────────────────────────────────────────────────
 170        [HttpGet("GetFidNames")]
 171        [Authorize(Roles = "User,Admin,SuperAdmin")]
 172        public async Task<IActionResult> GetFidNames()
 173        {
 0174            var names = await _fidStatDataServices.GetDistinctFidNames();
 0175            return Ok(names);
 0176        }
 177
 178        // GET /Studio2/FidStat/GetLatestSnapshot
 179        // AJAX: последний снимок со всеми элементами для badge обновления
 180        // ──────────────────────────────────────────────────────────────────────
 181        [HttpGet("GetLatestSnapshot")]
 182        [Authorize(Roles = "User,Admin,SuperAdmin")]
 183        public async Task<IActionResult> GetLatestSnapshot()
 184        {
 185            try
 186            {
 0187                var snapshots = await _fidStatDataServices.GetFiltered(null, null, null, 0, 1);
 188
 0189                if (snapshots == null || !snapshots.Any())
 190                {
 0191                    return Ok(new { items = new List<object>() });
 192                }
 193
 0194                var latest = snapshots.First();
 0195                var detailedSnapshot = await _fidStatDataServices.GetByIdWithItems(latest.Id);
 196
 0197                if (detailedSnapshot == null)
 198                {
 0199                    return Ok(new { items = new List<object>() });
 200                }
 201
 0202                return Ok(new
 0203                {
 0204                    Id = detailedSnapshot.Id,
 0205                    FidName = detailedSnapshot.FidName,
 0206                    PostTime = detailedSnapshot.PostTime.ToUniversalTime().ToString("o"),
 0207                    TotalCount = detailedSnapshot.Items.Sum(i => i.Count),
 0208                    Items = detailedSnapshot.Items.OrderBy(i => i.RangeFrom).Select(i => new
 0209                    {
 0210                        i.RowNumber,
 0211                        RangeFrom = i.RangeFrom,
 0212                        RangeTo = i.RangeTo,
 0213                        i.Count,
 0214                        i.Percentage,
 0215                        RangeLabel = $"{i.RangeFrom:0.000} - {i.RangeTo:0.000}"
 0216                    })
 0217                });
 218            }
 0219            catch (Exception ex)
 220            {
 0221                return StatusCode(500, new { error = ex.Message });
 222            }
 0223        }
 224    }
 225
 226    // ──────────────────────────────────────────────────────────────────────────
 227    // Request DTOs
 228    // ──────────────────────────────────────────────────────────────────────────
 229
 230    public class FidStatRequest
 231    {
 232        [Required]
 233        [MaxLength(100)]
 234        public string FidName { get; set; } = string.Empty;
 235
 236        public DateTimeOffset PostTime { get; set; }
 237
 238        [Required]
 239        [MinLength(1)]
 240        public List<FidStatItemRequest> Items { get; set; } = new();
 241    }
 242
 243    public class FidStatItemRequest
 244    {
 245        public int Id { get; set; }
 246
 247        public decimal RangeFrom { get; set; }
 248
 249        public decimal RangeTo { get; set; }
 250
 251        public int Count { get; set; }
 252
 253        public decimal Percentage { get; set; }
 254
 255        public string? Indices { get; set; }
 256    }
 257}