| | | 1 | | using Microsoft.AspNetCore.Mvc; |
| | | 2 | | using Microsoft.EntityFrameworkCore; |
| | | 3 | | using OzonOrdersWeb.WebServices.Admin; |
| | | 4 | | using OzonOrdersWeb.WebServices.Grid; |
| | | 5 | | using OzonRepositories.Context; |
| | | 6 | | |
| | | 7 | | namespace OzonOrdersWeb.Areas.Admin.Controllers; |
| | | 8 | | |
| | | 9 | | /// <summary> |
| | | 10 | | /// Журнал аудита изменений системы прав: серверный грид AG Grid (фильтры, сортировка, фасеты — на сервере). |
| | | 11 | | /// </summary> |
| | | 12 | | public class AuditLogController : AdminAreaControllerBase |
| | | 13 | | { |
| | | 14 | | private readonly ApplicationDbContext _db; |
| | 0 | 15 | | public AuditLogController(ApplicationDbContext db) { _db = db; } |
| | | 16 | | |
| | | 17 | | /// <summary>Каркас журнала: строки грузит серверный грид (Grid/GridFacets).</summary> |
| | | 18 | | public IActionResult Index() |
| | | 19 | | { |
| | 0 | 20 | | ViewData["Title"] = "Журнал изменений"; |
| | 0 | 21 | | ViewData["Breadcrumb"] = new List<(string, string?)> { ("Админка", Url.Action("Index", "Home")), ("Журнал", null |
| | | 22 | | // Только query-строка: параметр «action» у действия связывается со значением маршрута (Index). |
| | 0 | 23 | | ViewBag.F = new[] { "action", "entity", "user" }.ToDictionary(k => k, k => (string?)Request.Query[k].ToString()) |
| | 0 | 24 | | return View(); |
| | | 25 | | } |
| | | 26 | | |
| | | 27 | | /// <summary>Блок строк журнала для AG Grid Infinite Row Model (фильтры, сортировка, поиск — по всему журналу).</sum |
| | | 28 | | [HttpPost] |
| | | 29 | | [ValidateAntiForgeryToken] |
| | | 30 | | public async Task<IActionResult> Grid([FromBody] ServerGridRequest? request, CancellationToken ct) |
| | | 31 | | { |
| | 0 | 32 | | var error = ServerGridQuery.Validate(request); |
| | 0 | 33 | | if (error != null) return BadRequest(new { success = false, error }); |
| | | 34 | | |
| | 0 | 35 | | var query = AdminAuditGridDefinition.ApplyParams(_db.AuditLogEntries.AsNoTracking(), request!.Params); |
| | 0 | 36 | | var (items, total) = await ServerGridQuery.PageAsync(query, AdminAuditGridDefinition.Entries, request, ct); |
| | 0 | 37 | | var rows = items.Select(e => new { e.Id, e.Timestamp, e.ActorUserName, e.Action, e.EntityType, e.EntityId, e.IpA |
| | 0 | 38 | | var lastRow = request.StartRow + rows.Count >= total ? total : -1; |
| | 0 | 39 | | return Ok(new { success = true, rows, totalCount = total, lastRow }); |
| | 0 | 40 | | } |
| | | 41 | | |
| | | 42 | | /// <summary>Счётчики значений set-фильтров журнала (действие, сущность, пользователь).</summary> |
| | | 43 | | [HttpPost] |
| | | 44 | | [ValidateAntiForgeryToken] |
| | | 45 | | public async Task<IActionResult> GridFacets([FromBody] ServerGridRequest? request, CancellationToken ct) |
| | | 46 | | { |
| | 0 | 47 | | if (request is null || string.IsNullOrWhiteSpace(request.ColId)) return BadRequest(new { success = false, error |
| | 0 | 48 | | request.StartRow = 0; |
| | 0 | 49 | | request.EndRow = 1; |
| | 0 | 50 | | var error = ServerGridQuery.Validate(request); |
| | 0 | 51 | | if (error != null) return BadRequest(new { success = false, error }); |
| | | 52 | | |
| | 0 | 53 | | var query = AdminAuditGridDefinition.ApplyParams(_db.AuditLogEntries.AsNoTracking(), request.Params); |
| | 0 | 54 | | var values = await ServerGridQuery.FacetsAsync(query, AdminAuditGridDefinition.Entries, request, ct); |
| | 0 | 55 | | return Ok(new { success = true, values }); |
| | 0 | 56 | | } |
| | | 57 | | |
| | | 58 | | public async Task<IActionResult> Details(long id, CancellationToken ct) |
| | | 59 | | { |
| | 0 | 60 | | var e = await _db.AuditLogEntries.FirstOrDefaultAsync(x => x.Id == id, ct); |
| | 0 | 61 | | if (e == null) return NotFound(); |
| | 0 | 62 | | ViewData["Title"] = $"Запись #{e.Id}"; |
| | 0 | 63 | | return View(e); |
| | 0 | 64 | | } |
| | | 65 | | } |