users touchups, example admin panel for invites

This commit is contained in:
Jetsparrow 2022-05-16 17:54:21 +03:00
parent 31c6ced153
commit 290b98c798
8 changed files with 80 additions and 34 deletions

View File

@ -61,6 +61,7 @@ public class UserInvite
public uint PlanId { get; set; } public uint PlanId { get; set; }
public uint RoleId { get; set; } public uint RoleId { get; set; }
public uint RedeemedBy { get; set; } public uint RedeemedBy { get; set; }
public string? RedeemedByLogin { get; set; }
} }
public class UserSession public class UserSession

View File

@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Mvc;
using JetHerald.Authorization;
namespace JetHerald.Controllers.Ui;
[Permission("admin")]
[Route("ui/admin")]
public class AdminController : Controller
{
public AdminController() { }
[HttpGet]
public IActionResult Index() => View();
}

View File

@ -1,41 +1,35 @@
using JetHerald.Authorization; using Microsoft.AspNetCore.Mvc;
using JetHerald.Contracts; using Microsoft.AspNetCore.Mvc.ModelBinding;
using JetHerald.Authorization;
using JetHerald.Options; using JetHerald.Options;
using JetHerald.Services; using JetHerald.Services;
using JetHerald.Contracts;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace JetHerald.Controllers.Ui; namespace JetHerald.Controllers.Ui;
[Permission("admintools")]
public class AdminToolsController : Controller [Permission("admin.invites")]
[Route("ui/admin/invites")]
public class AdminInvitesController : Controller
{ {
Db Db { get; } Db Db { get; }
ILogger Log { get; }
AuthConfig AuthCfg { get; } AuthConfig AuthCfg { get; }
public AdminToolsController( public AdminInvitesController(
ILogger<AdminToolsController> log,
Db db, Db db,
IOptionsSnapshot<AuthConfig> authCfg IOptionsSnapshot<AuthConfig> authCfg
) )
{ {
Db = db; Db = db;
Log = log;
AuthCfg = authCfg.Value; AuthCfg = authCfg.Value;
} }
[HttpGet, Route("ui/admintools/")] [HttpGet]
public IActionResult Index() => View(); public async Task<IActionResult> Index()
[HttpGet, Route("ui/admintools/invites")]
public async Task<IActionResult> ViewInvites()
{ {
using var ctx = await Db.GetContext(); using var ctx = await Db.GetContext();
var invites = await ctx.GetInvites(); var invites = await ctx.GetInvites();
var plans = await ctx.GetPlans(); var plans = await ctx.GetPlans();
var roles = await ctx.GetRoles(); var roles = await ctx.GetRoles();
return View(new ViewInvitesModel return View(new AdminInvitesModel
{ {
Invites = invites.ToArray(), Invites = invites.ToArray(),
Plans = plans.ToDictionary(p => p.PlanId), Plans = plans.ToDictionary(p => p.PlanId),
@ -50,17 +44,35 @@ public class AdminToolsController : Controller
[BindProperty(Name = "roleId"), BindRequired] [BindProperty(Name = "roleId"), BindRequired]
public uint RoleId { get; set; } public uint RoleId { get; set; }
} }
[HttpPost, Route("ui/admintools/invites/create")]
[Permission("admin.invites.create")]
[HttpPost, Route("create")]
public async Task<IActionResult> CreateInvite(CreateInviteRequest req) public async Task<IActionResult> CreateInvite(CreateInviteRequest req)
{ {
using var ctx = await Db.GetContext(); using var ctx = await Db.GetContext();
await ctx.CreateUserInvite(req.PlanId, req.RoleId, TokenHelper.GetToken(AuthCfg.InviteCodeLength)); await ctx.CreateUserInvite(req.PlanId, req.RoleId, TokenHelper.GetToken(AuthCfg.InviteCodeLength));
ctx.Commit(); ctx.Commit();
return RedirectToAction(nameof(ViewInvites)); return RedirectToAction(nameof(Index));
}
public class DeleteInviteRequest
{
[BindProperty(Name = "inviteId"), BindRequired]
public uint UserInviteId { get; set; }
}
[Permission("admin.invites.delete")]
[HttpPost, Route("delete")]
public async Task<IActionResult> DeleteInvite(DeleteInviteRequest req)
{
using var ctx = await Db.GetContext();
await ctx.DeleteUserInvite(req.UserInviteId);
ctx.Commit();
return RedirectToAction(nameof(Index));
} }
} }
public class ViewInvitesModel public class AdminInvitesModel
{ {
public UserInvite[] Invites { get; set; } public UserInvite[] Invites { get; set; }
public Dictionary<uint, Plan> Plans { get; set; } public Dictionary<uint, Plan> Plans { get; set; }

View File

@ -56,7 +56,10 @@ public class DbContext : IDisposable
public Task<IEnumerable<Role>> GetRoles() public Task<IEnumerable<Role>> GetRoles()
=> Tran.QueryAsync<Role>("SELECT * FROM role"); => Tran.QueryAsync<Role>("SELECT * FROM role");
public Task<IEnumerable<UserInvite>> GetInvites() public Task<IEnumerable<UserInvite>> GetInvites()
=> Tran.QueryAsync<UserInvite>("SELECT * FROM userinvite"); => Tran.QueryAsync<UserInvite>(@"
SELECT ui.*, u.Login as RedeemedByLogin
FROM userinvite ui
LEFT JOIN user u ON ui.RedeemedBy = u.UserId");
public Task<IEnumerable<Heart>> GetHeartsForUser(uint userId) public Task<IEnumerable<Heart>> GetHeartsForUser(uint userId)
=> Tran.QueryAsync<Heart>( => Tran.QueryAsync<Heart>(
@ -71,6 +74,11 @@ public class DbContext : IDisposable
(@planId, @roleId, @inviteCode)", (@planId, @roleId, @inviteCode)",
new { planId, roleId, inviteCode }); new { planId, roleId, inviteCode });
public Task DeleteUserInvite(uint inviteId)
=> Tran.ExecuteAsync(@" DELETE FROM userinvite WHERE UserInviteId = @intiteId",
new { inviteId });
public Task<Topic> GetTopic(string name) public Task<Topic> GetTopic(string name)
=> Tran.QuerySingleOrDefaultAsync<Topic>( => Tran.QuerySingleOrDefaultAsync<Topic>(
"SELECT * FROM topic WHERE Name = @name", "SELECT * FROM topic WHERE Name = @name",

View File

@ -0,0 +1,6 @@
<ul class="issues-list">
<li><a asp-controller="AdminInvites">Invites</a></li>
<li><a asp-controller="AdminUsers">Users</a></li>
<li><a asp-controller="AdminRoles">Roles</a></li>
<li><a asp-controller="AdminPlans">Plans</a></li>
</ul>

View File

@ -1,6 +1,6 @@
@model ViewInvitesModel @model AdminInvitesModel
<form asp-controller="AdminTools" asp-action="CreateInvite" method="POST" enctype="application/x-www-form-urlencoded"> <form asp-controller="AdminInvites" asp-action="CreateInvite" method="POST" enctype="application/x-www-form-urlencoded">
<label for="roleselector">Role:</label> <label for="roleselector">Role:</label>
<select name="roleId" required id="roleselector"> <select name="roleId" required id="roleselector">
@foreach (var role in Model.Roles.Values) @foreach (var role in Model.Roles.Values)
@ -25,11 +25,23 @@
@foreach (var invite in Model.Invites) @foreach (var invite in Model.Invites)
{ {
<li> <li>
<span style="font-family:monospace">@invite.InviteCode.Substring(0, 8)... r:(@Model.Roles[invite.RoleId].Name) p:(@Model.Plans[invite.PlanId].Name)</span> <span style="font-family:monospace">@invite.InviteCode.Substring(0, 12)... r:(@Model.Roles[invite.RoleId].Name) p:(@Model.Plans[invite.PlanId].Name)</span>
<form asp-controller="Admin" asp-action="DeleteInvite" asp-route-inviteId="@invite.UserInviteId" method="POST" style="display:inline"> <form asp-controller="Admin" asp-action="DeleteInvite" asp-route-inviteId="@invite.UserInviteId" method="POST" style="display:inline">
<input type="submit" value="❌" style="display:inline; color:red;" class="buttonlink"> <input type="submit" value="❌" style="display:inline; color:red;" class="buttonlink">
</form> </form>
<a asp-controller="Registration" asp-action="Register" asp-route-invite="@invite.InviteCode" class="copier" style="display:inline; color:blue">📤</a> @if (invite.RedeemedBy == default)
{
<a class="copier" style="display:inline; color:blue"
asp-controller="Registration" asp-action="Register" asp-route-invite="@invite.InviteCode">
📤
</a>
}
else
{
<span>
@invite.RedeemedBy:@(invite.RedeemedByLogin ?? "deleted user")
</span>
}
</li> </li>
} }
</ul> </ul>

View File

@ -1,6 +0,0 @@
<ul class="issues-list">
<li><a asp-action="ViewUsers">View all registered users</a></li>
<!-- <li><a asp-action="ViewInvites">View unredeemed invites</a></li>
<li><a asp-action="ViewRoles">View all roles</a></li>
-->
</ul>

View File

@ -21,9 +21,9 @@
{ {
<a asp-action="Index" asp-controller="Dashboard">Dashboard</a> <a asp-action="Index" asp-controller="Dashboard">Dashboard</a>
} }
@if (Context.UserCan("admintools")) @if (Context.UserCan("admin"))
{ {
<a asp-action="Index" asp-controller="AdminTools">Admin tools</a> <a asp-action="Index" asp-controller="Admin">Admin tools</a>
} }
@if (User.IsAnonymous()) @if (User.IsAnonymous())
{ {