admin panel work

This commit is contained in:
Mikhail
2024-11-03 14:10:43 -05:00
parent 419a7d0a6a
commit 1d11cee520
13 changed files with 330 additions and 23 deletions

View File

@@ -83,7 +83,15 @@ namespace EpinelPS.Controllers
}
}
var user = new User() { ID = uid, Password = req.password, RegisterTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds(), Username = req.account, PlayerName = "Player_" + Rng.RandomString(8) };
var user = new User()
{
ID = uid,
Password = req.password,
RegisterTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Username = req.account,
PlayerName = "Player_" + Rng.RandomString(8),
IsAdmin = JsonDb.Instance.Users.Count == 0
};
JsonDb.Instance.Users.Add(user);

View File

@@ -14,9 +14,9 @@ namespace EpinelPS.Controllers
_logger = logger;
}
private bool CheckAuth()
public static bool CheckAuth(HttpContext context)
{
string? token = HttpContext.Request.Cookies["token"];
string? token = context.Request.Cookies["token"];
if (token == null) return false;
@@ -26,45 +26,40 @@ namespace EpinelPS.Controllers
}
return false;
}
[Route("dashboard")]
public IActionResult Dashboard()
{
if (!CheckAuth()) return Redirect("/admin/");
if (!CheckAuth(HttpContext)) return Redirect("/admin/");
return View();
}
[Route("Events")]
public IActionResult Events()
{
if (!CheckAuth()) return Redirect("/admin/");
if (!CheckAuth(HttpContext)) return Redirect("/admin/");
return View();
}
[Route("Configuration")]
public IActionResult Configuration()
{
if (!CheckAuth()) return Redirect("/admin/");
if (!CheckAuth(HttpContext)) return Redirect("/admin/");
return View();
}
[Route("Users")]
public IActionResult Users()
{
if (!CheckAuth()) return Redirect("/admin/");
return View();
}
[Route("Mail")]
public IActionResult Mail()
{
if (!CheckAuth()) return Redirect("/admin/");
if (!CheckAuth(HttpContext)) return Redirect("/admin/");
return View();
}
[Route("Database")]
public IActionResult Database()
{
if (!CheckAuth()) return Redirect("/admin/");
if (!CheckAuth(HttpContext)) return Redirect("/admin/");
return View();
}

View File

