mirror of
https://github.com/Jetsparrow/jetherald.git
synced 2026-01-21 07:56:09 +03:00
split plan and role, fix lots of small issues, move registration logic to code
This commit is contained in:
parent
95e8d12751
commit
4cdeb8a7c7
12
JetHerald/.config/dotnet-tools.json
Normal file
12
JetHerald/.config/dotnet-tools.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"isRoot": true,
|
||||||
|
"tools": {
|
||||||
|
"dotnet-ef": {
|
||||||
|
"version": "6.0.5",
|
||||||
|
"commands": [
|
||||||
|
"dotnet-ef"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -45,6 +45,7 @@ public class User
|
|||||||
public byte[] PasswordSalt { get; set; }
|
public byte[] PasswordSalt { get; set; }
|
||||||
public int HashType { get; set; }
|
public int HashType { get; set; }
|
||||||
public uint PlanId { get; set; }
|
public uint PlanId { get; set; }
|
||||||
|
public uint RoleId { get; set; }
|
||||||
|
|
||||||
public string Allow { get; set; }
|
public string Allow { get; set; }
|
||||||
|
|
||||||
@ -58,6 +59,7 @@ public class UserInvite
|
|||||||
public uint UserInviteId { get; set; }
|
public uint UserInviteId { get; set; }
|
||||||
public string InviteCode { get; set; }
|
public string InviteCode { get; set; }
|
||||||
public uint PlanId { get; set; }
|
public uint PlanId { get; set; }
|
||||||
|
public uint RoleId { get; set; }
|
||||||
public uint RedeemedBy { get; set; }
|
public uint RedeemedBy { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,5 +76,11 @@ public class Plan
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public int MaxTopics { get; set; }
|
public int MaxTopics { get; set; }
|
||||||
public double TimeoutMultiplier { get; set; }
|
public double TimeoutMultiplier { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Role
|
||||||
|
{
|
||||||
|
public uint RoleId { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
public string Allow { get; set; }
|
public string Allow { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -76,9 +76,9 @@ public class HeartbeatController : ControllerBase
|
|||||||
if (Timeouts.IsTimedOut(t.TopicId))
|
if (Timeouts.IsTimedOut(t.TopicId))
|
||||||
return StatusCode(StatusCodes.Status429TooManyRequests);
|
return StatusCode(StatusCodes.Status429TooManyRequests);
|
||||||
|
|
||||||
var affected = await Db.ReportHeartbeat(t.TopicId, heart, args.ExpiryTimeout);
|
var wasBeating = await Db.ReportHeartbeat(t.TopicId, heart, args.ExpiryTimeout);
|
||||||
|
|
||||||
if (affected == 0)
|
if (wasBeating == 0)
|
||||||
await Herald.BroadcastMessageRaw(t.TopicId, $"!{t.Description}!:\nHeart \"{heart}\" has started beating at {DateTime.UtcNow:O}");
|
await Herald.BroadcastMessageRaw(t.TopicId, $"!{t.Description}!:\nHeart \"{heart}\" has started beating at {DateTime.UtcNow:O}");
|
||||||
|
|
||||||
Timeouts.ApplyCost(t.TopicId, Config.HeartbeatCost);
|
Timeouts.ApplyCost(t.TopicId, Config.HeartbeatCost);
|
||||||
|
|||||||
@ -33,10 +33,12 @@ public class AdminToolsController : Controller
|
|||||||
{
|
{
|
||||||
var invites = await Db.GetInvites();
|
var invites = await Db.GetInvites();
|
||||||
var plans = await Db.GetPlans();
|
var plans = await Db.GetPlans();
|
||||||
|
var roles = await Db.GetRoles();
|
||||||
return View(new ViewInvitesModel
|
return View(new ViewInvitesModel
|
||||||
{
|
{
|
||||||
Invites = invites.ToArray(),
|
Invites = invites.ToArray(),
|
||||||
Plans = plans.ToDictionary(p => p.PlanId)
|
Plans = plans.ToDictionary(p => p.PlanId),
|
||||||
|
Roles = roles.ToDictionary(r => r.RoleId)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,16 +46,20 @@ public class AdminToolsController : Controller
|
|||||||
{
|
{
|
||||||
[BindProperty(Name = "planId"), BindRequired]
|
[BindProperty(Name = "planId"), BindRequired]
|
||||||
public uint PlanId { get; set; }
|
public uint PlanId { get; set; }
|
||||||
|
[BindProperty(Name = "roleId"), BindRequired]
|
||||||
|
public uint RoleId { get; set; }
|
||||||
}
|
}
|
||||||
[HttpPost, Route("ui/admintools/invites/create")]
|
[HttpPost, Route("ui/admintools/invites/create")]
|
||||||
public async Task<IActionResult> CreateInvite(CreateInviteRequest req)
|
public async Task<IActionResult> CreateInvite(CreateInviteRequest req)
|
||||||
{
|
{
|
||||||
await Db.CreateUserInvite(req.PlanId, TokenHelper.GetToken(AuthCfg.InviteCodeLength));
|
await Db.CreateUserInvite(req.PlanId, req.RoleId, TokenHelper.GetToken(AuthCfg.InviteCodeLength));
|
||||||
return RedirectToAction(nameof(ViewInvites));
|
return RedirectToAction(nameof(ViewInvites));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ViewInvitesModel
|
public class ViewInvitesModel
|
||||||
{
|
{
|
||||||
public UserInvite[] Invites { get; set; }
|
public UserInvite[] Invites { get; set; }
|
||||||
public Dictionary<uint, Plan> Plans { get; set; }
|
public Dictionary<uint, Plan> Plans { get; set; }
|
||||||
|
public Dictionary<uint, Role> Roles { get; set; }
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ public class LoginController : Controller
|
|||||||
}
|
}
|
||||||
catch (ArgumentException)
|
catch (ArgumentException)
|
||||||
{
|
{
|
||||||
return RedirectToAction("Dashboard", "Dashboard");
|
return RedirectToAction("Index", "Dashboard");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,25 +1,26 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
namespace JetHerald.Controllers.Ui;
|
namespace JetHerald.Controllers.Ui;
|
||||||
|
[Route("ui")]
|
||||||
public class MainController : Controller
|
public class MainController : Controller
|
||||||
{
|
{
|
||||||
[Route("/error/")]
|
[Route("error")]
|
||||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||||
public IActionResult Error()
|
public IActionResult Error()
|
||||||
{
|
{
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
[Route("/403")]
|
[Route("403")]
|
||||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||||
public IActionResult Error403()
|
public IActionResult Error403()
|
||||||
{
|
{
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
[Route("/404")]
|
[Route("404")]
|
||||||
public IActionResult Error404()
|
public IActionResult Error404()
|
||||||
{
|
{
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
[Route("/400")]
|
[Route("400")]
|
||||||
public IActionResult Error400()
|
public IActionResult Error400()
|
||||||
{
|
{
|
||||||
return View();
|
return View();
|
||||||
|
|||||||
@ -27,7 +27,7 @@ public class RegistrationController : Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
public RegistrationController(
|
public RegistrationController(
|
||||||
ILogger<LoginController> log,
|
ILogger<RegistrationController> log,
|
||||||
Db db,
|
Db db,
|
||||||
IOptionsSnapshot<AuthConfig> authConfig)
|
IOptionsSnapshot<AuthConfig> authConfig)
|
||||||
{
|
{
|
||||||
@ -83,14 +83,17 @@ public class RegistrationController : Controller
|
|||||||
}
|
}
|
||||||
var user = new User()
|
var user = new User()
|
||||||
{
|
{
|
||||||
|
RoleId = invite.RoleId,
|
||||||
PlanId = invite.PlanId,
|
PlanId = invite.PlanId,
|
||||||
Login = req.Login,
|
Login = req.Login,
|
||||||
Name = req.Name,
|
Name = req.Name,
|
||||||
|
HashType = Cfg.HashType,
|
||||||
PasswordSalt = RandomNumberGenerator.GetBytes(64)
|
PasswordSalt = RandomNumberGenerator.GetBytes(64)
|
||||||
};
|
};
|
||||||
user.PasswordHash = AuthUtils.GetHashFor(req.Password, user.PasswordSalt, Cfg.HashType);
|
user.PasswordHash = AuthUtils.GetHashFor(req.Password, user.PasswordSalt, user.HashType);
|
||||||
var newUser = await Db.RegisterUserFromInvite(user, invite.UserInviteId);
|
user = await Db.RegisterUser(user);
|
||||||
var userIdentity = AuthUtils.CreateIdentity(newUser.UserId, newUser.Login, newUser.Name, newUser.Allow);
|
await Db.RedeemInvite(invite.UserInviteId, user.UserId);
|
||||||
|
var userIdentity = AuthUtils.CreateIdentity(user.UserId, user.Login, user.Name, user.Allow);
|
||||||
var principal = new ClaimsPrincipal(userIdentity);
|
var principal = new ClaimsPrincipal(userIdentity);
|
||||||
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
|
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
|
||||||
|
|
||||||
@ -100,7 +103,7 @@ public class RegistrationController : Controller
|
|||||||
}
|
}
|
||||||
catch (ArgumentException)
|
catch (ArgumentException)
|
||||||
{
|
{
|
||||||
return RedirectToAction("News", "Issue");
|
return RedirectToAction("Index", "Dashboard");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Dapper" Version="2.0.123" />
|
<PackageReference Include="Dapper.Transaction" Version="2.0.35.2" />
|
||||||
<PackageReference Include="DSharpPlus" Version="4.1.0" />
|
<PackageReference Include="DSharpPlus" Version="4.1.0" />
|
||||||
<PackageReference Include="DSharpPlus.CommandsNext" Version="4.1.0" />
|
<PackageReference Include="DSharpPlus.CommandsNext" Version="4.1.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.1" />
|
||||||
@ -15,10 +15,4 @@
|
|||||||
<PackageReference Include="Telegram.Bot.Extensions.Polling" Version="1.0.2" />
|
<PackageReference Include="Telegram.Bot.Extensions.Polling" Version="1.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Update="appsettings.json">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -1,28 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
autoReload="true">
|
|
||||||
|
|
||||||
<!-- enable asp.net core layout renderers -->
|
|
||||||
<extensions>
|
|
||||||
<add assembly="NLog.Web.AspNetCore"/>
|
|
||||||
</extensions>
|
|
||||||
|
|
||||||
<targets>
|
|
||||||
<target xsi:type="File" name="allfile" fileName="herald.log"
|
|
||||||
layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" />
|
|
||||||
|
|
||||||
<target name="logconsole" xsi:type="Console"
|
|
||||||
layout="${longdate}|${level:uppercase=true}|${logger}|${message} ${exception:format=Message,StackTrace,Data:maxInnerExceptionLevel=10}"/>
|
|
||||||
</targets>
|
|
||||||
|
|
||||||
<!-- rules to map from logger name to target -->
|
|
||||||
<rules>
|
|
||||||
<!--All logs, including from Microsoft-->
|
|
||||||
<logger name="*" minlevel="Trace" writeTo="allfile" />
|
|
||||||
<logger name="*" minlevel="Trace" writeTo="logconsole" />
|
|
||||||
|
|
||||||
<!--Skip non-critical Microsoft logs and so log only own logs-->
|
|
||||||
<logger name="Microsoft.*" maxlevel="Info" final="true" />
|
|
||||||
</rules>
|
|
||||||
</nlog>
|
|
||||||
@ -35,7 +35,6 @@ try
|
|||||||
|
|
||||||
builder.WebHost.ConfigureAppConfiguration((hostingContext, config) =>
|
builder.WebHost.ConfigureAppConfiguration((hostingContext, config) =>
|
||||||
{
|
{
|
||||||
//config.SetBasePath(Directory.GetCurrentDirectory());
|
|
||||||
config.AddIniFile("secrets.ini",
|
config.AddIniFile("secrets.ini",
|
||||||
optional: true, reloadOnChange: true);
|
optional: true, reloadOnChange: true);
|
||||||
config.AddIniFile($"secrets.{hostingContext.HostingEnvironment.EnvironmentName}.ini",
|
config.AddIniFile($"secrets.{hostingContext.HostingEnvironment.EnvironmentName}.ini",
|
||||||
@ -78,10 +77,10 @@ try
|
|||||||
options.Cookie.SameSite = SameSiteMode.Strict;
|
options.Cookie.SameSite = SameSiteMode.Strict;
|
||||||
options.Cookie.HttpOnly = true;
|
options.Cookie.HttpOnly = true;
|
||||||
// options.SessionStore = new JetHeraldTicketStore();
|
// options.SessionStore = new JetHeraldTicketStore();
|
||||||
options.LoginPath = "/login";
|
options.LoginPath = "/ui/login";
|
||||||
options.LogoutPath = "/logout";
|
options.LogoutPath = "/ui/logout";
|
||||||
options.ReturnUrlParameter = "redirect";
|
options.ReturnUrlParameter = "redirect";
|
||||||
options.AccessDeniedPath = "/403";
|
options.AccessDeniedPath = "/ui/403";
|
||||||
options.ClaimsIssuer = "JetHerald";
|
options.ClaimsIssuer = "JetHerald";
|
||||||
});
|
});
|
||||||
services.AddPermissions();
|
services.AddPermissions();
|
||||||
@ -96,6 +95,9 @@ try
|
|||||||
var adminUser = await db.GetUser("admin");
|
var adminUser = await db.GetUser("admin");
|
||||||
if (adminUser == null)
|
if (adminUser == null)
|
||||||
{
|
{
|
||||||
|
var adminRole = (await db.GetRoles()).First(r => r.Name == "admin");
|
||||||
|
var unlimitedPlan = (await db.GetPlans()).First(p => p.Name == "unlimited");
|
||||||
|
|
||||||
var authCfg = app.Services.GetService<IOptions<AuthConfig>>().Value;
|
var authCfg = app.Services.GetService<IOptions<AuthConfig>>().Value;
|
||||||
var password = Convert.ToBase64String(RandomNumberGenerator.GetBytes(48));
|
var password = Convert.ToBase64String(RandomNumberGenerator.GetBytes(48));
|
||||||
adminUser = new JetHerald.Contracts.User()
|
adminUser = new JetHerald.Contracts.User()
|
||||||
@ -103,10 +105,12 @@ try
|
|||||||
Login = "admin",
|
Login = "admin",
|
||||||
Name = "Administrator",
|
Name = "Administrator",
|
||||||
PasswordSalt = RandomNumberGenerator.GetBytes(64),
|
PasswordSalt = RandomNumberGenerator.GetBytes(64),
|
||||||
HashType = authCfg.HashType
|
HashType = authCfg.HashType,
|
||||||
|
RoleId = adminRole.RoleId,
|
||||||
|
PlanId = unlimitedPlan.PlanId
|
||||||
};
|
};
|
||||||
adminUser.PasswordHash = AuthUtils.GetHashFor(password, adminUser.PasswordSalt, adminUser.HashType);
|
adminUser.PasswordHash = AuthUtils.GetHashFor(password, adminUser.PasswordSalt, adminUser.HashType);
|
||||||
var newUser = await db.RegisterUser(adminUser, "admin");
|
var newUser = await db.RegisterUser(adminUser);
|
||||||
log.Warn($"Created administrative account {adminUser.Login}:{password}. Be sure to save these credentials somewhere!");
|
log.Warn($"Created administrative account {adminUser.Login}:{password}. Be sure to save these credentials somewhere!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,11 @@ public class Db
|
|||||||
return await c.QueryAsync<Plan>("SELECT * FROM plan");
|
return await c.QueryAsync<Plan>("SELECT * FROM plan");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Role>> GetRoles()
|
||||||
|
{
|
||||||
|
using var c = GetConnection();
|
||||||
|
return await c.QueryAsync<Role>("SELECT * FROM role");
|
||||||
|
}
|
||||||
public async Task<IEnumerable<UserInvite>> GetInvites()
|
public async Task<IEnumerable<UserInvite>> GetInvites()
|
||||||
{
|
{
|
||||||
using var c = GetConnection();
|
using var c = GetConnection();
|
||||||
@ -33,12 +38,15 @@ public class Db
|
|||||||
new { userId });
|
new { userId });
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task CreateUserInvite(uint planId, string inviteCode)
|
public async Task CreateUserInvite(uint planId, uint roleId, string inviteCode)
|
||||||
{
|
{
|
||||||
using var c = GetConnection();
|
using var c = GetConnection();
|
||||||
await c.ExecuteAsync(
|
await c.ExecuteAsync(@"
|
||||||
"INSERT INTO userinvite (PlanId, InviteCode) VALUES (@planId, @inviteCode)",
|
INSERT INTO userinvite
|
||||||
new { planId, inviteCode });
|
( PlanId, RoleId, InviteCode)
|
||||||
|
VALUES
|
||||||
|
(@planId, @roleId, @inviteCode)",
|
||||||
|
new { planId, roleId, inviteCode });
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Topic> GetTopic(string name)
|
public async Task<Topic> GetTopic(string name)
|
||||||
@ -79,11 +87,12 @@ public class Db
|
|||||||
public async Task<User> GetUser(string login)
|
public async Task<User> GetUser(string login)
|
||||||
{
|
{
|
||||||
using var c = GetConnection();
|
using var c = GetConnection();
|
||||||
return await c.QuerySingleOrDefaultAsync<User>(
|
return await c.QuerySingleOrDefaultAsync<User>(@"
|
||||||
" SELECT u.*, p.* " +
|
SELECT u.*, up.*, ur.*
|
||||||
" FROM user u " +
|
FROM user u
|
||||||
" LEFT JOIN plan p ON p.PlanId = u.PlanId " +
|
JOIN plan up ON u.PlanId = up.PlanId
|
||||||
" WHERE u.Login = @login",
|
JOIN role ur ON u.RoleId = ur.RoleId
|
||||||
|
WHERE u.Login = @login;",
|
||||||
new { login });
|
new { login });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,24 +144,24 @@ public class Db
|
|||||||
return topic;
|
return topic;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<User> RegisterUserFromInvite(User user, uint inviteId)
|
public async Task<User> RegisterUser(User user)
|
||||||
{
|
{
|
||||||
using var c = GetConnection();
|
using var c = GetConnection();
|
||||||
uint userId = await c.QuerySingleOrDefaultAsync<uint>(
|
uint userId = await c.QuerySingleOrDefaultAsync<uint>(@"
|
||||||
"CALL register_user_from_invite(@inviteId, @Login, @Name, @PasswordHash, @PasswordSalt, @HashType);",
|
INSERT INTO user
|
||||||
new { inviteId, user.Login, user.Name, user.PasswordHash, user.PasswordSalt, user.HashType });
|
( Login, Name, PasswordHash, PasswordSalt, HashType, PlanId, RoleId)
|
||||||
|
VALUES
|
||||||
|
(@Login, @Name, @PasswordHash, @PasswordSalt, @HashType, @PlanId, @RoleId);",
|
||||||
|
param:user);
|
||||||
return await GetUser(user.Login);
|
return await GetUser(user.Login);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<User> RegisterUser(User user, string plan)
|
public async Task RedeemInvite(uint inviteId, uint userId)
|
||||||
{
|
{
|
||||||
using var c = GetConnection();
|
using var c = GetConnection();
|
||||||
uint userId = await c.QuerySingleOrDefaultAsync<uint>(
|
await c.ExecuteAsync(
|
||||||
"CALL register_user(@plan, @Login, @Name, @PasswordHash, @PasswordSalt, @HashType);",
|
@"UPDATE userinvite SET RedeemedBy = @userId WHERE UserInviteId = @inviteId",
|
||||||
new { plan, user.Login, user.Name, user.PasswordHash, user.PasswordSalt, user.HashType });
|
new { inviteId, userId });
|
||||||
|
|
||||||
return await GetUser(user.Login);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<UserInvite> GetInviteByCode(string inviteCode)
|
public async Task<UserInvite> GetInviteByCode(string inviteCode)
|
||||||
@ -274,6 +283,6 @@ public class Db
|
|||||||
Config = cfg;
|
Config = cfg;
|
||||||
}
|
}
|
||||||
IOptionsMonitor<ConnectionStrings> Config { get; }
|
IOptionsMonitor<ConnectionStrings> Config { get; }
|
||||||
MySqlConnection GetConnection() => new(Config.CurrentValue.DefaultConnection);
|
public MySqlConnection GetConnection() => new(Config.CurrentValue.DefaultConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<ul class="issues-list">
|
<ul class="issues-list">
|
||||||
<li><a asp-action="CreateProject">Create new project code</a></li>
|
|
||||||
<li><a asp-action="ViewUsers">View all registered users</a></li>
|
<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="ViewInvites">View unredeemed invites</a></li>
|
||||||
<li><a asp-action="ViewRoles">View all roles</a></li>
|
<li><a asp-action="ViewRoles">View all roles</a></li>
|
||||||
|
-->
|
||||||
</ul>
|
</ul>
|
||||||
@ -1,13 +1,21 @@
|
|||||||
@model ViewInvitesModel
|
@model ViewInvitesModel
|
||||||
|
|
||||||
<form asp-controller="AdminTools" asp-action="CreateInvite" method="POST" enctype="application/x-www-form-urlencoded">
|
<form asp-controller="AdminTools" asp-action="CreateInvite" method="POST" enctype="application/x-www-form-urlencoded">
|
||||||
<label for="planselector">Plan: </label>
|
<label for="roleselector">Role:</label>
|
||||||
|
<select name="roleId" required id="roleselector">
|
||||||
|
@foreach (var role in Model.Roles.Values)
|
||||||
|
{
|
||||||
|
<option value="@role.RoleId">@role.Name</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
<label for="planselector">Plan:</label>
|
||||||
<select name="planId" required id="planselector">
|
<select name="planId" required id="planselector">
|
||||||
@foreach (var plan in Model.Plans.Values)
|
@foreach (var plan in Model.Plans.Values)
|
||||||
{
|
{
|
||||||
<option value="@plan.PlanId">@plan.Name</option>
|
<option value="@plan.PlanId">@plan.Name</option>
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<input type="submit" value="Create invite" class="h2 submitpost" style="margin-top:10px; width:initial">
|
<input type="submit" value="Create invite" class="h2 submitpost" style="margin-top:10px; width:initial">
|
||||||
</form>
|
</form>
|
||||||
<br>
|
<br>
|
||||||
@ -17,7 +25,7 @@
|
|||||||
@foreach (var invite in Model.Invites)
|
@foreach (var invite in Model.Invites)
|
||||||
{
|
{
|
||||||
<li>
|
<li>
|
||||||
<span style="font-family:monospace">@invite.InviteCode.Substring(0, 8)... (@Model.Plans[invite.PlanId].Name)</span>
|
<span style="font-family:monospace">@invite.InviteCode.Substring(0, 8)... 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>
|
||||||
|
|||||||
@ -5,5 +5,19 @@
|
|||||||
"System": "Information",
|
"System": "Information",
|
||||||
"Microsoft": "Information"
|
"Microsoft": "Information"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Telegram": {
|
||||||
|
"UseProxy": "true"
|
||||||
|
},
|
||||||
|
"Timeout": {
|
||||||
|
"DebtLimitSeconds": 600,
|
||||||
|
"HeartbeatCost": 60,
|
||||||
|
"ReportCost": 60
|
||||||
|
},
|
||||||
|
"PathBase": "/",
|
||||||
|
"AuthConfig": {
|
||||||
|
"InviteCodeLength": 128,
|
||||||
|
"TicketIdLengthBytes": 64,
|
||||||
|
"HashType": 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Warning"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Telegram": {
|
|
||||||
"UseProxy": "true"
|
|
||||||
},
|
|
||||||
"Timeout": {
|
|
||||||
"DebtLimitSeconds": 600,
|
|
||||||
"HeartbeatCost": 60,
|
|
||||||
"ReportCost": 60
|
|
||||||
},
|
|
||||||
"PathBase": "/",
|
|
||||||
"AuthConfig": {
|
|
||||||
"InviteCodeLength" : 128,
|
|
||||||
"TicketIdLengthBytes": 64,
|
|
||||||
"HashType": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,6 +1,4 @@
|
|||||||
CREATE DATABASE IF NOT EXISTS `herald` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
|
-- MySQL dump 10.13 Distrib 8.0.26, for Linux (x86_64)
|
||||||
USE `herald`;
|
|
||||||
-- MySQL dump 10.13 Distrib 8.0.28, for Win64 (x86_64)
|
|
||||||
--
|
--
|
||||||
-- Host: localhost Database: herald
|
-- Host: localhost Database: herald
|
||||||
-- ------------------------------------------------------
|
-- ------------------------------------------------------
|
||||||
@ -9,7 +7,7 @@ USE `herald`;
|
|||||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||||
/*!50503 SET NAMES utf8 */;
|
/*!50503 SET NAMES utf8mb4 */;
|
||||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||||
@ -28,17 +26,19 @@ CREATE TABLE `heart` (
|
|||||||
`HeartId` bigint unsigned NOT NULL AUTO_INCREMENT,
|
`HeartId` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`TopicId` int unsigned NOT NULL,
|
`TopicId` int unsigned NOT NULL,
|
||||||
`Heart` varchar(32) NOT NULL,
|
`Heart` varchar(32) NOT NULL,
|
||||||
`Status` enum('beating','stopped','deleted') NOT NULL DEFAULT 'beating',
|
`Name` varchar(45) GENERATED ALWAYS AS (`Heart`) VIRTUAL,
|
||||||
|
`Status` varchar(16) NOT NULL DEFAULT 'beating',
|
||||||
`LastBeatTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
`LastBeatTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
`ExpiryTs` timestamp NOT NULL,
|
`ExpiryTs` timestamp NOT NULL,
|
||||||
`CreateTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
`CreateTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
`UpdateTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
`UpdateTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY (`HeartId`),
|
PRIMARY KEY (`HeartId`),
|
||||||
UNIQUE KEY `idx_TopicId_Heart_UNIQUE` (`TopicId`,`Heart`),
|
UNIQUE KEY `idx_TopicId_Heart_UNIQUE` (`TopicId`,`Heart`),
|
||||||
CONSTRAINT `fk_topic` FOREIGN KEY (`TopicId`) REFERENCES `topic` (`TopicId`)
|
CONSTRAINT `fk_heart_TopicId` FOREIGN KEY (`TopicId`) REFERENCES `topic` (`TopicId`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=115140 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
) ENGINE=InnoDB AUTO_INCREMENT=227102 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Table structure for table `heartevent`
|
-- Table structure for table `heartevent`
|
||||||
--
|
--
|
||||||
@ -50,15 +50,68 @@ CREATE TABLE `heartevent` (
|
|||||||
`HeartEventId` bigint unsigned NOT NULL AUTO_INCREMENT,
|
`HeartEventId` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`TopicId` int unsigned NOT NULL,
|
`TopicId` int unsigned NOT NULL,
|
||||||
`Heart` varchar(32) NOT NULL,
|
`Heart` varchar(32) NOT NULL,
|
||||||
`Status` enum('created','processing','reported') NOT NULL DEFAULT 'created',
|
`Status` varchar(16) NOT NULL DEFAULT 'created',
|
||||||
`Event` enum('created','started','stopped','deleted') NOT NULL COMMENT 'ENUM(''created'',''started'',''stopped'',''deleted'')',
|
`Event` varchar(16) NOT NULL COMMENT 'ENUM(''created'',''started'',''stopped'',''deleted'')',
|
||||||
`CreateTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
`CreateTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY (`HeartEventId`),
|
PRIMARY KEY (`HeartEventId`),
|
||||||
KEY `idx_topic` (`TopicId`,`CreateTs`),
|
KEY `idx_topic` (`TopicId`,`CreateTs`),
|
||||||
KEY `idx_reported` (`Status`)
|
KEY `idx_reported` (`Status`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=201 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
) ENGINE=InnoDB AUTO_INCREMENT=372 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `plan`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `plan`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!50503 SET character_set_client = utf8mb4 */;
|
||||||
|
CREATE TABLE `plan` (
|
||||||
|
`PlanId` int unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`Name` varchar(45) NOT NULL,
|
||||||
|
`MaxTopics` int unsigned NOT NULL,
|
||||||
|
`TimeoutMultiplier` double NOT NULL,
|
||||||
|
PRIMARY KEY (`PlanId`),
|
||||||
|
UNIQUE KEY `Name_UNIQUE` (`Name`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=4099 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `plan`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `plan` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `plan` DISABLE KEYS */;
|
||||||
|
INSERT INTO `plan` VALUES (4096,'none',0,1),(4097,'unlimited',1000000,0);
|
||||||
|
/*!40000 ALTER TABLE `plan` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `role`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `role`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!50503 SET character_set_client = utf8mb4 */;
|
||||||
|
CREATE TABLE `role` (
|
||||||
|
`RoleId` int unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`Name` varchar(45) NOT NULL,
|
||||||
|
`Allow` text NOT NULL,
|
||||||
|
PRIMARY KEY (`RoleId`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=4099 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `role`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `role` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `role` DISABLE KEYS */;
|
||||||
|
INSERT INTO `role` VALUES (4096,'anonymous','login;register;'),(4097,'admin','**;'),(4098,'client','dashboard;profile;topic;');
|
||||||
|
/*!40000 ALTER TABLE `role` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Table structure for table `topic`
|
-- Table structure for table `topic`
|
||||||
--
|
--
|
||||||
@ -69,11 +122,11 @@ DROP TABLE IF EXISTS `topic`;
|
|||||||
CREATE TABLE `topic` (
|
CREATE TABLE `topic` (
|
||||||
`TopicId` int unsigned NOT NULL AUTO_INCREMENT,
|
`TopicId` int unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`Creator` varchar(45) NOT NULL,
|
`Creator` varchar(45) NOT NULL,
|
||||||
|
`CreatorId` int unsigned NOT NULL,
|
||||||
`Name` varchar(45) NOT NULL,
|
`Name` varchar(45) NOT NULL,
|
||||||
`Description` varchar(45) NOT NULL,
|
`Description` varchar(45) NOT NULL,
|
||||||
`ReadToken` char(32) NOT NULL,
|
`ReadToken` char(32) NOT NULL,
|
||||||
`WriteToken` char(32) NOT NULL,
|
`WriteToken` char(32) NOT NULL,
|
||||||
`AdminToken` char(32) NOT NULL,
|
|
||||||
`CreateTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
`CreateTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
`UpdateTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
`UpdateTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY (`TopicId`),
|
PRIMARY KEY (`TopicId`),
|
||||||
@ -95,14 +148,87 @@ CREATE TABLE `topic_sub` (
|
|||||||
`Sub` varchar(45) NOT NULL,
|
`Sub` varchar(45) NOT NULL,
|
||||||
`CreateTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
`CreateTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY (`TopicId`,`Sub`),
|
PRIMARY KEY (`TopicId`,`Sub`),
|
||||||
CONSTRAINT `FK_TOPICID` FOREIGN KEY (`TopicId`) REFERENCES `topic` (`TopicId`) ON DELETE CASCADE
|
CONSTRAINT `fk_topic_sub_TopicId` FOREIGN KEY (`TopicId`) REFERENCES `topic` (`TopicId`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Dumping events for database 'herald'
|
-- Table structure for table `user`
|
||||||
--
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `user`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!50503 SET character_set_client = utf8mb4 */;
|
||||||
|
CREATE TABLE `user` (
|
||||||
|
`UserId` int unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`PlanId` int unsigned NOT NULL,
|
||||||
|
`RoleId` int unsigned NOT NULL,
|
||||||
|
`Login` varchar(45) NOT NULL,
|
||||||
|
`Name` varchar(255) NOT NULL,
|
||||||
|
`PasswordHash` varbinary(255) NOT NULL,
|
||||||
|
`PasswordSalt` varbinary(255) NOT NULL,
|
||||||
|
`HashType` tinyint NOT NULL DEFAULT '1',
|
||||||
|
`CreateTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`UpdateTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`UserId`),
|
||||||
|
KEY `idx_user_PlanId` (`PlanId`),
|
||||||
|
KEY `fk_user_RoleId_idx` (`RoleId`),
|
||||||
|
CONSTRAINT `fk_user_PlanId` FOREIGN KEY (`PlanId`) REFERENCES `plan` (`PlanId`),
|
||||||
|
CONSTRAINT `fk_user_RoleId` FOREIGN KEY (`RoleId`) REFERENCES `role` (`RoleId`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=4111 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `user`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `user` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `user` DISABLE KEYS */;
|
||||||
|
INSERT INTO `user` VALUES (4096,4096,4096,'Anonymous','Anonymous',0xBADC0D35,0xBADC0D35,0,NOW(),NOW());
|
||||||
|
/*!40000 ALTER TABLE `user` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `userinvite`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `userinvite`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!50503 SET character_set_client = utf8mb4 */;
|
||||||
|
CREATE TABLE `userinvite` (
|
||||||
|
`UserInviteId` int NOT NULL AUTO_INCREMENT,
|
||||||
|
`PlanId` int unsigned NOT NULL,
|
||||||
|
`RoleId` int unsigned NOT NULL DEFAULT '4096',
|
||||||
|
`InviteCode` varchar(255) NOT NULL,
|
||||||
|
`RedeemedBy` int unsigned DEFAULT NULL,
|
||||||
|
`CreateTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`UpdateTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`UserInviteId`),
|
||||||
|
UNIQUE KEY `InviteCode_UNIQUE` (`InviteCode`),
|
||||||
|
KEY `fk_PlanId_idx` (`PlanId`),
|
||||||
|
KEY `fk_userinvite_RoleId_idx` (`RoleId`),
|
||||||
|
CONSTRAINT `fk_userinvite_PlanId` FOREIGN KEY (`PlanId`) REFERENCES `plan` (`PlanId`),
|
||||||
|
CONSTRAINT `fk_userinvite_RoleId` FOREIGN KEY (`RoleId`) REFERENCES `role` (`RoleId`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `usersession`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `usersession`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!50503 SET character_set_client = utf8mb4 */;
|
||||||
|
CREATE TABLE `usersession` (
|
||||||
|
`SessionId` varchar(255) NOT NULL,
|
||||||
|
`SessionData` blob NOT NULL,
|
||||||
|
`ExpiryTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
`CreateTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`UpdateTs` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`SessionId`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Dumping routines for database 'herald'
|
-- Dumping routines for database 'herald'
|
||||||
--
|
--
|
||||||
@ -116,33 +242,31 @@ CREATE TABLE `topic_sub` (
|
|||||||
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
||||||
/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION' */ ;
|
/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION' */ ;
|
||||||
DELIMITER ;;
|
DELIMITER ;;
|
||||||
CREATE PROCEDURE `process_hearts`()
|
CREATE DEFINER=`herald`@`%` PROCEDURE `process_hearts`()
|
||||||
BEGIN
|
BEGIN
|
||||||
|
START TRANSACTION;
|
||||||
START TRANSACTION;
|
|
||||||
|
|
||||||
SET @ts = NOW();
|
SET @ts = NOW();
|
||||||
|
|
||||||
INSERT INTO heartevent
|
INSERT INTO heartevent
|
||||||
(TopicId, Heart, `Event`)
|
(TopicId, Heart, Event)
|
||||||
SELECT
|
SELECT
|
||||||
TopicId, Heart, 'stopped'
|
TopicID, Heart, 'stopped'
|
||||||
FROM heart
|
FROM heart
|
||||||
WHERE ExpiryTs < @ts AND `Status` = 'beating';
|
WHERE ExpiryTs < @ts AND Status = 'beating';
|
||||||
|
|
||||||
UPDATE heart SET `Status` = 'stopped' WHERE ExpiryTs < @ts AND `Status` = 'beating' AND HeartId > 0;
|
|
||||||
|
|
||||||
|
UPDATE heart set Status = 'stopped' WHERE ExpiryTs < @ts AND Status = 'beating' AND HeartId > 0;
|
||||||
SET @id = (SELECT HeartEventId FROM heartevent WHERE `Status` = 'created' ORDER BY HeartEventId DESC LIMIT 1);
|
SET @id = (SELECT HeartEventId FROM heartevent WHERE `Status` = 'created' ORDER BY HeartEventId DESC LIMIT 1);
|
||||||
|
|
||||||
UPDATE heartevent SET `Status` = 'processing' WHERE HeartEventId = @id;
|
UPDATE heartevent SET `Status` = 'processing' WHERE HeartEventId = @id;
|
||||||
|
|
||||||
SELECT ha.*, t.`Description`
|
SELECT ha.*, t.`Description`
|
||||||
FROM heartevent ha
|
FROM heartevent ha
|
||||||
JOIN topic t USING (TopicId)
|
JOIN topic t USING (TopicId)
|
||||||
WHERE HeartEventId = @id;
|
WHERE HeartEventId = @id;
|
||||||
|
COMMIT;
|
||||||
COMMIT;
|
|
||||||
|
|
||||||
END ;;
|
END ;;
|
||||||
DELIMITER ;
|
DELIMITER ;
|
||||||
|
|
||||||
/*!50003 SET sql_mode = @saved_sql_mode */ ;
|
/*!50003 SET sql_mode = @saved_sql_mode */ ;
|
||||||
/*!50003 SET character_set_client = @saved_cs_client */ ;
|
/*!50003 SET character_set_client = @saved_cs_client */ ;
|
||||||
/*!50003 SET character_set_results = @saved_cs_results */ ;
|
/*!50003 SET character_set_results = @saved_cs_results */ ;
|
||||||
@ -157,18 +281,27 @@ DELIMITER ;
|
|||||||
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
||||||
/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION' */ ;
|
/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION' */ ;
|
||||||
DELIMITER ;;
|
DELIMITER ;;
|
||||||
CREATE PROCEDURE `report_heartbeat`(_topicId INT UNSIGNED, _heart VARCHAR(45), _timeoutSeconds INTEGER UNSIGNED)
|
CREATE DEFINER=`herald`@`%` PROCEDURE `report_heartbeat`(_topicId INT UNSIGNED, _heart VARCHAR(45), _timeoutSeconds INTEGER UNSIGNED)
|
||||||
BEGIN
|
BEGIN
|
||||||
DECLARE beating INTEGER DEFAULT 0;
|
DECLARE beating INTEGER DEFAULT 0;
|
||||||
START TRANSACTION;
|
START TRANSACTION;
|
||||||
SET beating = EXISTS(SELECT * FROM heart WHERE TopicId = _topicId AND Heart = _heart AND `Status` = `beating`);
|
SET beating = EXISTS(SELECT * FROM heart WHERE TopicId = _topicId AND Heart = _heart AND `Status` = 'beating');
|
||||||
INSERT INTO heart
|
INSERT INTO heart
|
||||||
(TopicId, Heart, `Status`, ExpiryTs)
|
(TopicId, Heart, `Status`, ExpiryTs)
|
||||||
VALUES
|
VALUES
|
||||||
(_topicId, _heart, 'beating', CURRENT_TIMESTAMP() + INTERVAL _timeoutSeconds SECOND)
|
(_topicId, _heart, 'beating', CURRENT_TIMESTAMP() + INTERVAL _timeoutSeconds SECOND)
|
||||||
ON DUPLICATE KEY UPDATE
|
ON DUPLICATE KEY UPDATE
|
||||||
`Status` = 'beating',
|
`Status` = 'beating',
|
||||||
|
LastBeatTs = CURRENT_TIMESTAMP(),
|
||||||
ExpiryTs = CURRENT_TIMESTAMP() + INTERVAL _timeoutSeconds SECOND;
|
ExpiryTs = CURRENT_TIMESTAMP() + INTERVAL _timeoutSeconds SECOND;
|
||||||
|
|
||||||
|
IF NOT beating THEN
|
||||||
|
INSERT INTO heartevent
|
||||||
|
(TopicId, Heart, Event)
|
||||||
|
SELECT
|
||||||
|
_topicId, _heart, 'started';
|
||||||
|
END IF;
|
||||||
|
|
||||||
SELECT beating;
|
SELECT beating;
|
||||||
COMMIT;
|
COMMIT;
|
||||||
END ;;
|
END ;;
|
||||||
@ -187,4 +320,4 @@ DELIMITER ;
|
|||||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||||
|
|
||||||
-- Dump completed on 2022-01-28 17:03:44
|
-- Dump completed on 2022-05-13 18:44:48
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user