< Summary

Information
Class: OzonOrdersWeb.Controllers.UserController
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Controllers/UserController.cs
Line coverage
6%
Covered lines: 12
Uncovered lines: 180
Coverable lines: 192
Total lines: 432
Line coverage: 6.2%
Branch coverage
0%
Covered branches: 0
Total branches: 102
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%11100%
Impersonate()0%2040%
Index()100%11100%
CreateRole()100%210%
CreateRole()0%4260%
Delete()0%620%
UserList()0%210140%
UserList()0%110100%
Edit()0%2040%
Edit()0%4260%
EditUserAccess()0%110100%
Create()100%210%
Create()0%7280%
SetAccessProfile()100%210%
SetAccessProfile()0%4260%
UnlockUser()0%110100%
LockUser()0%506220%

File(s)

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

#LineLine coverage
 1using Microsoft.AspNetCore.Authorization;
 2using Microsoft.AspNetCore.Identity;
 3using Microsoft.AspNetCore.Mvc;
 4using Microsoft.EntityFrameworkCore;
 5using Newtonsoft.Json;
 6using OzonDomains.ViewModels;
 7using OzonOrdersWeb.ViewModels.UserViewModels;
 8using OzonRepositories.Context;
 9using OzonRepositories.Context.Identity;
 10using OzonDomains.Models.AccessControl;
 11using Services.FiltersServices.DataFilterManagers;
 12using Services.FiltersServices.FilterModels;
 13
 14namespace OzonOrdersWeb.Controllers
 15{
 16    [Authorize(Roles = "Admin")]
 17    [Area("Studio2")]
 18    public class UserController : Controller
 19    {
 20        private readonly UserManager<CustomIdentityUser> _userManager;
 21        private readonly RoleManager<IdentityRole> _roleManager;
 22        private readonly SignInManager<CustomIdentityUser> _signInManager;
 23        private readonly ApplicationDbContext _context;
 24        private readonly UserFilterManager _filter;
 125        public UserController(UserManager<CustomIdentityUser> userManager,
 126                              RoleManager<IdentityRole> roleManager,
 127                              SignInManager<CustomIdentityUser> signInManager,
 128                              ApplicationDbContext context,
 129                              UserFilterManager userFilterManager)
 30        {
 131            _userManager = userManager;
 132            _roleManager = roleManager;
 133            _signInManager = signInManager;
 134            _context = context;
 135            _filter = userFilterManager;
 136        }
 37        /// <summary>
 38        /// Имперсонация пользователя (быстрое переключение).
 39        /// Только для админов. Открывать в новом окне!
 40        /// </summary>
 41        [HttpGet]
 42        [Authorize(Roles = "Admin")]
 43        public async Task<IActionResult> Impersonate(string userId)
 44        {
 045            if (string.IsNullOrEmpty(userId))
 046                return BadRequest("UserId is required");
 47
 048            var user = await _userManager.FindByIdAsync(userId);
 049            if (user == null)
 050                return NotFound("User not found");
 51
 52            // Устанавливаем cookie для имперсонации с ограниченным Path "/Impersonation"
 053            var cookieOptions = new CookieOptions
 054            {
 055                HttpOnly = true,
 056                Secure = true,
 057                SameSite = SameSiteMode.Lax,
 058                Path = "/Impersonation",
 059                Expires = DateTimeOffset.UtcNow.AddMinutes(30)
 060            };
 61
 062            Response.Cookies.Append("ImpersonationUserId", user.Id, cookieOptions);
 63
 64            // Перенаправляем в область /Impersonation — middleware применит имперсонированного пользователя
 065            return Redirect("/Impersonation");
 066        }
 67        // Старый маршрут /User остаётся совместимым, но отдельного Index.cshtml больше нет.
 168        public IActionResult Index() => RedirectToAction(nameof(UserList));
 69
 070        public IActionResult CreateRole() => View();
 71        [HttpPost]
 72        public async Task<IActionResult> CreateRole(string name)
 73        {
 074            if (!string.IsNullOrEmpty(name))
 75            {
 076                IdentityResult result = await _roleManager.CreateAsync(new IdentityRole(name));
 077                if (result.Succeeded)
 78                {
 079                    return RedirectToAction("Index");
 80                }
 81                else
 82                {
 083                    foreach (var error in result.Errors)
 84                    {
 085                        ModelState.AddModelError(string.Empty, error.Description);
 86                    }
 87                }
 88            }
 089            return View(name);
 090        }
 91
 92        [HttpPost]
 93        public async Task<IActionResult> Delete(string id)
 94        {
 095            IdentityRole? role = await _roleManager.FindByIdAsync(id);
 096            if (role != null)
 97            {
 098                IdentityResult result = await _roleManager.DeleteAsync(role);
 99            }
 0100            return RedirectToAction("Index");
 0101        }
 102
 103        public async Task<IActionResult> UserList(int page = 1)
 104        {
 105
 0106            var usersWithUserAccess = _userManager.Users.Include(u => u.AccessProfile).ToList();
 0107            var accesses = _context.AccessProfiles.ToList();
 0108            var roles = _roleManager.Roles.Select(r => r.Name).ToList();
 0109            var accessDictionary = accesses.ToDictionary(a => a.Id);
 110
 0111            foreach (var user in usersWithUserAccess)
 112            {
 0113                if (user.AccessProfileId.HasValue && accessDictionary.ContainsKey(user.AccessProfileId.Value))
 114                {
 0115                    user.AccessProfile = accessDictionary[user.AccessProfileId.Value];
 116                }
 117            }
 118
 0119            ViewBag.Accesses = accesses;
 120
 0121            var filterDataString = HttpContext.Request.Cookies["UserFilterData"];
 0122            var filterData = new UserFilterModel();
 0123            if (!string.IsNullOrEmpty(filterDataString))
 124            {
 0125                filterData = JsonConvert.DeserializeObject<UserFilterModel>(filterDataString) ?? filterData;
 0126                usersWithUserAccess = await _filter.FilterByFilterData(usersWithUserAccess, filterData);
 127            }
 0128            ViewBag.Roles = roles; // Передаем список ролей в ViewBag
 129
 0130            return View(new PageViewModel<CustomIdentityUser, UserFilterModel>(usersWithUserAccess, page, 15, filterData
 0131        }
 132
 133        [HttpPost]
 134        public async Task<IActionResult> UserList(UserFilterModel filterModel, int page = 1)
 135        {
 0136            var serializedFilterData = JsonConvert.SerializeObject(filterModel);
 0137            HttpContext.Response.Cookies.Append("UserFilterData", serializedFilterData);
 0138            var roles = _roleManager.Roles.Select(r => r.Name).ToList();
 0139            var usersWithUserAccess = _userManager.Users.Include(u => u.AccessProfile).ToList();
 0140            var accesses = _context.AccessProfiles.ToList();
 141
 0142            var accessDictionary = accesses.ToDictionary(a => a.Id);
 143
 0144            foreach (var user in usersWithUserAccess)
 145            {
 0146                if (user.AccessProfileId.HasValue && accessDictionary.ContainsKey(user.AccessProfileId.Value))
 147                {
 0148                    user.AccessProfile = accessDictionary[user.AccessProfileId.Value];
 149                }
 150            }
 151
 0152            ViewBag.Accesses = accesses;
 0153            ViewBag.Roles = roles; // Передаем список ролей в ViewBag
 154            // Фильтруем пользователей по модели фильтрации
 0155            var filteredUsers = await _filter.FilterByFilterData(usersWithUserAccess, filterModel);
 156
 157            // Возвращаем обновленное представление
 0158            return View(new PageViewModel<CustomIdentityUser, UserFilterModel>(filteredUsers, page, 15, filterModel));
 0159        }
 160
 161
 162
 163        public async Task<IActionResult> Edit(string userId)
 164        {
 165            // получаем пользователя
 0166            CustomIdentityUser? user = await _userManager.FindByIdAsync(userId);
 0167            if (user != null)
 168            {
 169                // получем список ролей пользователя
 0170                var userRoles = await _userManager.GetRolesAsync(user);
 0171                var allRoles = _roleManager.Roles.ToList();
 0172                ChangeRoleViewModel model = new ChangeRoleViewModel
 0173                {
 0174                    UserId = user.Id,
 0175                    UserEmail = user.Email ?? string.Empty,
 0176                    UserRoles = userRoles,
 0177                    AllRoles = allRoles
 0178                };
 0179                return View(model);
 180            }
 181
 0182            return NotFound();
 0183        }
 184
 185        [HttpPost]
 186        [ValidateAntiForgeryToken]
 187        public async Task<IActionResult> Edit(string id, List<string> roles)
 188        {
 0189            var existingUser = await _userManager.FindByIdAsync(id);
 0190            if (existingUser == null) return NotFound();
 191
 0192            var currentRoles = await _userManager.GetRolesAsync(existingUser);
 0193            await _userManager.RemoveFromRolesAsync(existingUser, currentRoles);
 0194            if (roles?.Any() == true)
 0195                await _userManager.AddToRolesAsync(existingUser, roles);
 196
 0197            TempData["SuccessMessage"] = $"Роли пользователя {existingUser.UserName} обновлены.";
 0198            return RedirectToAction(nameof(UserList));
 0199        }
 200
 201
 202        [HttpPost]
 203        [ValidateAntiForgeryToken]
 204        public async Task<IActionResult> EditUserAccess(string id, CustomIdentityUser user)
 205        {
 0206            if (id != user.Id)
 207            {
 0208                return NotFound();
 209            }
 210
 0211            if (ModelState.IsValid)
 212            {
 0213                var existingUser = await _userManager.FindByIdAsync(id);
 0214                if (existingUser != null)
 215                {
 0216                    existingUser.AccessProfileId = user.AccessProfileId;
 217
 0218                    var result = await _userManager.UpdateAsync(existingUser);
 0219                    if (result.Succeeded)
 220                    {
 0221                        return RedirectToAction(nameof(UserList));
 222                    }
 223                    else
 224                    {
 0225                        foreach (var error in result.Errors)
 226                        {
 0227                            ModelState.AddModelError(string.Empty, error.Description);
 228                        }
 229                    }
 230                }
 231                else
 232                {
 0233                    return NotFound();
 234                }
 235            }
 236
 0237            return View(user);
 0238        }
 239
 240        [HttpGet]
 241        public IActionResult Create()
 242        {
 0243            return View();
 244        }
 245
 246        [HttpPost]
 247        public async Task<IActionResult> Create(RegisterViewModel model)
 248        {
 0249            if (ModelState.IsValid)
 250            {
 0251                var user = new CustomIdentityUser { UserName = model.Username, Email = model.Username };
 252
 0253                var result = await _userManager.CreateAsync(user, model.Password);
 254
 0255                if (result.Succeeded)
 256                {
 0257                    var roleExists = await _roleManager.RoleExistsAsync("user");
 0258                    if (!roleExists)
 259                    {
 0260                        await _roleManager.CreateAsync(new IdentityRole("user"));
 261                    }
 0262                    await _userManager.AddToRoleAsync(user, "user");
 263
 0264                    return RedirectToAction("Index", "Home");
 265                }
 266
 0267                foreach (var error in result.Errors)
 268                {
 0269                    ModelState.AddModelError(string.Empty, error.Description);
 270                }
 0271            }
 272
 0273            return View(model);
 0274        }
 275
 276        public async Task<IActionResult> SetAccessProfile(string userId)
 277        {
 0278            await Task.CompletedTask;
 0279            var viewModel = new SetUserAccessViewModel
 0280            {
 0281                AccessProfiles = _context.AccessProfiles.ToList(),
 0282                UserId = userId
 0283            };
 284
 0285            return View(viewModel);
 0286        }
 287
 288        [HttpPost]
 289        public async Task<IActionResult> SetAccessProfile(SetUserAccessViewModel viewModel)
 290        {
 0291            if (viewModel.UserId != null && viewModel.SelectedAccessProfileId != null)
 292            {
 0293                var user = await _userManager.FindByIdAsync(viewModel.UserId);
 0294                var access = await _context.AccessProfiles.FindAsync(viewModel.SelectedAccessProfileId);
 0295                if (user != null)
 296                {
 0297                    user.AccessProfile = access;
 0298                    await _userManager.UpdateAsync(user);
 0299                    return RedirectToAction("UserList");
 300                }
 0301            }
 302
 0303            viewModel.AccessProfiles = await _context.AccessProfiles.ToListAsync();
 304
 0305            return View(viewModel);
 0306        }
 307
 308        /// <summary>
 309        /// Разблокирует аккаунт пользователя
 310        /// </summary>
 311        [HttpPost]
 312        [ValidateAntiForgeryToken]
 313        public async Task<IActionResult> UnlockUser(string userId)
 314        {
 0315            if (string.IsNullOrEmpty(userId))
 316            {
 0317                return BadRequest("ID пользователя не указан");
 318            }
 319
 0320            var user = await _userManager.FindByIdAsync(userId);
 0321            if (user == null)
 322            {
 0323                return NotFound("Пользователь не найден");
 324            }
 325
 326            // Снимаем блокировку аккаунта
 0327            var lockoutResult = await _userManager.SetLockoutEndDateAsync(user, null);
 328            // Сбрасываем счетчик неудачных попыток входа
 0329            var resetResult = await _userManager.ResetAccessFailedCountAsync(user);
 330
 0331            if (lockoutResult.Succeeded && resetResult.Succeeded)
 332            {
 0333                TempData["SuccessMessage"] = $"Аккаунт пользователя {user.UserName} успешно разблокирован.";
 0334                return RedirectToAction(nameof(UserList));
 335            }
 336            else
 337            {
 0338                var errors = lockoutResult.Errors.Concat(resetResult.Errors);
 0339                foreach (var error in errors)
 340                {
 0341                    ModelState.AddModelError(string.Empty, error.Description);
 342                }
 0343                TempData["ErrorMessage"] = "Ошибка при разблокировке аккаунта.";
 0344                return RedirectToAction(nameof(UserList));
 345            }
 0346        }
 347
 348        /// <summary>
 349        /// Блокирует аккаунт пользователя
 350        /// </summary>
 351        [HttpPost]
 352        [ValidateAntiForgeryToken]
 353        public async Task<IActionResult> LockUser(string userId, string lockoutType, DateTime? lockoutDate)
 354        {
 0355            if (string.IsNullOrEmpty(userId))
 356            {
 0357                return BadRequest("ID пользователя не указан");
 358            }
 359
 0360            var user = await _userManager.FindByIdAsync(userId);
 0361            if (user == null)
 362            {
 0363                return NotFound("Пользователь не найден");
 364            }
 365
 366            // Проверяем, не является ли пользователь администратором
 0367            var roles = await _userManager.GetRolesAsync(user);
 0368            if (roles.Contains("Admin"))
 369            {
 0370                TempData["ErrorMessage"] = "Нельзя заблокировать аккаунт администратора.";
 0371                return RedirectToAction(nameof(UserList));
 372            }
 373
 0374            DateTimeOffset? lockoutEndDate = null;
 375
 0376            if (lockoutType == "permanent")
 377            {
 378                // Блокировка навсегда (используем максимальную дату)
 0379                lockoutEndDate = DateTimeOffset.MaxValue;
 380            }
 0381            else if (lockoutType == "temporary" && lockoutDate.HasValue)
 382            {
 383                // Временная блокировка до указанной даты
 384                // Используем локальное время пользователя
 0385                lockoutEndDate = new DateTimeOffset(lockoutDate.Value, TimeZoneInfo.Local.GetUtcOffset(lockoutDate.Value
 386            }
 387            else
 388            {
 0389                TempData["ErrorMessage"] = "Неверные параметры блокировки.";
 0390                return RedirectToAction(nameof(UserList));
 391            }
 392
 393            // Устанавливаем дату окончания блокировки
 0394            var lockoutResult = await _userManager.SetLockoutEndDateAsync(user, lockoutEndDate);
 395            // Увеличиваем счетчик неудачных попыток, чтобы активировать блокировку
 0396            await _userManager.AccessFailedAsync(user);
 397
 398            // Инвалидируем все сессии пользователя (выбрасывает из системы)
 0399            await _userManager.UpdateSecurityStampAsync(user);
 400
 0401            if (lockoutResult.Succeeded)
 402            {
 403                // Если пользователь сейчас залогинен, разлогиниваем его
 0404                var currentUser = await _userManager.GetUserAsync(User);
 0405                if (currentUser != null && currentUser.Id == user.Id)
 406                {
 407                    // Если блокируется текущий пользователь (что маловероятно, но на всякий случай)
 0408                    await _signInManager.SignOutAsync();
 409                }
 410
 411                // Проверяем, залогинен ли заблокированный пользователь в другом месте
 412                // Инвалидация SecurityStamp автоматически разлогинит пользователя при следующем запросе
 413
 0414                string message = lockoutType == "permanent"
 0415                    ? $"Аккаунт пользователя {user.UserName} заблокирован навсегда. Пользователь будет разлогинен из все
 0416                    : $"Аккаунт пользователя {user.UserName} заблокирован до {lockoutEndDate!.Value.LocalDateTime:dd.MM.
 0417                TempData["SuccessMessage"] = message;
 0418                return RedirectToAction(nameof(UserList));
 419            }
 420            else
 421            {
 0422                foreach (var error in lockoutResult.Errors)
 423                {
 0424                    ModelState.AddModelError(string.Empty, error.Description);
 425                }
 0426                TempData["ErrorMessage"] = "Ошибка при блокировке аккаунта.";
 0427                return RedirectToAction(nameof(UserList));
 428            }
 0429        }
 430
 431    }
 432}