diff --git a/FactorioWebInterface/Pages/Admin/AccountOverview.cshtml b/FactorioWebInterface/Pages/Admin/AccountOverview.cshtml new file mode 100644 index 00000000..f6a277c1 --- /dev/null +++ b/FactorioWebInterface/Pages/Admin/AccountOverview.cshtml @@ -0,0 +1,58 @@ +@page +@model FactorioWebInterface.Pages.Admin.AccountOverviewModel +@{ + ViewData["Title"] = "Account Overview"; +} + +@section Scripts { + @await Html.PartialAsync("_ValidationScriptsPartial") +} + +
+ +

Account Overview

+ +
+
+
+

Create User

+
+
+
+ +
+ +
+ +
+
+ +
+ @for (var i = 0; i < Model.Input.Roles.Count(); i++) + { + @Model.Input.Roles[i].Role
+ } +
+ +
+ +
+
+
+ +
+ + @if (Model.GeneratedPassword != null && Model.GeneratedPassword.Length > 0) + { +
+

New password generated:

+
+

@Model.GeneratedPassword

+
+

Please advice recipient to change password ASAP

+ } +
+
+
+ + diff --git a/FactorioWebInterface/Pages/Admin/AccountOverview.cshtml.cs b/FactorioWebInterface/Pages/Admin/AccountOverview.cshtml.cs new file mode 100644 index 00000000..9bafae66 --- /dev/null +++ b/FactorioWebInterface/Pages/Admin/AccountOverview.cshtml.cs @@ -0,0 +1,198 @@ +using FactorioWebInterface.Data; +using FactorioWebInterface.Services; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; + +namespace FactorioWebInterface.Pages.Admin +{ + //[Authorize(Roles = Constants.AdminRole + Constants.RootRole) ] + public class AccountOverviewModel : PageModel + { + private readonly SignInManager _signInManager; + private readonly IWebAccountManager _accountManager; + private readonly ILogger _logger; + + public AccountOverviewModel( + IWebAccountManager accountManager, + SignInManager signInManager, + ILogger logger + ) + { + _accountManager = accountManager; + _signInManager = signInManager; + _logger = logger; + } + + public ApplicationUser ManagingUser { get; set; } + public string? GeneratedPassword { get; set; } + + public class AccountRole + { + public string Role { get; set; } + + public bool IsSelected { get; set; } = false; + } + + [BindProperty] + public InputModel Input { get; set; } = default!; + + public class InputModel + { + public ApplicationUser User { get; set; } = default!; + + [DataType(DataType.Text)] + [Display(Name = "Username")] + public string UserName { get; set; } = default!; + + [Display(Name = "Select role")] + public List Roles { get; } = GenerateAccountRoleList(); + + private static List GenerateAccountRoleList() + { + var adminRole = new AccountRole + { + Role = Constants.AdminRole + }; + var rootRole = new AccountRole + { + Role = Constants.RootRole + }; + return new List() { adminRole, rootRole }; + } + } + + public async Task IsInRole(ApplicationUser user, string role) + { + return await _accountManager.IsInRoleAsync(user, role); + } + + public async Task OnGetAsync(string userId, string generatedPassword) + { + var user = await _accountManager.GetUserAsync(User); + + if (user == null || user.Suspended) + { + HttpContext.Session.SetString("returnUrl", "account"); + return RedirectToPage("signIn"); + } + + ManagingUser = await _accountManager.FindByIdAsync(userId); + + GeneratedPassword = generatedPassword; + + return Page(); + } + + public async Task OnPostAsync(string userId) + { + var user = await _accountManager.GetUserAsync(User); + if (user == null || user.Suspended) + { + HttpContext.Session.SetString("returnUrl", "accountoverview"); + return RedirectToPage("signIn"); + } + + ManagingUser = await _accountManager.FindByIdAsync(userId); + + return Page(); + } + + private void PopulateInputModel(ApplicationUser user) + { + Input.User = user; + Input.UserName = user.UserName; + } + + public async Task OnPostUpdateAccountAsync() + { + + var user = await _accountManager.GetUserAsync(User); + + if (user == null || user.Suspended) + { + HttpContext.Session.SetString("returnUrl", "account"); + return RedirectToPage("signIn"); + } + + if (!ModelState.IsValid) + { + return Page(); + } + + if (Input.UserName != Input.User.UserName) + { + await _accountManager.ChangeUsernameAsync(Input.User, Input.UserName); + } + foreach (var role in Input.Roles) + { + var inRole = await _accountManager.IsInRoleAsync(Input.User, role.Role); + if (role.IsSelected && inRole) + { + break; + } + + if (role.IsSelected && !inRole) + { + var result = await _accountManager.AddRoleAsync(Input.User, role.Role); + if (!result.Succeeded) + { + foreach (var error in result.Errors) + { + ModelState.AddModelError(string.Empty, error.Description); + } + + return Page(); + } + break; + } + + if (!role.IsSelected && inRole) + { + var result = await _accountManager.RemoveRoleAsync(Input.User, role.Role); + if (!result.Succeeded) + { + foreach (var error in result.Errors) + { + ModelState.AddModelError(string.Empty, error.Description); + } + + return Page(); + } + } + } + + _logger.LogInformation($"The account {UserName} has been updated"); + + return RedirectToPage(new {UserId = Input.User.Id, PasswordReset = false}); + } + + public async Task OnPostResetPasswordAsync() + { + var user = await _accountManager.GetUserAsync(User); + + if (user == null || user.Suspended) + { + HttpContext.Session.SetString("returnUrl", "account"); + return RedirectToPage("signIn"); + } + + if (!ModelState.IsValid) + { + return Page(); + } + + var password = await _accountManager.ResetPasswordAsync(user); + + _logger.LogInformation($"User {user.UserName} changed password"); + + return RedirectToPage(new { Password = true }); + } + } +} \ No newline at end of file diff --git a/FactorioWebInterface/Pages/Admin/CreateAccount.cshtml b/FactorioWebInterface/Pages/Admin/CreateAccount.cshtml new file mode 100644 index 00000000..61ef7ced --- /dev/null +++ b/FactorioWebInterface/Pages/Admin/CreateAccount.cshtml @@ -0,0 +1,64 @@ +@page +@model FactorioWebInterface.Pages.Admin.CreateAccountModel +@{ + ViewData["Title"] = "Create New Account"; +} + +@section Scripts { + @await Html.PartialAsync("_ValidationScriptsPartial") +} + +
+ +

Create New Account

+ +
+
+
+

Create User

+
+
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ @foreach (var item in Model.Roles) + { + @item + } +
+ +
+ +
+ + @if (Model.AccountCreated) + { +
+

Account created

+ } +
+
+
+ + diff --git a/FactorioWebInterface/Pages/Admin/CreateAccount.cshtml.cs b/FactorioWebInterface/Pages/Admin/CreateAccount.cshtml.cs new file mode 100644 index 00000000..51efc71b --- /dev/null +++ b/FactorioWebInterface/Pages/Admin/CreateAccount.cshtml.cs @@ -0,0 +1,112 @@ +using FactorioWebInterface.Data; +using FactorioWebInterface.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; + +namespace FactorioWebInterface.Pages.Admin +{ + public class CreateAccountModel : PageModel + { + private readonly IWebAccountManager _accountManager; + private readonly ILogger _logger; + private const string sessionUrl = "createaccount"; + + public CreateAccountModel( + IWebAccountManager accountManager, + ILogger logger + ) + { + _accountManager = accountManager; + _logger = logger; + } + + public bool AccountCreated { get; set; } + + [BindProperty] + public InputModel Input { get; set; } = default!; + + public string[] Roles { get; set; } = { Constants.AdminRole, Constants.RootRole }; + + public class InputModel + { + [Required] + [DataType(DataType.Text)] + [Display(Name = "Username")] + public string UserName { get; set; } = default!; + + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + [Display(Name = "Password")] + public string Password { get; set; } = default!; + + [DataType(DataType.Password)] + [Display(Name = "Confirm password")] + [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] + public string ConfirmPassword { get; set; } = default!; + + [Display(Name = "Select role")] + public string Role { get; set; } = Constants.AdminRole; + } + + public async Task OnGetAsync(bool accountCreated) + { + var user = await _accountManager.GetUserAsync(User); + + if (!await IsAuthorized(user)) + { + return UnauthorizedRedirect(); + } + + AccountCreated = accountCreated; + + return Page(); + } + + public async Task OnPostCreateAccountAsync() + { + var user = await _accountManager.GetUserAsync(User); + + if (!await IsAuthorized(user)) + { + return UnauthorizedRedirect(); + } + + var result = await _accountManager.CreateAccountAsync(Input.UserName, Input.Password, new string[]{Input.Role}); + + if (!result.Succeeded) + { + foreach (var error in result.Errors) + { + ModelState.AddModelError(string.Empty, error.Description); + } + + return Page(); + } + + return RedirectToPage(new { AccountCreated = true }); + } + + private async Task IsAuthorized(ApplicationUser user) + { + if (user == null || user.Suspended || !await _accountManager.IsInRoleAsync(user, Constants.RootRole)) + { + return false; + } + return true; + } + + private IActionResult UnauthorizedRedirect() + { + HttpContext.Session.SetString("returnUrl", sessionUrl); + return RedirectToPage("signIn"); + } + } +} \ No newline at end of file diff --git a/FactorioWebInterface/Pages/Admin/ManageAccounts.cshtml b/FactorioWebInterface/Pages/Admin/ManageAccounts.cshtml new file mode 100644 index 00000000..da7db485 --- /dev/null +++ b/FactorioWebInterface/Pages/Admin/ManageAccounts.cshtml @@ -0,0 +1,42 @@ +@page +@model FactorioWebInterface.Pages.Admin.ManageAccountsModel +@using FactorioWebInterface.Data; +@{ + ViewData["Title"] = "Account managing"; +} + +
+ +
+

Account manager

+
+ +
+

Account list

+ + + + + + + + + @{ + foreach (ApplicationUser user in Model.getUsers()) + { + + + + + } + } + +
NameEdit
@user.UserName +
+ + +
+
+
+
+ diff --git a/FactorioWebInterface/Pages/Admin/ManageAccounts.cshtml.cs b/FactorioWebInterface/Pages/Admin/ManageAccounts.cshtml.cs new file mode 100644 index 00000000..5b656f88 --- /dev/null +++ b/FactorioWebInterface/Pages/Admin/ManageAccounts.cshtml.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using FactorioWebInterface.Data; +using FactorioWebInterface.Services; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace FactorioWebInterface.Pages.Admin +{ + public class ManageAccountsModel : PageModel + { + + private readonly IWebAccountManager _accountManager; + public ManageAccountsModel(IWebAccountManager accountManager) + { + _accountManager = accountManager; + } + + public List getUsers() + { + return _accountManager.GetUsers(); + } + + public void OnGet() + { + } + } +} diff --git a/FactorioWebInterface/Pages/Admin/_AdminNavBarPartial.cshtml b/FactorioWebInterface/Pages/Admin/_AdminNavBarPartial.cshtml index 73fce7c1..658c9ff7 100644 --- a/FactorioWebInterface/Pages/Admin/_AdminNavBarPartial.cshtml +++ b/FactorioWebInterface/Pages/Admin/_AdminNavBarPartial.cshtml @@ -1,9 +1,9 @@ @using Microsoft.AspNetCore.Identity; @using FactorioWebInterface.Data; -@inject UserManager userManger; +@inject UserManager userManager; @{ - var user = await userManger.GetUserAsync(User); + var user = await userManager.GetUserAsync(User); }