@@ -0,0 +1,102 @@
using EpinelPS.Database;
using EpinelPS.Models;
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Text;
namespace EpinelPS.Controllers
{
[Route("admin/Users")]
public class UsersController : Controller
{
private readonly ILogger<AdminController> _logger;
private static MD5 sha = MD5.Create();
public UsersController(ILogger<AdminController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
if (!AdminController.CheckAuth(HttpContext)) return Redirect("/admin/");
return View(JsonDb.Instance.Users);
}
[Route("Modify/{id}")]
public IActionResult Modify(ulong id)
{
if (!AdminController.CheckAuth(HttpContext)) return Redirect("/admin/");
if (id == null)
{
return NotFound();
}
var user = JsonDb.Instance.Users.Where(x => x.ID == id).FirstOrDefault();
if (user == null)
{
return NotFound();
}
return View(user);
}
[Route("SetPassword/{id}")]
public IActionResult SetPassword(ulong id)
{
if (!AdminController.CheckAuth(HttpContext)) return Redirect("/admin/");
if (id == null)
{
return NotFound();
}
var user = JsonDb.Instance.Users.Where(x => x.ID == id).FirstOrDefault();
if (user == null)
{
return NotFound();
}
user.Password = ""; // do not return the password
return View(user);
}
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[Route("SetPassword")]
[HttpPost, ActionName("SetPassword")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> SetPasswordConfirm(ulong? id)
{
if (!AdminController.CheckAuth(HttpContext)) return Redirect("/admin/");
if (id == null)
{
return NotFound();
}
string? newPw = Request.Form["PasswordHash"];
if (string.IsNullOrEmpty(newPw))
{
return BadRequest();
}
// TODO: use bcrypt
var userToUpdate = JsonDb.Instance.Users.Where(s => s.ID == id).FirstOrDefault();
if (userToUpdate == null)
{
return NotFound();
}
userToUpdate.Password = Convert.ToHexString(sha.ComputeHash(Encoding.ASCII.GetBytes(newPw))).ToLower(); ;
return View(userToUpdate);
}
}
}

View File

@@ -0,0 +1,8 @@
@{
ViewData["Title"] = "Configuration";
}
<div class="text-center">
<h1 class="display-4">Configuration</h1>
<p>Coming soon!</p>
</div>

View File

@@ -0,0 +1,8 @@
@{
ViewData["Title"] = "Database configuration";
}
<div class="text-center">
<h1 class="display-4">Database configuration</h1>
<p>Coming soon!</p>
</div>

View File

@@ -0,0 +1,8 @@
@{
ViewData["Title"] = "Event configuration";
}
<div class="text-center">
<h1 class="display-4">Event configuration</h1>
<p>Coming soon!</p>
</div>

View File

@@ -0,0 +1,8 @@
@{
ViewData["Title"] = "Mail";
}
<div class="text-center">
<h1 class="display-4">In-game Mail</h1>
<p>Coming soon!</p>
</div>

View File

@@ -1,8 +0,0 @@
@{
ViewData["Title"] = "Users";
}
<div class="text-center">
<h1 class="display-4">Users</h1>
</div>

View File

@@ -26,7 +26,7 @@
<a class="nav-link text-dark" href="/admin/Events">Events</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" href="/admin/Users">Users</a>
<a class="nav-link text-dark" href="/admin/Users/">Users</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" href="/admin/Mail">Mail</a>

View File

@@ -0,0 +1,57 @@
@model EpinelPS.Database.User
@{
ViewData["Title"] = "Delete user";
}
<h1>Delete</h1>
<p class="text-danger">@ViewData["ErrorMessage"]</p>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>User</h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.ID)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.ID)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Username)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Username)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.IsAdmin)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.IsAdmin)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.PlayerName)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.PlayerName)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Nickname)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Nickname)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.IsBanned)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.IsBanned)
</dd>
</dl>
<form asp-action="Delete">
<input type="hidden" asp-for="ID" />
<input type="submit" value="Delete" class="btn btn-danger" /> |
<a asp-action="Index">Back to List</a>
</form>
</div>

View File

@@ -0,0 +1,46 @@
@model IEnumerable<EpinelPS.Database.User>
@{
ViewData["Title"] = "Users";
}
<div class="text-center">
<h1 class="display-4">Users</h1>
</div>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Username)
</th>
<th>
@Html.DisplayNameFor(model => model.IsAdmin)
</th>
<th>
@Html.DisplayNameFor(model => model.PlayerName)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Username)
</td>
<td>
@Html.DisplayFor(modelItem => item.IsAdmin)
</td>
<td>
@Html.DisplayFor(modelItem => item.PlayerName)
</td>
<td>
<a asp-action="SetPassword" asp-route-id="@item.ID">Change Password</a> |
<a asp-action="Modify" asp-route-id="@item.ID">Modify</a> |
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>

View File

@@ -0,0 +1,45 @@
@model EpinelPS.Database.User
@{
ViewData["Title"] = "Modify user";
}
<h1>Modify</h1>
<h4>User</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Modify">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="ID" />
<div class="form-group">
<label asp-for="Username" class="control-label col-sm-2"></label>
<div class="col-sm-10"><input asp-for="Username" class="form-control" /></div>
<span asp-validation-for="Username" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="IsAdmin" class="control-label"></label>
<input asp-for="IsAdmin" class="form-check-input" />
<span asp-validation-for="IsAdmin" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="IsBanned" class="control-label"></label>
<input asp-for="IsBanned" class="form-check-input" />
<span asp-validation-for="IsBanned" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Nickname" class="control-label col-sm-2"></label>
<div class="col-sm-10"><input asp-for="Nickname" class="form-control" /></div>
<span asp-validation-for="Nickname" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>

View File

@@ -0,0 +1,30 @@
@model EpinelPS.Database.User
@{
ViewData["Title"] = "Change user password";
}
<h1>Change password</h1>
<h4>User</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="SetPassword">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="ID" />
<div class="form-group">
<label asp-for="Password" class="control-label"></label>
<input asp-for="Password" class="form-control" required />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Change password" class="btn btn-danger" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>