mirror of
https://github.com/Jetsparrow/jetherald.git
synced 2026-01-20 23:56:08 +03:00
users touchups, example admin panel for invites
This commit is contained in:
parent
31c6ced153
commit
290b98c798
@ -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
|
||||
|
||||
13
JetHerald/Controllers/Ui/AdminController.cs
Normal file
13
JetHerald/Controllers/Ui/AdminController.cs
Normal 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();
|
||||
}
|
||||
@ -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; }
|
||||
@ -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",
|
||||
|
||||
6
JetHerald/Views/Admin/Index.cshtml
Normal file
6
JetHerald/Views/Admin/Index.cshtml
Normal 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>
|
||||
@ -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>
|
||||
@ -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>
|
||||
@ -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())
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user