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 RoleId { get; set; }
public uint RedeemedBy { get; set; }
public string? RedeemedByLogin { get; set; }
}
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 JetHerald.Contracts;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using JetHerald.Authorization;
using JetHerald.Options;
using JetHerald.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using JetHerald.Contracts;
namespace JetHerald.Controllers.Ui;
[Permission("admintools")]
public class AdminToolsController : Controller
[Permission("admin.invites")]
[Route("ui/admin/invites")]
public class AdminInvitesController : Controller
{
Db Db { get; }
ILogger Log { get; }
AuthConfig AuthCfg { get; }
public AdminToolsController(
ILogger<AdminToolsController> log,
public AdminInvitesController(
Db db,
IOptionsSnapshot<AuthConfig> authCfg
)
{
Db = db;
Log = log;
AuthCfg = authCfg.Value;
}
[HttpGet, Route("ui/admintools/")]
public IActionResult Index() => View();
[HttpGet, Route("ui/admintools/invites")]
public async Task<IActionResult> ViewInvites()
[HttpGet]
public async Task<IActionResult> Index()
{
using var ctx = await Db.GetContext();
var invites = await ctx.GetInvites();
var plans = await ctx.GetPlans();
var roles = await ctx.GetRoles();
return View(new ViewInvitesModel
return View(new AdminInvitesModel
{
Invites = invites.ToArray(),
Plans = plans.ToDictionary(p => p.PlanId),
@ -50,17 +44,35 @@ public class AdminToolsController : Controller
[BindProperty(Name = "roleId"), BindRequired]
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)
{
using var ctx = await Db.GetContext();
await ctx.CreateUserInvite(req.PlanId, req.RoleId, TokenHelper.GetToken(AuthCfg.InviteCodeLength));
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 Dictionary<uint, Plan> Plans { get; set; }

View File

@ -56,7 +56,10 @@ public class DbContext : IDisposable
public Task<IEnumerable<Role>> GetRoles()
=> Tran.QueryAsync<Role>("SELECT * FROM role");
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)
=> Tran.QueryAsync<Heart>(
@ -71,6 +74,11 @@ public class DbContext : IDisposable
(@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)
=> Tran.QuerySingleOrDefaultAsync<Topic>(
"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>
<select name="roleId" required id="roleselector">
@foreach (var role in Model.Roles.Values)
@ -25,11 +25,23 @@
@foreach (var invite in Model.Invites)
{
<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">
<input type="submit" value="❌" style="display:inline; color:red;" class="buttonlink">
</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>
}
</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>
}
@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())
{