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
+
+
+
+
+
+
+
+ @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
+
+
+
+
+
+ @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 list
+
+
+
+ | Name |
+ Edit |
+
+
+
+ @{
+ foreach (ApplicationUser user in Model.getUsers())
+ {
+
+ | @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);
}