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>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||||
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||||
<PreserveCompilationContext>false</PreserveCompilationContext>
|
<PreserveCompilationContext>false</PreserveCompilationContext>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Dapper.Transaction" Version="2.0.35.2" />
|
<PackageReference Include="Dapper.Transaction" Version="2.0.35.2" />
|
||||||
<PackageReference Include="DSharpPlus" Version="4.1.0" />
|
<PackageReference Include="DSharpPlus" Version="4.2.0" />
|
||||||
<PackageReference Include="DSharpPlus.CommandsNext" Version="4.1.0" />
|
<PackageReference Include="DSharpPlus.CommandsNext" Version="4.2.0" />
|
||||||
<PackageReference Include="MySql.Data" Version="8.0.28" />
|
<PackageReference Include="MySql.Data" Version="8.0.28" />
|
||||||
<PackageReference Include="NLog.Web.AspNetCore" Version="5.0.0-rc2" />
|
<PackageReference Include="NLog.Web.AspNetCore" Version="5.0.0-rc2" />
|
||||||
<PackageReference Include="Telegram.Bot.Extensions.Polling" Version="1.0.2" />
|
<PackageReference Include="Telegram.Bot.Extensions.Polling" Version="1.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@ -47,26 +47,39 @@ public class DbContext : IDisposable
|
|||||||
Tran.Dispose();
|
Tran.Dispose();
|
||||||
Conn.Dispose();
|
Conn.Dispose();
|
||||||
}
|
}
|
||||||
public Task<IEnumerable<Topic>> GetTopicsForUser(uint userId)
|
public Task<IEnumerable<Topic>> GetTopicsForUser(uint userId)
|
||||||
=> Tran.QueryAsync<Topic>(
|
=> Tran.QueryAsync<Topic>(
|
||||||
" SELECT * FROM topic WHERE CreatorId = @userId",
|
" SELECT * FROM topic WHERE CreatorId = @userId",
|
||||||
new { 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");
|
=> Tran.QueryAsync<Plan>("SELECT * FROM plan");
|
||||||
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>(@"
|
=> Tran.QueryAsync<UserInvite>(@"
|
||||||
SELECT ui.*, u.Login as RedeemedByLogin
|
SELECT ui.*, u.Login as RedeemedByLogin
|
||||||
FROM userinvite ui
|
FROM userinvite ui
|
||||||
LEFT JOIN user u ON ui.RedeemedBy = u.UserId");
|
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)
|
public Task<IEnumerable<Heart>> GetHeartsForUser(uint userId)
|
||||||
=> Tran.QueryAsync<Heart>(
|
=> Tran.QueryAsync<Heart>(
|
||||||
" SELECT h.* FROM heart h JOIN topic USING (TopicId) WHERE CreatorId = @userId",
|
" SELECT h.* FROM heart h JOIN topic USING (TopicId) WHERE CreatorId = @userId",
|
||||||
new { userId });
|
new { userId });
|
||||||
|
|
||||||
public Task CreateUserInvite(uint planId, uint roleId, string inviteCode)
|
public Task CreateUserInvite(uint planId, uint roleId, string inviteCode)
|
||||||
=> Tran.ExecuteAsync(@"
|
=> Tran.ExecuteAsync(@"
|
||||||
INSERT INTO userinvite
|
INSERT INTO userinvite
|
||||||
( PlanId, RoleId, InviteCode)
|
( PlanId, RoleId, InviteCode)
|
||||||
@ -97,11 +110,11 @@ public class DbContext : IDisposable
|
|||||||
" WHERE ReadToken = @token",
|
" WHERE ReadToken = @token",
|
||||||
new { token, sub });
|
new { token, sub });
|
||||||
|
|
||||||
public Task<IEnumerable<Heart>> GetHeartsForTopic(uint topicId)
|
public Task<IEnumerable<Heart>> GetHeartsForTopic(uint topicId)
|
||||||
=> Tran.QueryAsync<Heart>(
|
=> Tran.QueryAsync<Heart>(
|
||||||
" SELECT * FROM heart WHERE TopicId = @topicId",
|
" SELECT * FROM heart WHERE TopicId = @topicId",
|
||||||
new { topicId });
|
new { topicId });
|
||||||
public Task<User> GetUser(string login)
|
public Task<User> GetUser(string login)
|
||||||
=> Tran.QuerySingleOrDefaultAsync<User>(@"
|
=> Tran.QuerySingleOrDefaultAsync<User>(@"
|
||||||
SELECT u.*, up.*, ur.*
|
SELECT u.*, up.*, ur.*
|
||||||
FROM user u
|
FROM user u
|
||||||
@ -154,30 +167,30 @@ public class DbContext : IDisposable
|
|||||||
( Login, Name, PasswordHash, PasswordSalt, HashType, PlanId, RoleId)
|
( Login, Name, PasswordHash, PasswordSalt, HashType, PlanId, RoleId)
|
||||||
VALUES
|
VALUES
|
||||||
(@Login, @Name, @PasswordHash, @PasswordSalt, @HashType, @PlanId, @RoleId);",
|
(@Login, @Name, @PasswordHash, @PasswordSalt, @HashType, @PlanId, @RoleId);",
|
||||||
param:user);
|
param: user);
|
||||||
return await GetUser(user.Login);
|
return await GetUser(user.Login);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task RedeemInvite(uint inviteId, uint userId)
|
public Task RedeemInvite(uint inviteId, uint userId)
|
||||||
=> Tran.ExecuteAsync(
|
=> Tran.ExecuteAsync(
|
||||||
@"UPDATE userinvite SET RedeemedBy = @userId WHERE UserInviteId = @inviteId",
|
@"UPDATE userinvite SET RedeemedBy = @userId WHERE UserInviteId = @inviteId",
|
||||||
new { inviteId, userId });
|
new { inviteId, userId });
|
||||||
|
|
||||||
public Task<UserInvite> GetInviteByCode(string inviteCode)
|
public Task<UserInvite> GetInviteByCode(string inviteCode)
|
||||||
=> Tran.QuerySingleOrDefaultAsync<UserInvite>(
|
=> Tran.QuerySingleOrDefaultAsync<UserInvite>(
|
||||||
" SELECT * FROM userinvite " +
|
" SELECT * FROM userinvite " +
|
||||||
" WHERE InviteCode = @inviteCode " +
|
" WHERE InviteCode = @inviteCode " +
|
||||||
" AND RedeemedBy IS NULL ",
|
" AND RedeemedBy IS NULL ",
|
||||||
new { inviteCode });
|
new { inviteCode });
|
||||||
|
|
||||||
public Task<IEnumerable<NamespacedId>> GetSubsForTopic(uint topicId)
|
public Task<IEnumerable<NamespacedId>> GetSubsForTopic(uint topicId)
|
||||||
=> Tran.QueryAsync<NamespacedId>(
|
=> Tran.QueryAsync<NamespacedId>(
|
||||||
" SELECT Sub " +
|
" SELECT Sub " +
|
||||||
" FROM topic_sub " +
|
" FROM topic_sub " +
|
||||||
" WHERE TopicId = @topicid",
|
" WHERE TopicId = @topicid",
|
||||||
new { topicId });
|
new { topicId });
|
||||||
|
|
||||||
public Task<IEnumerable<Topic>> GetTopicsForSub(NamespacedId sub)
|
public Task<IEnumerable<Topic>> GetTopicsForSub(NamespacedId sub)
|
||||||
=> Tran.QueryAsync<Topic>(
|
=> Tran.QueryAsync<Topic>(
|
||||||
" SELECT t.*" +
|
" SELECT t.*" +
|
||||||
" FROM topic_sub ts" +
|
" FROM topic_sub ts" +
|
||||||
@ -185,7 +198,7 @@ public class DbContext : IDisposable
|
|||||||
" WHERE ts.Sub = @sub",
|
" WHERE ts.Sub = @sub",
|
||||||
new { sub });
|
new { sub });
|
||||||
|
|
||||||
public Task CreateSubscription(uint topicId, NamespacedId sub)
|
public Task CreateSubscription(uint topicId, NamespacedId sub)
|
||||||
=> Tran.ExecuteAsync(
|
=> Tran.ExecuteAsync(
|
||||||
" INSERT INTO topic_sub" +
|
" INSERT INTO topic_sub" +
|
||||||
" (TopicId, Sub)" +
|
" (TopicId, Sub)" +
|
||||||
@ -193,7 +206,7 @@ public class DbContext : IDisposable
|
|||||||
" (@topicId, @sub)",
|
" (@topicId, @sub)",
|
||||||
new { topicId, sub });
|
new { topicId, sub });
|
||||||
|
|
||||||
public Task<int> RemoveSubscription(string topicName, NamespacedId sub)
|
public Task<int> RemoveSubscription(string topicName, NamespacedId sub)
|
||||||
=> Tran.ExecuteAsync(
|
=> Tran.ExecuteAsync(
|
||||||
" DELETE ts " +
|
" DELETE ts " +
|
||||||
" FROM topic_sub ts" +
|
" FROM topic_sub ts" +
|
||||||
@ -202,7 +215,7 @@ public class DbContext : IDisposable
|
|||||||
new { topicName, sub });
|
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>(
|
=> Tran.QueryFirstAsync<int>(
|
||||||
@"CALL report_heartbeat(@topicId, @heart, @timeoutSeconds);",
|
@"CALL report_heartbeat(@topicId, @heart, @timeoutSeconds);",
|
||||||
new { topicId, heart, timeoutSeconds });
|
new { topicId, heart, timeoutSeconds });
|
||||||
@ -215,14 +228,14 @@ public class DbContext : IDisposable
|
|||||||
|
|
||||||
#region TicketStore
|
#region TicketStore
|
||||||
|
|
||||||
public Task RemoveSession(string sessionId)
|
public Task RemoveSession(string sessionId)
|
||||||
=> Tran.ExecuteAsync("DELETE FROM usersession WHERE SessionId = @sessionId", new { 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>(
|
=> Tran.QuerySingleOrDefaultAsync<UserSession>(
|
||||||
"SELECT * FROM usersession WHERE SessionId = @sessionId",
|
"SELECT * FROM usersession WHERE SessionId = @sessionId",
|
||||||
new { sessionId });
|
new { sessionId });
|
||||||
|
|
||||||
public Task UpdateSession(string sessionId, byte[] data, DateTime expiryTs)
|
public Task UpdateSession(string sessionId, byte[] data, DateTime expiryTs)
|
||||||
=> Tran.ExecuteAsync(@"
|
=> Tran.ExecuteAsync(@"
|
||||||
UPDATE usersession SET
|
UPDATE usersession SET
|
||||||
SessionData = @data,
|
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 {
|
a.show-button {
|
||||||
display: inline;
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
color: gray;
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user