mirror of
https://github.com/Jetsparrow/jetherald.git
synced 2026-01-20 23:56:08 +03:00
add user list page
This commit is contained in:
parent
6b6883bb20
commit
c5d4db1c4c
61
JetHerald/Controllers/Ui/AdminUsersController.cs
Normal file
61
JetHerald/Controllers/Ui/AdminUsersController.cs
Normal file
@ -0,0 +1,61 @@
|
||||
using JetHerald.Authorization;
|
||||
using JetHerald.Contracts;
|
||||
using JetHerald.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
namespace JetHerald.Controllers.Ui;
|
||||
|
||||
[Permission("admin.users")]
|
||||
[Route("ui/admin/users")]
|
||||
public class AdminUsersController : Controller
|
||||
{
|
||||
Db Db { get; }
|
||||
public AdminUsersController(Db db)
|
||||
{
|
||||
Db = db;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Index()
|
||||
{
|
||||
using var ctx = await Db.GetContext();
|
||||
|
||||
var users = await ctx.GetUsers();
|
||||
var plans = await ctx.GetPlans();
|
||||
var roles = await ctx.GetRoles();
|
||||
|
||||
return View(new AdminUsersModel
|
||||
{
|
||||
Users = users.ToArray(),
|
||||
Plans = plans.ToDictionary(p => p.PlanId),
|
||||
Roles = roles.ToDictionary(r => r.RoleId)
|
||||
});
|
||||
}
|
||||
|
||||
public class SetPermsRequest
|
||||
{
|
||||
[BindProperty(Name = "planId"), BindRequired]
|
||||
public uint PlanId { get; set; }
|
||||
[BindProperty(Name = "roleId"), BindRequired]
|
||||
public uint RoleId { get; set; }
|
||||
}
|
||||
|
||||
[Permission("admin.users.setperms")]
|
||||
[HttpPost, Route("setperms/{userId?}")]
|
||||
public async Task<IActionResult> SetPerms([FromRoute] uint userId, SetPermsRequest req)
|
||||
{
|
||||
using var ctx = await Db.GetContext();
|
||||
await ctx.UpdatePerms(userId, req.PlanId, req.RoleId);
|
||||
ctx.Commit();
|
||||
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
}
|
||||
|
||||
public class AdminUsersModel
|
||||
{
|
||||
public User[] Users { get; set; }
|
||||
public Dictionary<uint, Plan> Plans { get; set; }
|
||||
public Dictionary<uint, Role> Roles { get; set; }
|
||||
}
|
||||
@ -2,18 +2,18 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||
<PreserveCompilationContext>false</PreserveCompilationContext>
|
||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||
<PreserveCompilationContext>false</PreserveCompilationContext>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapper.Transaction" Version="2.0.35.2" />
|
||||
<PackageReference Include="DSharpPlus" Version="4.1.0" />
|
||||
<PackageReference Include="DSharpPlus.CommandsNext" Version="4.1.0" />
|
||||
<PackageReference Include="DSharpPlus" Version="4.2.0" />
|
||||
<PackageReference Include="DSharpPlus.CommandsNext" Version="4.2.0" />
|
||||
<PackageReference Include="MySql.Data" Version="8.0.28" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="5.0.0-rc2" />
|
||||
<PackageReference Include="Telegram.Bot.Extensions.Polling" Version="1.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
</Project>
|
||||
@ -47,26 +47,39 @@ public class DbContext : IDisposable
|
||||
Tran.Dispose();
|
||||
Conn.Dispose();
|
||||
}
|
||||
public Task<IEnumerable<Topic>> GetTopicsForUser(uint userId)
|
||||
public Task<IEnumerable<Topic>> GetTopicsForUser(uint userId)
|
||||
=> Tran.QueryAsync<Topic>(
|
||||
" SELECT * FROM topic WHERE CreatorId = @userId",
|
||||
new { userId });
|
||||
public Task<IEnumerable<Plan>> GetPlans()
|
||||
|
||||
public Task UpdatePerms(uint userId, uint planId, uint roleId)
|
||||
=> Tran.ExecuteAsync(@"
|
||||
UPDATE user
|
||||
SET PlanId = @planId,
|
||||
RoleId = @roleId
|
||||
WHERE UserId = @userId",
|
||||
new { userId, planId, roleId });
|
||||
|
||||
public Task<IEnumerable<Plan>> GetPlans()
|
||||
=> Tran.QueryAsync<Plan>("SELECT * FROM plan");
|
||||
public Task<IEnumerable<Role>> GetRoles()
|
||||
public Task<IEnumerable<Role>> GetRoles()
|
||||
=> Tran.QueryAsync<Role>("SELECT * FROM role");
|
||||
public Task<IEnumerable<UserInvite>> GetInvites()
|
||||
public Task<IEnumerable<UserInvite>> GetInvites()
|
||||
=> Tran.QueryAsync<UserInvite>(@"
|
||||
SELECT ui.*, u.Login as RedeemedByLogin
|
||||
FROM userinvite ui
|
||||
LEFT JOIN user u ON ui.RedeemedBy = u.UserId");
|
||||
public Task<IEnumerable<User>> GetUsers()
|
||||
=> Tran.QueryAsync<User>(@"
|
||||
SELECT u.*
|
||||
FROM user u;");
|
||||
|
||||
public Task<IEnumerable<Heart>> GetHeartsForUser(uint userId)
|
||||
=> Tran.QueryAsync<Heart>(
|
||||
" SELECT h.* FROM heart h JOIN topic USING (TopicId) WHERE CreatorId = @userId",
|
||||
new { userId });
|
||||
|
||||
public Task CreateUserInvite(uint planId, uint roleId, string inviteCode)
|
||||
public Task CreateUserInvite(uint planId, uint roleId, string inviteCode)
|
||||
=> Tran.ExecuteAsync(@"
|
||||
INSERT INTO userinvite
|
||||
( PlanId, RoleId, InviteCode)
|
||||
@ -97,11 +110,11 @@ public class DbContext : IDisposable
|
||||
" WHERE ReadToken = @token",
|
||||
new { token, sub });
|
||||
|
||||
public Task<IEnumerable<Heart>> GetHeartsForTopic(uint topicId)
|
||||
public Task<IEnumerable<Heart>> GetHeartsForTopic(uint topicId)
|
||||
=> Tran.QueryAsync<Heart>(
|
||||
" SELECT * FROM heart WHERE TopicId = @topicId",
|
||||
new { topicId });
|
||||
public Task<User> GetUser(string login)
|
||||
public Task<User> GetUser(string login)
|
||||
=> Tran.QuerySingleOrDefaultAsync<User>(@"
|
||||
SELECT u.*, up.*, ur.*
|
||||
FROM user u
|
||||
@ -154,30 +167,30 @@ public class DbContext : IDisposable
|
||||
( Login, Name, PasswordHash, PasswordSalt, HashType, PlanId, RoleId)
|
||||
VALUES
|
||||
(@Login, @Name, @PasswordHash, @PasswordSalt, @HashType, @PlanId, @RoleId);",
|
||||
param:user);
|
||||
param: user);
|
||||
return await GetUser(user.Login);
|
||||
}
|
||||
|
||||
public Task RedeemInvite(uint inviteId, uint userId)
|
||||
public Task RedeemInvite(uint inviteId, uint userId)
|
||||
=> Tran.ExecuteAsync(
|
||||
@"UPDATE userinvite SET RedeemedBy = @userId WHERE UserInviteId = @inviteId",
|
||||
new { inviteId, userId });
|
||||
|
||||
public Task<UserInvite> GetInviteByCode(string inviteCode)
|
||||
public Task<UserInvite> GetInviteByCode(string inviteCode)
|
||||
=> Tran.QuerySingleOrDefaultAsync<UserInvite>(
|
||||
" SELECT * FROM userinvite " +
|
||||
" WHERE InviteCode = @inviteCode " +
|
||||
" AND RedeemedBy IS NULL ",
|
||||
new { inviteCode });
|
||||
|
||||
public Task<IEnumerable<NamespacedId>> GetSubsForTopic(uint topicId)
|
||||
public Task<IEnumerable<NamespacedId>> GetSubsForTopic(uint topicId)
|
||||
=> Tran.QueryAsync<NamespacedId>(
|
||||
" SELECT Sub " +
|
||||
" FROM topic_sub " +
|
||||
" WHERE TopicId = @topicid",
|
||||
new { topicId });
|
||||
|
||||
public Task<IEnumerable<Topic>> GetTopicsForSub(NamespacedId sub)
|
||||
public Task<IEnumerable<Topic>> GetTopicsForSub(NamespacedId sub)
|
||||
=> Tran.QueryAsync<Topic>(
|
||||
" SELECT t.*" +
|
||||
" FROM topic_sub ts" +
|
||||
@ -185,7 +198,7 @@ public class DbContext : IDisposable
|
||||
" WHERE ts.Sub = @sub",
|
||||
new { sub });
|
||||
|
||||
public Task CreateSubscription(uint topicId, NamespacedId sub)
|
||||
public Task CreateSubscription(uint topicId, NamespacedId sub)
|
||||
=> Tran.ExecuteAsync(
|
||||
" INSERT INTO topic_sub" +
|
||||
" (TopicId, Sub)" +
|
||||
@ -193,7 +206,7 @@ public class DbContext : IDisposable
|
||||
" (@topicId, @sub)",
|
||||
new { topicId, sub });
|
||||
|
||||
public Task<int> RemoveSubscription(string topicName, NamespacedId sub)
|
||||
public Task<int> RemoveSubscription(string topicName, NamespacedId sub)
|
||||
=> Tran.ExecuteAsync(
|
||||
" DELETE ts " +
|
||||
" FROM topic_sub ts" +
|
||||
@ -202,7 +215,7 @@ public class DbContext : IDisposable
|
||||
new { topicName, sub });
|
||||
|
||||
|
||||
public Task<int> ReportHeartbeat(uint topicId, string heart, int timeoutSeconds)
|
||||
public Task<int> ReportHeartbeat(uint topicId, string heart, int timeoutSeconds)
|
||||
=> Tran.QueryFirstAsync<int>(
|
||||
@"CALL report_heartbeat(@topicId, @heart, @timeoutSeconds);",
|
||||
new { topicId, heart, timeoutSeconds });
|
||||
@ -215,14 +228,14 @@ public class DbContext : IDisposable
|
||||
|
||||
#region TicketStore
|
||||
|
||||
public Task RemoveSession(string sessionId)
|
||||
public Task RemoveSession(string sessionId)
|
||||
=> Tran.ExecuteAsync("DELETE FROM usersession WHERE SessionId = @sessionId", new { sessionId });
|
||||
public Task<UserSession> GetSession(string sessionId)
|
||||
public Task<UserSession> GetSession(string sessionId)
|
||||
=> Tran.QuerySingleOrDefaultAsync<UserSession>(
|
||||
"SELECT * FROM usersession WHERE SessionId = @sessionId",
|
||||
new { sessionId });
|
||||
|
||||
public Task UpdateSession(string sessionId, byte[] data, DateTime expiryTs)
|
||||
public Task UpdateSession(string sessionId, byte[] data, DateTime expiryTs)
|
||||
=> Tran.ExecuteAsync(@"
|
||||
UPDATE usersession SET
|
||||
SessionData = @data,
|
||||
|
||||
50
JetHerald/Views/AdminUsers/Index.cshtml
Normal file
50
JetHerald/Views/AdminUsers/Index.cshtml
Normal file
@ -0,0 +1,50 @@
|
||||
@model AdminUsersModel
|
||||
|
||||
<h3>Invites</h3>
|
||||
<ul class="issues-list">
|
||||
@foreach (var user in Model.Users)
|
||||
{
|
||||
<li>
|
||||
@user.Name <span class="username">@@@user.Login</span> (
|
||||
@if (Context.UserCan("admin.users.setperms"))
|
||||
{
|
||||
<form asp-controller="AdminUsers" asp-action="SetPerms" asp-route-userid="@user.UserId" method="POST"
|
||||
enctype="application/x-www-form-urlencoded" style="display:inline">
|
||||
r:<select name="roleId" required class="blueunderline">
|
||||
@foreach (var role in Model.Roles.Values)
|
||||
{
|
||||
if (role.RoleId == user.RoleId)
|
||||
{
|
||||
<option value="@role.RoleId" selected>@role.Name</option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="@role.RoleId">@role.Name</option>
|
||||
}
|
||||
}
|
||||
</select>,
|
||||
p:<select name="planId" required class="blueunderline">
|
||||
@foreach (var plan in Model.Plans.Values)
|
||||
{
|
||||
if (plan.PlanId == user.PlanId)
|
||||
{
|
||||
<option value="@plan.PlanId" selected>@plan.Name</option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="@plan.PlanId">@plan.Name</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
<input type="submit" value="Set permissions">
|
||||
</form>
|
||||
}
|
||||
else
|
||||
{
|
||||
@: r:@Model.Roles[user.RoleId].Name,
|
||||
@: p:@Model.Plans[user.PlanId].Name
|
||||
}
|
||||
)
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
@ -395,4 +395,8 @@ td.numeric {
|
||||
|
||||
a.show-button {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.username {
|
||||
color: gray;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user