public async Task<ActionResult> Edit(string userName, ControllableViewModelParams modelParams)
      {
         if (userName == null)
         {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
         }

         var viewModel = await UserManager.Users.Where(x => x.UserName == userName)
            .Select(user => new ApplicationUserViewModels.EditViewModel
            {
               UserId = user.Id,
               UserName = user.UserName,
               LockoutEnabled = user.LockoutEnabled,
               LockoutEndDateUtc = user.LockoutEndDateUtc,
               RoleList = RoleManager.Roles
                  .Select(role => new SelectListItem
                  {
                     Value = role.Id,
                     Text = role.Name
                  }).ToList(),
               SelectedRoles = RoleManager.Roles
               .Where(role => role.Users.Any(userRole => userRole.UserId == user.Id))
               .Select(role => role.Id).ToList()
            }).SingleOrDefaultAsync();

         if (viewModel == null)
         {
            return HttpNotFound();
         }

         ViewData.SetControllableViewModelParams(modelParams);

         return View(viewModel);
      }
      public async Task<ActionResult> Details(int? id, ControllableViewModelParams modelParams)
      {
         if (id == null)
         {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
         }

         var updateEvent = await db.UpdateEvents.Where(x => x.Id == id).Select(x => new UpdateEventViewModels.DetailsViewModel
         {
            Id = x.Id,
            TrainingProviderName = x.TrainingProvider.Name,
            Description = x.Description,
            StartedOn = x.StartedOn,
            EndedOn = x.EndedOn,
            ErrorData = x.ErrorData,
            UpdateResult = x.UpdateResult,
            Added = new UpdateEventViewModels.StatisticViewModel
            {
               Categories = x.Added.Categories,
               Courses = x.Added.Courses,
               Authors = x.Added.Authors,

               HasCategoriesUpdateLog = x.CategoriesUpdates.Any(u => u.OperationType == OperationType.Add),
               HasCoursesUpdateLog = x.CoursesUpdates.Any(u => u.OperationType == OperationType.Add),
               HasAuthorsUpdateLog = x.AuthorsUpdates.Any(u => u.OperationType == OperationType.Add)
            },
            Deleted = new UpdateEventViewModels.StatisticViewModel
            {
               Categories = x.Deleted.Categories,
               Courses = x.Deleted.Courses,
               Authors = x.Deleted.Authors,

               HasCategoriesUpdateLog = x.CategoriesUpdates.Any(u => u.OperationType == OperationType.Delete),
               HasCoursesUpdateLog = x.CoursesUpdates.Any(u => u.OperationType == OperationType.Delete),
               HasAuthorsUpdateLog = x.AuthorsUpdates.Any(u => u.OperationType == OperationType.Delete)
            },
            Modified = new UpdateEventViewModels.StatisticViewModel
            {
               Categories = x.Modified.Categories,
               Courses = x.Modified.Courses,
               Authors = x.Modified.Authors,

               HasCategoriesUpdateLog = x.CategoriesUpdates.Any(u => u.OperationType == OperationType.Modify),
               HasCoursesUpdateLog = x.CoursesUpdates.Any(u => u.OperationType == OperationType.Modify && u.CourseBackup != null),
               HasAuthorsUpdateLog = x.AuthorsUpdates.Any(u => u.OperationType == OperationType.Modify)
            }
         }).SingleOrDefaultAsync();

         if (updateEvent == null)
         {
            return HttpNotFound();
         }

         ViewData.SetControllableViewModelParams(modelParams);

         return View(updateEvent);
      }
      public async Task<ActionResult> Index(ControllableViewModelParams modelParams)
      {
         var updateEventsQuery = db.UpdateEvents.Select(x => new UpdateEventViewModels.IndexViewModel
         {
            Id = x.Id,
            TrainingProviderName = x.TrainingProvider.Name,
            Description = x.Description,
            StartedOn = x.StartedOn,
            EndedOn = x.EndedOn,
            UpdateResult = x.UpdateResult
         });

         var controllableViewModel = await UpdateEventViewModels.IndexViewModel.ToControlableViewModelAsync(updateEventsQuery, modelParams);

         return View(controllableViewModel);
      }
      public async Task<ActionResult> CategoryCourses(int? categoryId, ControllableViewModelParams modelParams,
         IEnumerable<CoursesWithoutSpecializationsViewModels.SelectedSpecializationsModel> selectedSpecializations)
      {
         if (categoryId == null)
         {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
         }

         if (ModelState.IsValid)
         {
            do
            {
               var courseSpecializations = selectedSpecializations
                  .Where(x => x.Specializations != null && x.Specializations.Any())
                  .SelectMany(x => x.GetCourseSpecializations());

               _db.CourseSpecializations.AddRange(courseSpecializations);

               try
               {
                  await _db.SaveChangesAsync();
               }
                  // ReSharper disable once CatchAllClause
               catch (Exception ex)
               {
                  ModelState.AddModelError("", ex.ToString());
                  break;
               }

               return RedirectToAction("Index", modelParams);

               // only for flow control
#pragma warning disable 162
            } while (false);
#pragma warning restore 162
         }

         var viewModel = await GetCategoryCoursesViewModel(categoryId.Value);

         if (viewModel != null)
         {
            ViewData.SetControllableViewModelParams(modelParams);
         }

         return View(viewModel);
      }
      public async Task<ActionResult> CategoryCourses(int? categoryId, ControllableViewModelParams modelParams)
      {
         if (categoryId == null)
         {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
         }

         var viewModel = await GetCategoryCoursesViewModel(categoryId.Value);

         if (viewModel == null)
         {
            return HttpNotFound();
         }

         ViewData.SetControllableViewModelParams(modelParams);

         return View(viewModel);
      }
      public async Task<ActionResult> Index(ControllableViewModelParams modelParams)
      {
         var coursesQuery = _db.Courses.Where(x => !x.IsDeleted &&
                                                   !x.CourseSpecializations.Any());

         var viewModelQuery = _db.Categories
            .Where(x => coursesQuery.Any(course => course.CategoryId == x.Id) && !x.IsDeleted)
            .Select(x => new CoursesWithoutSpecializationsViewModels.IndexViewModel
            {
               TrainingProviderName = x.TrainingProvider.Name,
               CategoryId = x.Id,
               CategoryName = x.Title,
               CourseCount = coursesQuery.Count(course => course.CategoryId == x.Id)
            });

         var controllableViewModel = await CoursesWithoutSpecializationsViewModels.IndexViewModel.ToControllableViewModelAsync(viewModelQuery, modelParams);

         return View(controllableViewModel);
      }
      public async Task<ActionResult> Index(ControllableViewModelParams modelParams)
      {
         var viewModelQuery = UserManager.Users
            .Select(user => new ApplicationUserViewModels.IndexViewModel
            {
               UserName = user.UserName,
               RegisteredOnUtc = user.RegisteredOnUtc,
               LastLoginOnUtc = user.LastLoginOnUtc,
               LockoutEnabled = user.LockoutEnabled,
               LockoutEndDateUtc = user.LockoutEndDateUtc,
               AccessFailedCount = user.AccessFailedCount,
               IsAdmin = RoleManager.Roles
                  .FirstOrDefault(role => role.Name == AppConstants.UserRole.Administrator)
                  .Users.Any(userRole => userRole.UserId == user.Id)
            });

         var controllableViewModel = await ApplicationUserViewModels.IndexViewModel.ToControlableViewModelAsync(viewModelQuery, modelParams);

         return View(controllableViewModel);
      }
      public async Task<ActionResult> UnLockAccount(string userId, ControllableViewModelParams modelParams)
      {
         var currentUser = await UserManager.FindByIdAsync(userId);
         if (currentUser == null)
         {
            return HttpNotFound();
         }

         await UserManager.ResetAccessFailedCountAsync(currentUser.Id);
         await UserManager.SetLockoutEndDateAsync(currentUser.Id, DateTimeOffset.UtcNow);

         return RedirectToAction("Index", modelParams);
      }
      public async Task<ActionResult> LockAccount(string userId, ControllableViewModelParams modelParams)
      {
         var currentUser = await UserManager.FindByIdAsync(userId);
         if (currentUser == null)
         {
            return HttpNotFound();
         }

         var userIsAnAdministrator = await UserManager.IsInRoleAsync(currentUser.Id, AppConstants.UserRole.Administrator);

         if (userIsAnAdministrator)
         {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest, "Cannot lock user in an administrator role.");
         }

         await UserManager.ResetAccessFailedCountAsync(currentUser.Id);
         await UserManager.SetLockoutEndDateAsync(currentUser.Id, DateTimeOffset.UtcNow.AddYears(1));

         return RedirectToAction("Index", modelParams);
      }
      public async Task<ActionResult> Edit(ApplicationUserViewModels.EditViewModel editModel, ControllableViewModelParams modelParams)
      {
         if (ModelState.IsValid)
         {
            do
            {
               var currentUser = await UserManager.FindByIdAsync(editModel.UserId);

               if (currentUser == null)
               {
                  return HttpNotFound();
               }

               var adminRole = await RoleManager.FindByNameAsync(AppConstants.UserRole.Administrator);
               var currentUserRolesIds = currentUser.Roles.Select(x => x.RoleId).ToList();

               // if user is currently stored having the Administrator role
               var isThisUserAnAdmin = currentUserRolesIds.Contains(adminRole.Id);

               // and the user did not have Administrator role checked
               var isThisUserAdminDeselected = editModel.SelectedRoles.All(roleId => roleId != adminRole.Id);

               // and the current stored count of users with Administrator role == 1
               var isOnlyOneUserAnAdmin = adminRole.Users.Count == 1;

               // then prevent the removal of the Administrator role.
               if (isThisUserAnAdmin && isThisUserAdminDeselected && isOnlyOneUserAnAdmin)
               {
                  ModelState.AddModelError("", "At least one user must retain the 'administrator' role.");
                  break;
               }

               if (currentUser.LockoutEnabled != editModel.LockoutEnabled)
               {
                  currentUser.LockoutEnabled = editModel.LockoutEnabled;

                  var result = await UserManager.UpdateAsync(currentUser);
                  if (!result.Succeeded)
                  {
                     ModelState.AddModelError("", result.Errors.First());
                     break;
                  }
               }

               var allRoles = await RoleManager.Roles.ToListAsync();

               var deletedRolesIds = currentUserRolesIds.Except(editModel.SelectedRoles).ToList();

               if (deletedRolesIds.Any())
               {
                  var rolesToRemove = allRoles
                     .Where(x => deletedRolesIds.Contains(x.Id)).Select(x => x.Name)
                     .ToArray();

                  var result = await UserManager.RemoveFromRolesAsync(currentUser.Id, rolesToRemove);

                  if (!result.Succeeded)
                  {
                     ModelState.AddModelError("", result.Errors.First());
                     break;
                  }
               }


               var newRolesIds = editModel.SelectedRoles.Except(currentUserRolesIds).ToArray();

               if (newRolesIds.Any())
               {
                  var rolesToAdd = allRoles
                     .Where(x => newRolesIds.Contains(x.Id)).Select(x => x.Name)
                     .ToArray();

                  var result = await UserManager.AddToRolesAsync(currentUser.Id, rolesToAdd);

                  if (!result.Succeeded)
                  {
                     ModelState.AddModelError("", result.Errors.First());
                     break;
                  }
               }

               return RedirectToAction("Index", modelParams);
#pragma warning disable 162
            } while (false);
#pragma warning restore 162
         }

         editModel.RoleList = await RoleManager.Roles
            .Select(x => new SelectListItem
            {
               Text = x.Name,
               Value = x.Id
            }).ToListAsync();

         return View(editModel);
      }