< Summary

Information
Class: AspNetCoreGeneratedDocument.Areas_Studio2_Views_User_UserList
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/User/UserList.cshtml
Line coverage
0%
Covered lines: 0
Uncovered lines: 37
Coverable lines: 37
Total lines: 238
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 100
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ExecuteAsync()0%3906620%
<ExecuteAsync()0%272160%
<ExecuteAsync()0%7280%
<ExecuteAsync()0%7280%
<ExecuteAsync()0%7280%
<ExecuteAsync()100%210%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/User/UserList.cshtml

#LineLine coverage
 1@using Microsoft.AspNetCore.Identity
 2@using OzonRepositories.Context.Identity
 3@using OzonDomains.ViewModels
 4@using Services.FiltersServices.FilterModels
 5
 6@inject UserManager<CustomIdentityUser> UserManager
 7
 8@model PageViewModel<CustomIdentityUser, UserFilterModel>
 9
 10@{
 011    ViewData["Title"] = "Пользователи";
 012    Layout = "_AdminLayout";
 013    ViewData["Breadcrumb"] = new List<(string, string?)> { ("Администрирование", null), ("Пользователи", null) };
 014    var allRoles = ViewBag.Roles as List<string> ?? new List<string>();
 015    var allAccesses = ViewBag.Accesses as List<OzonDomains.Models.AccessControl.AccessProfile> ?? new();
 16}
 17
 18@section PageActions {
 19    <a asp-action="Create" class="btn btn-primary">
 20        <i class="ti ti-plus me-1"></i>Новый пользователь
 21    </a>
 22}
 23
 24<!-- Filter -->
 25<div class="card mb-3">
 26    <div class="card-body">
 27        <form asp-action="UserList" method="post" class="row g-3 align-items-end">
 28            <div class="col-md-4">
 29                <label class="form-label">Имя пользователя</label>
 30                <input asp-for="FilterModel.UserName" name="UserName" class="form-control"
 031                       placeholder="Поиск по имени..." value="@Model.FilterModel?.UserName"/>
 32            </div>
 33            <div class="col-md-3">
 34                <label class="form-label">Профиль доступа</label>
 35                <select asp-for="FilterModel.AccessProfile.Id" name="AccessProfileId" class="form-select">
 36                    <option value="">Все профили</option>
 037                    @foreach (var a in allAccesses)
 38                    {
 039                        <option value="@a.Id">@a.Name</option>
 40                    }
 41                </select>
 42            </div>
 43            <div class="col-md-3">
 44                <label class="form-label">Роль</label>
 45                <select asp-for="FilterModel.UserRole" name="UserRole" class="form-select">
 46                    <option value="Все">Все роли</option>
 047                    @foreach (var r in allRoles)
 48                    {
 049                        <option value="@r">@r</option>
 50                    }
 51                </select>
 52            </div>
 53            <div class="col-md-2 d-flex gap-2">
 54                <button type="submit" class="btn btn-primary flex-fill">
 55                    <i class="ti ti-search me-1"></i>Найти
 56                </button>
 57                <a asp-action="UserList" class="btn btn-outline-secondary">
 58                    <i class="ti ti-x"></i>
 59                </a>
 60            </div>
 61        </form>
 62    </div>
 63</div>
 64
 65<!-- Users table -->
 66<div class="card">
 67    <div class="card-header">
 68        <h3 class="card-title">
 69            <i class="ti ti-users me-2"></i>
 070            Всего: <span class="badge bg-blue-lt ms-1">@Model.Items.Count()</span>
 71        </h3>
 72    </div>
 73    <div class="table-responsive">
 74        <table class="table table-vcenter table-hover card-table">
 75            <thead>
 76                <tr>
 77                    <th style="width:40px"></th>
 78                    <th>Пользователь</th>
 79                    <th>Роли</th>
 80                    <th>Профиль доступа</th>
 81                    <th style="width:180px" class="text-center">Действия</th>
 82                </tr>
 83            </thead>
 84            <tbody>
 085            @foreach (var user in Model.Items)
 86            {
 087                var isLockedOut = await UserManager.IsLockedOutAsync(user);
 088                var lockoutEnd = await UserManager.GetLockoutEndDateAsync(user);
 089                var isPermanentLock = isLockedOut && lockoutEnd.HasValue && lockoutEnd.Value >= DateTimeOffset.MaxValue.
 090                var userRoles = await UserManager.GetRolesAsync(user);
 091                var isAdmin = userRoles.Contains("Admin");
 92                <tr class="@(isLockedOut ? "table-warning" : "")">
 93                    <td class="text-center">
 094                        @if (isLockedOut)
 95                        {
 96                            <span class="badge bg-warning" title="@(isPermanentLock ? "Заблокирован навсегда" : $"До {lo
 97                                <i class="ti ti-lock"></i>
 98                            </span>
 99                        }
 100                        else
 101                        {
 0102                            <span class="avatar avatar-xs bg-blue-lt">@(user.UserName?.FirstOrDefault().ToString().ToUpp
 103                        }
 104                    </td>
 105                    <td>
 0106                        <div class="fw-semibold">@user.UserName</div>
 0107                        <div class="text-muted small">@user.Email</div>
 108                    </td>
 109                    <td>
 0110                        @if (userRoles.Any())
 111                        {
 0112                            @foreach (var role in userRoles)
 113                            {
 0114                                <span class="badge @(role == "Admin" ? "bg-red" : "bg-azure") me-1">@role</span>
 115                            }
 116                        }
 117                        else
 118                        {
 119                            <span class="text-muted">—</span>
 120                        }
 121                    </td>
 122                    <td>
 123                        <!-- Inline access profile change -->
 124                        <form asp-action="EditUserAccess" method="post" class="d-flex gap-2 align-items-center">
 125                            <input type="hidden" name="Id" value="@user.Id"/>
 126                            <select name="AccessProfileId" class="form-select form-select-sm"
 127                                    onchange="this.form.submit()" style="max-width:200px;">
 128                                <option value="">— нет профиля —</option>
 0129                                @foreach (var a in allAccesses)
 130                                {
 0131                                    <option value="@a.Id" selected="@(a.Id == user.AccessProfileId)">@a.Name</option>
 132                                }
 133                            </select>
 134                        </form>
 135                    </td>
 136                    <td class="text-center">
 137                        <div class="btn-group btn-group-sm">
 138                            <!-- Role edit -->
 0139                            <a asp-action="Edit" asp-route-userId="@user.Id"
 140                               class="btn btn-outline-secondary" title="Изменить роли">
 141                                <i class="ti ti-user-cog"></i>
 142                            </a>
 143                            <!-- Impersonate -->
 0144                            <a asp-action="Impersonate" asp-route-userId="@user.Id"
 145                               class="btn btn-outline-info" title="Войти как пользователь" target="_blank">
 146                                <i class="ti ti-login"></i>
 147                            </a>
 0148                            @if (!isAdmin)
 149                            {
 0150                                @if (isLockedOut)
 151                                {
 152                                    <form asp-action="UnlockUser" method="post" style="display:inline">
 153                                        <input type="hidden" name="userId" value="@user.Id"/>
 154                                        <button class="btn btn-outline-success" title="Разблокировать">
 155                                            <i class="ti ti-lock-open"></i>
 156                                        </button>
 157                                    </form>
 158                                }
 159                                else
 160                                {
 161                                    <button class="btn btn-outline-danger"
 162                                            title="Заблокировать"
 163                                            data-bs-toggle="modal"
 164                                            data-bs-target="#lockModal"
 0165                                            data-userid="@user.Id"
 0166                                            data-username="@user.UserName">
 167                                        <i class="ti ti-lock"></i>
 168                                    </button>
 169                                }
 170                            }
 171                        </div>
 172                    </td>
 173                </tr>
 0174            }
 175            </tbody>
 176        </table>
 177    </div>
 0178    @if (Model.TotalPages > 1)
 179    {
 180        <div class="card-footer d-flex align-items-center">
 0181            <p class="m-0 text-muted">Страница <strong>@Model.PageNumber</strong> из <strong>@Model.TotalPages</strong><
 182            <ul class="pagination m-0 ms-auto">
 0183                @for (var i = 1; i <= Model.TotalPages; i++)
 184                {
 185                    <li class="page-item @(i == Model.PageNumber ? "active" : "")">
 0186                        <a class="page-link" asp-action="UserList" asp-route-page="@i">@i</a>
 187                    </li>
 188                }
 189            </ul>
 190        </div>
 191    }
 192</div>
 193
 194<!-- Lock Modal -->
 195<div class="modal modal-blur fade" id="lockModal" tabindex="-1">
 196    <div class="modal-dialog modal-sm modal-dialog-centered">
 197        <div class="modal-content">
 198            <div class="modal-header">
 199                <h5 class="modal-title">Заблокировать пользователя</h5>
 200                <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
 201            </div>
 202            <form asp-action="LockUser" method="post" id="lockForm">
 203                <div class="modal-body">
 204                    <input type="hidden" name="userId" id="lockUserId"/>
 205                    <p>Пользователь: <strong id="lockUserName"></strong></p>
 206                    <div class="mb-3">
 207                        <label class="form-label">Тип блокировки</label>
 208                        <select name="lockoutType" id="lockoutType" class="form-select" onchange="toggleDatePicker(this)
 209                            <option value="permanent">Навсегда</option>
 210                            <option value="temporary">До даты</option>
 211                        </select>
 212                    </div>
 213                    <div class="mb-3" id="datePicker" style="display:none">
 214                        <label class="form-label">Дата разблокировки</label>
 215                        <input type="datetime-local" name="lockoutDate" class="form-control"/>
 216                    </div>
 217                </div>
 218                <div class="modal-footer">
 219                    <button type="button" class="btn btn-link link-secondary me-auto" data-bs-dismiss="modal">Отмена</bu
 220                    <button type="submit" class="btn btn-danger">Заблокировать</button>
 221                </div>
 222            </form>
 223        </div>
 224    </div>
 225</div>
 226
 227@section Scripts {
 228<script>
 229document.getElementById('lockModal').addEventListener('show.bs.modal', function (e) {
 230    const btn = e.relatedTarget;
 231    document.getElementById('lockUserId').value = btn.dataset.userid;
 232    document.getElementById('lockUserName').textContent = btn.dataset.username;
 233});
 234function toggleDatePicker(sel) {
 235    document.getElementById('datePicker').style.display = sel.value === 'temporary' ? '' : 'none';
 236}
 237</script>
 238}