mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-08-01 17:48:41 +00:00
Merge main into mod-panel
This commit is contained in:
commit
b2e6f25265
38 changed files with 468 additions and 139 deletions
|
@ -3,11 +3,13 @@
|
||||||
<component name="UserContentModel">
|
<component name="UserContentModel">
|
||||||
<attachedFolders />
|
<attachedFolders />
|
||||||
<explicitIncludes>
|
<explicitIncludes>
|
||||||
|
<Path>.config/dotnet-tools.json</Path>
|
||||||
<Path>.github</Path>
|
<Path>.github</Path>
|
||||||
<Path>.gitignore</Path>
|
<Path>.gitignore</Path>
|
||||||
<Path>.idea</Path>
|
<Path>.idea</Path>
|
||||||
<Path>CONTRIBUTING.md</Path>
|
<Path>CONTRIBUTING.md</Path>
|
||||||
<Path>DatabaseMigrations</Path>
|
<Path>DatabaseMigrations</Path>
|
||||||
|
<Path>LICENSE</Path>
|
||||||
<Path>ProjectLighthouse.sln.DotSettings</Path>
|
<Path>ProjectLighthouse.sln.DotSettings</Path>
|
||||||
<Path>ProjectLighthouse.sln.DotSettings.user</Path>
|
<Path>ProjectLighthouse.sln.DotSettings.user</Path>
|
||||||
<Path>README.md</Path>
|
<Path>README.md</Path>
|
||||||
|
|
|
@ -130,7 +130,7 @@ public class LoginController : ControllerBase
|
||||||
new LoginResult
|
new LoginResult
|
||||||
{
|
{
|
||||||
AuthTicket = "MM_AUTH=" + token.UserToken,
|
AuthTicket = "MM_AUTH=" + token.UserToken,
|
||||||
LbpEnvVer = ServerStatics.ServerName,
|
ServerBrand = VersionHelper.FullVersion,
|
||||||
}.Serialize()
|
}.Serialize()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,9 +86,9 @@ public class PublishController : ControllerBase
|
||||||
|
|
||||||
if (slot.Location == null) return this.BadRequest();
|
if (slot.Location == null) return this.BadRequest();
|
||||||
|
|
||||||
if (slot.Description.Length > 200) return this.BadRequest();
|
if (slot.Description.Length > 500) return this.BadRequest();
|
||||||
|
|
||||||
if (slot.Name.Length > 100) return this.BadRequest();
|
if (slot.Name.Length > 64) return this.BadRequest();
|
||||||
|
|
||||||
if (slot.Resources.Any(resource => !FileHelper.ResourceExists(resource)))
|
if (slot.Resources.Any(resource => !FileHelper.ResourceExists(resource)))
|
||||||
{
|
{
|
||||||
|
|
|
@ -96,7 +96,7 @@ public class ReviewController : ControllerBase
|
||||||
Review? newReview = await this.getReviewFromBody();
|
Review? newReview = await this.getReviewFromBody();
|
||||||
if (newReview == null) return this.BadRequest();
|
if (newReview == null) return this.BadRequest();
|
||||||
|
|
||||||
if (newReview.Text.Length > 100) return this.BadRequest();
|
if (newReview.Text.Length > 512) return this.BadRequest();
|
||||||
|
|
||||||
Review? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == user.UserId);
|
Review? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == user.UserId);
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class RoomVisualizerController : ControllerBase
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
return this.NotFound();
|
return this.NotFound();
|
||||||
#else
|
#else
|
||||||
RoomHelper.Rooms.RemoveAll();
|
lock(RoomHelper.RoomLock) RoomHelper.Rooms.RemoveAll();
|
||||||
return this.Redirect("/debug/roomVisualizer");
|
return this.Redirect("/debug/roomVisualizer");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
@page "/"
|
@page "/"
|
||||||
@using LBPUnion.ProjectLighthouse.Configuration
|
@using LBPUnion.ProjectLighthouse.Configuration
|
||||||
|
@using LBPUnion.ProjectLighthouse.Extensions
|
||||||
@using LBPUnion.ProjectLighthouse.PlayerData.Profiles
|
@using LBPUnion.ProjectLighthouse.PlayerData.Profiles
|
||||||
@using LBPUnion.ProjectLighthouse.Types
|
@using LBPUnion.ProjectLighthouse.Levels
|
||||||
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.LandingPage
|
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.LandingPage
|
||||||
|
|
||||||
@{
|
@{
|
||||||
Layout = "Layouts/BaseLayout";
|
Layout = "Layouts/BaseLayout";
|
||||||
Model.ShowTitleInPage = false;
|
Model.ShowTitleInPage = false;
|
||||||
|
bool isMobile = this.Request.IsMobile();
|
||||||
}
|
}
|
||||||
<h1>Welcome to <b>Project Lighthouse</b>!</h1>
|
<h1>Welcome to <b>@ServerConfiguration.Instance.Customization.ServerName</b>!</h1>
|
||||||
|
|
||||||
@if (Model.User != null)
|
@if (Model.User != null)
|
||||||
{
|
{
|
||||||
|
@ -42,3 +44,38 @@ else
|
||||||
<a href="/user/@user.UserId" title="@user.Status.ToString()">@user.Username</a>
|
<a href="/user/@user.UserId" title="@user.Status.ToString()">@user.Username</a>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div class="@(isMobile ? "" : "ui center aligned grid")">
|
||||||
|
<div class="eight wide column">
|
||||||
|
<div class="ui pink segment">
|
||||||
|
<h1><i class="ribbon icon"></i>Latest Team Picks</h1>
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
<div class="ui left aligned segment">
|
||||||
|
@foreach (Slot slot in Model.LatestTeamPicks!) @* Can't reach a point where this is null *@
|
||||||
|
{
|
||||||
|
@await Html.PartialAsync("Partials/SlotCardPartial", slot, Model.GetSlotViewData(slot.SlotId, isMobile))
|
||||||
|
<br>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if (isMobile)
|
||||||
|
{
|
||||||
|
<br>
|
||||||
|
}
|
||||||
|
<div class="eight wide column">
|
||||||
|
<div class="ui blue segment">
|
||||||
|
<h1><i class="certificate icon"></i>Newest Levels</h1>
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
<div class="ui left aligned segment">
|
||||||
|
@foreach (Slot slot in Model.NewestLevels!) @* Can't reach a point where this is null *@
|
||||||
|
{
|
||||||
|
@await Html.PartialAsync("Partials/SlotCardPartial", slot, Model.GetSlotViewData(slot.SlotId, isMobile))
|
||||||
|
<br>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1,23 +1,27 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
using LBPUnion.ProjectLighthouse.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
|
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
|
||||||
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
|
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
|
||||||
using LBPUnion.ProjectLighthouse.Types;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages;
|
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages;
|
||||||
|
|
||||||
public class LandingPage : BaseLayout
|
public class LandingPage : BaseLayout
|
||||||
{
|
{
|
||||||
|
public LandingPage(Database database) : base(database)
|
||||||
|
{}
|
||||||
|
|
||||||
public int AuthenticationAttemptsCount;
|
public int AuthenticationAttemptsCount;
|
||||||
public List<User> PlayersOnline = new();
|
public List<User> PlayersOnline = new();
|
||||||
|
|
||||||
public int PlayersOnlineCount;
|
public int PlayersOnlineCount;
|
||||||
public LandingPage(Database database) : base(database)
|
|
||||||
{}
|
public List<Slot>? LatestTeamPicks;
|
||||||
|
public List<Slot>? NewestLevels;
|
||||||
|
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public async Task<IActionResult> OnGet()
|
public async Task<IActionResult> OnGet()
|
||||||
|
@ -35,6 +39,38 @@ public class LandingPage : BaseLayout
|
||||||
List<int> userIds = await this.Database.LastContacts.Where(l => TimeHelper.Timestamp - l.Timestamp < 300).Select(l => l.UserId).ToListAsync();
|
List<int> userIds = await this.Database.LastContacts.Where(l => TimeHelper.Timestamp - l.Timestamp < 300).Select(l => l.UserId).ToListAsync();
|
||||||
|
|
||||||
this.PlayersOnline = await this.Database.Users.Where(u => userIds.Contains(u.UserId)).ToListAsync();
|
this.PlayersOnline = await this.Database.Users.Where(u => userIds.Contains(u.UserId)).ToListAsync();
|
||||||
|
|
||||||
|
const int maxShownLevels = 5;
|
||||||
|
|
||||||
|
this.LatestTeamPicks = await this.Database.Slots.Where
|
||||||
|
(s => s.TeamPick)
|
||||||
|
.OrderByDescending(s => s.FirstUploaded)
|
||||||
|
.Take(maxShownLevels)
|
||||||
|
.Include(s => s.Creator)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
this.NewestLevels = await this.Database.Slots.OrderByDescending(s => s.FirstUploaded).Take(maxShownLevels).Include(s => s.Creator).ToListAsync();
|
||||||
|
|
||||||
return this.Page();
|
return this.Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ViewDataDictionary GetSlotViewData(int slotId, bool isMobile = false)
|
||||||
|
=> new(ViewData)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"User", this.User
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CallbackUrl", $"~/slot/{slotId}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ShowLink", true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IsMini", true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IsMobile", isMobile
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
|
@ -33,11 +33,11 @@
|
||||||
<head>
|
<head>
|
||||||
@if (Model.Title == string.Empty)
|
@if (Model.Title == string.Empty)
|
||||||
{
|
{
|
||||||
<title>Project Lighthouse</title>
|
<title>@ServerConfiguration.Instance.Customization.ServerName</title>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<title>Project Lighthouse - @Model.Title</title>
|
<title>@ServerConfiguration.Instance.Customization.ServerName - @Model.Title</title>
|
||||||
}
|
}
|
||||||
<link rel="stylesheet" type="text/css" href="~/css/styles.css">
|
<link rel="stylesheet" type="text/css" href="~/css/styles.css">
|
||||||
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.8.8/dist/semantic.min.css">
|
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.8.8/dist/semantic.min.css">
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
|
|
||||||
@* Embed Stuff *@
|
@* Embed Stuff *@
|
||||||
<meta name="theme-color" data-react-helmet="true" content="#008cff">
|
<meta name="theme-color" data-react-helmet="true" content="#008cff">
|
||||||
<meta content="Project Lighthouse - @Model.Title" property="og:title">
|
<meta content="@ServerConfiguration.Instance.Customization.ServerName - @Model.Title" property="og:title">
|
||||||
@if (!string.IsNullOrEmpty(Model.Description))
|
@if (!string.IsNullOrEmpty(Model.Description))
|
||||||
{
|
{
|
||||||
<meta content="@Model.Description" property="og:description">
|
<meta content="@Model.Description" property="og:description">
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
@using LBPUnion.ProjectLighthouse.Configuration
|
@using LBPUnion.ProjectLighthouse.Configuration
|
||||||
@using LBPUnion.ProjectLighthouse.PlayerData
|
@using LBPUnion.ProjectLighthouse.PlayerData
|
||||||
@using LBPUnion.ProjectLighthouse.PlayerData.Profiles
|
@using LBPUnion.ProjectLighthouse.PlayerData.Profiles
|
||||||
@using LBPUnion.ProjectLighthouse.Types
|
|
||||||
@using Microsoft.EntityFrameworkCore
|
@using Microsoft.EntityFrameworkCore
|
||||||
@model LBPUnion.ProjectLighthouse.Levels.Slot
|
@model LBPUnion.ProjectLighthouse.Levels.Slot
|
||||||
|
|
||||||
|
@ -12,7 +11,9 @@
|
||||||
await using Database database = new();
|
await using Database database = new();
|
||||||
|
|
||||||
string slotName = string.IsNullOrEmpty(Model.Name) ? "Unnamed Level" : Model.Name;
|
string slotName = string.IsNullOrEmpty(Model.Name) ? "Unnamed Level" : Model.Name;
|
||||||
|
|
||||||
bool isMobile = (bool?)ViewData["IsMobile"] ?? false;
|
bool isMobile = (bool?)ViewData["IsMobile"] ?? false;
|
||||||
|
bool mini = (bool?)ViewData["IsMini"] ?? false;
|
||||||
|
|
||||||
bool isQueued = false;
|
bool isQueued = false;
|
||||||
bool isHearted = false;
|
bool isHearted = false;
|
||||||
|
@ -31,13 +32,15 @@
|
||||||
}
|
}
|
||||||
<div class="card">
|
<div class="card">
|
||||||
@{
|
@{
|
||||||
int size = isMobile ? 50 : 100;
|
int size = isMobile || mini ? 50 : 100;
|
||||||
}
|
}
|
||||||
<div>
|
<div>
|
||||||
<img src="~/assets/slotCardOverlay.png" style="min-width: @(size)px; width: @(size)px; height: @(size)px; pointer-events: none; position: absolute">
|
<img src="~/assets/slotCardOverlay.png" style="min-width: @(size)px; width: @(size)px; height: @(size)px; pointer-events: none; position: absolute">
|
||||||
<img class="cardIcon slotCardIcon" src="/gameAssets/@iconHash" style="min-width: @(size)px; width: @(size)px; height: @(size)px">
|
<img class="cardIcon slotCardIcon" src="/gameAssets/@iconHash" style="min-width: @(size)px; width: @(size)px; height: @(size)px">
|
||||||
</div>
|
</div>
|
||||||
<div class="cardStats">
|
<div class="cardStats">
|
||||||
|
@if (!mini)
|
||||||
|
{
|
||||||
@if (showLink)
|
@if (showLink)
|
||||||
{
|
{
|
||||||
<h2>
|
<h2>
|
||||||
|
@ -50,6 +53,23 @@
|
||||||
@slotName
|
@slotName
|
||||||
</h1>
|
</h1>
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@if (showLink)
|
||||||
|
{
|
||||||
|
<h3>
|
||||||
|
<a href="~/slot/@Model.SlotId">@slotName</a>
|
||||||
|
</h3>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<h3>
|
||||||
|
@slotName
|
||||||
|
</h3>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
<div class="cardStatsUnderTitle">
|
<div class="cardStatsUnderTitle">
|
||||||
<i class="pink heart icon" title="Hearts"></i> <span>@Model.Hearts</span>
|
<i class="pink heart icon" title="Hearts"></i> <span>@Model.Hearts</span>
|
||||||
<i class="blue play icon" title="Plays"></i> <span>@Model.PlaysUnique</span>
|
<i class="blue play icon" title="Plays"></i> <span>@Model.PlaysUnique</span>
|
||||||
|
@ -68,7 +88,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="cardButtons">
|
<div class="cardButtons">
|
||||||
<br>
|
<br>
|
||||||
@if (user != null)
|
@if (user != null && !mini)
|
||||||
{
|
{
|
||||||
if (isHearted)
|
if (isHearted)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using LBPUnion.ProjectLighthouse.Configuration;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
|
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
|
||||||
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
|
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
|
||||||
|
@ -38,7 +39,8 @@ public class PasswordResetPage : BaseLayout
|
||||||
|
|
||||||
await this.Database.SaveChangesAsync();
|
await this.Database.SaveChangesAsync();
|
||||||
|
|
||||||
if (!user.EmailAddressVerified) return this.Redirect("~/login/sendVerificationEmail");
|
if (!user.EmailAddressVerified && ServerConfiguration.Instance.Mail.MailEnabled)
|
||||||
|
return this.Redirect("~/login/sendVerificationEmail");
|
||||||
|
|
||||||
return this.Redirect("~/");
|
return this.Redirect("~/");
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using LBPUnion.ProjectLighthouse.Configuration;
|
using LBPUnion.ProjectLighthouse.Configuration;
|
||||||
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.PlayerData;
|
using LBPUnion.ProjectLighthouse.PlayerData;
|
||||||
using LBPUnion.ProjectLighthouse.Tests;
|
using LBPUnion.ProjectLighthouse.Tests;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
@ -25,7 +26,7 @@ public class AuthenticationTests : LighthouseServerTest
|
||||||
Assert.True(response.IsSuccessStatusCode);
|
Assert.True(response.IsSuccessStatusCode);
|
||||||
string responseContent = await response.Content.ReadAsStringAsync();
|
string responseContent = await response.Content.ReadAsStringAsync();
|
||||||
Assert.Contains("MM_AUTH=", responseContent);
|
Assert.Contains("MM_AUTH=", responseContent);
|
||||||
Assert.Contains(ServerStatics.ServerName, responseContent);
|
Assert.Contains(VersionHelper.FullVersion, responseContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
[DatabaseFact]
|
[DatabaseFact]
|
||||||
|
@ -35,10 +36,10 @@ public class AuthenticationTests : LighthouseServerTest
|
||||||
|
|
||||||
Assert.NotNull(loginResult);
|
Assert.NotNull(loginResult);
|
||||||
Assert.NotNull(loginResult.AuthTicket);
|
Assert.NotNull(loginResult.AuthTicket);
|
||||||
Assert.NotNull(loginResult.LbpEnvVer);
|
Assert.NotNull(loginResult.ServerBrand);
|
||||||
|
|
||||||
Assert.Contains("MM_AUTH=", loginResult.AuthTicket);
|
Assert.Contains("MM_AUTH=", loginResult.AuthTicket);
|
||||||
Assert.Equal(ServerStatics.ServerName, loginResult.LbpEnvVer);
|
Assert.Equal(VersionHelper.FullVersion, loginResult.ServerBrand);
|
||||||
}
|
}
|
||||||
|
|
||||||
[DatabaseFact]
|
[DatabaseFact]
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||||
<PackageReference Include="Selenium.WebDriver" Version="4.1.1" />
|
<PackageReference Include="Selenium.WebDriver" Version="4.2.0" />
|
||||||
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="101.0.4951.4100" />
|
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="101.0.4951.4100" />
|
||||||
<PackageReference Include="xunit" Version="2.4.1" />
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||||
|
|
|
@ -115,6 +115,7 @@
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=dpadrate/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=dpadrate/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=ezoiar/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=ezoiar/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=farc/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=farc/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=FLUSHALL/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=friendscores/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=friendscores/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Ingame/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Ingame/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Kettu/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Kettu/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
|
25
ProjectLighthouse/Administration/CompletedMigration.cs
Normal file
25
ProjectLighthouse/Administration/CompletedMigration.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using LBPUnion.ProjectLighthouse.Administration.Maintenance;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Administration;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A record of the completion of a <see cref="IMigrationTask"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class CompletedMigration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the migration.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Do not use the user-friendly name when setting this.
|
||||||
|
/// </remarks>
|
||||||
|
[Key]
|
||||||
|
public string MigrationName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The moment the migration was ran.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime RanAt { get; set; }
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
|
using LBPUnion.ProjectLighthouse.StorableLists;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Administration.Maintenance.Commands;
|
||||||
|
|
||||||
|
public class FlushRedisCommand : ICommand
|
||||||
|
{
|
||||||
|
public string Name() => "Flush Redis";
|
||||||
|
public string[] Aliases() => new[] {
|
||||||
|
"flush", "flush-redis",
|
||||||
|
};
|
||||||
|
public string Arguments() => "";
|
||||||
|
public int RequiredArgs() => 0;
|
||||||
|
|
||||||
|
public async Task Run(string[] args, Logger logger)
|
||||||
|
{
|
||||||
|
await RedisDatabase.FlushAll();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Administration.Maintenance;
|
namespace LBPUnion.ProjectLighthouse.Administration.Maintenance;
|
||||||
|
|
||||||
|
[UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)]
|
||||||
public interface IMaintenanceJob
|
public interface IMaintenanceJob
|
||||||
{
|
{
|
||||||
public Task Run();
|
public Task Run();
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Administration.Maintenance;
|
||||||
|
|
||||||
|
[UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)]
|
||||||
|
public interface IMigrationTask
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The user-friendly name of a migration.
|
||||||
|
/// </summary>
|
||||||
|
public string Name();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs the migration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="database">The Lighthouse database.</param>
|
||||||
|
/// <returns>True if successful, false if not.</returns>
|
||||||
|
internal Task<bool> Run(Database database);
|
||||||
|
}
|
|
@ -1,9 +1,11 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Logging.Loggers;
|
using LBPUnion.ProjectLighthouse.Logging.Loggers;
|
||||||
|
|
||||||
|
@ -11,24 +13,16 @@ namespace LBPUnion.ProjectLighthouse.Administration.Maintenance;
|
||||||
|
|
||||||
public static class MaintenanceHelper
|
public static class MaintenanceHelper
|
||||||
{
|
{
|
||||||
|
|
||||||
static MaintenanceHelper()
|
static MaintenanceHelper()
|
||||||
{
|
{
|
||||||
Commands = getListOfInterfaceObjects<ICommand>();
|
Commands = getListOfInterfaceObjects<ICommand>();
|
||||||
MaintenanceJobs = getListOfInterfaceObjects<IMaintenanceJob>();
|
MaintenanceJobs = getListOfInterfaceObjects<IMaintenanceJob>();
|
||||||
|
MigrationTasks = getListOfInterfaceObjects<IMigrationTask>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<ICommand> Commands { get; }
|
public static List<ICommand> Commands { get; }
|
||||||
|
|
||||||
public static List<IMaintenanceJob> MaintenanceJobs { get; }
|
public static List<IMaintenanceJob> MaintenanceJobs { get; }
|
||||||
|
public static List<IMigrationTask> MigrationTasks { get; }
|
||||||
private static List<T> getListOfInterfaceObjects<T>() where T : class
|
|
||||||
{
|
|
||||||
return Assembly.GetExecutingAssembly()
|
|
||||||
.GetTypes()
|
|
||||||
.Where(t => t.GetInterfaces().Contains(typeof(T)) && t.GetConstructor(Type.EmptyTypes) != null)
|
|
||||||
.Select(t => Activator.CreateInstance(t) as T)
|
|
||||||
.ToList()!;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<List<LogLine>> RunCommand(string[] args)
|
public static async Task<List<LogLine>> RunCommand(string[] args)
|
||||||
{
|
{
|
||||||
|
@ -66,11 +60,57 @@ public static class MaintenanceHelper
|
||||||
IMaintenanceJob? job = MaintenanceJobs.FirstOrDefault(j => j.GetType().Name == jobName);
|
IMaintenanceJob? job = MaintenanceJobs.FirstOrDefault(j => j.GetType().Name == jobName);
|
||||||
if (job == null) throw new ArgumentNullException();
|
if (job == null) throw new ArgumentNullException();
|
||||||
|
|
||||||
await RunMaintenanceJob(job);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task RunMaintenanceJob(IMaintenanceJob job)
|
|
||||||
{
|
|
||||||
await job.Run();
|
await job.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task RunMigration(IMigrationTask migrationTask, Database? database = null)
|
||||||
|
{
|
||||||
|
database ??= new Database();
|
||||||
|
|
||||||
|
// Migrations should never be run twice.
|
||||||
|
Debug.Assert(!await database.CompletedMigrations.Has(m => m.MigrationName == migrationTask.GetType().Name));
|
||||||
|
|
||||||
|
Logger.Info($"Running migration task {migrationTask.Name()}", LogArea.Database);
|
||||||
|
|
||||||
|
bool success;
|
||||||
|
Exception? exception = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
success = await migrationTask.Run(database);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
exception = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!success)
|
||||||
|
{
|
||||||
|
Logger.Error($"Could not run migration {migrationTask.Name()}", LogArea.Database);
|
||||||
|
if (exception != null) Logger.Error(exception.ToDetailedException(), LogArea.Database);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Success($"Successfully completed migration {migrationTask.Name()}", LogArea.Database);
|
||||||
|
|
||||||
|
CompletedMigration completedMigration = new()
|
||||||
|
{
|
||||||
|
MigrationName = migrationTask.GetType().Name,
|
||||||
|
RanAt = DateTime.Now,
|
||||||
|
};
|
||||||
|
|
||||||
|
database.CompletedMigrations.Add(completedMigration);
|
||||||
|
await database.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<T> getListOfInterfaceObjects<T>() where T : class
|
||||||
|
{
|
||||||
|
return Assembly.GetExecutingAssembly()
|
||||||
|
.GetTypes()
|
||||||
|
.Where(t => t.GetInterfaces().Contains(typeof(T)) && t.GetConstructor(Type.EmptyTypes) != null)
|
||||||
|
.Select(t => Activator.CreateInstance(t) as T)
|
||||||
|
.ToList()!;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -25,7 +25,7 @@ public class CleanupBrokenPhotosMaintenanceJob : IMaintenanceJob
|
||||||
bool largeHashIsInvalidFile = false;
|
bool largeHashIsInvalidFile = false;
|
||||||
bool tooManyPhotoSubjects = false;
|
bool tooManyPhotoSubjects = false;
|
||||||
bool duplicatePhotoSubjects = false;
|
bool duplicatePhotoSubjects = false;
|
||||||
bool takenInTheFuture = true;
|
bool takenInTheFuture = false;
|
||||||
|
|
||||||
// Checks should generally be ordered in least computationally expensive to most.
|
// Checks should generally be ordered in least computationally expensive to most.
|
||||||
|
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
#nullable enable
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using LBPUnion.ProjectLighthouse.Administration.Reports;
|
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
|
||||||
using LBPUnion.ProjectLighthouse.Levels;
|
|
||||||
using LBPUnion.ProjectLighthouse.PlayerData;
|
|
||||||
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
|
|
||||||
using LBPUnion.ProjectLighthouse.PlayerData.Reviews;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Administration.Maintenance.MaintenanceJobs;
|
|
||||||
|
|
||||||
public class CleanupXmlInjection : IMaintenanceJob
|
|
||||||
{
|
|
||||||
private readonly Database database = new();
|
|
||||||
public string Name() => "Sanitize user content";
|
|
||||||
public string Description() => "Sanitizes all user-generated strings in levels, reviews, comments, users, and scores to prevent XML injection. Only needs to be run once.";
|
|
||||||
|
|
||||||
public async Task Run()
|
|
||||||
{
|
|
||||||
foreach (Slot slot in this.database.Slots) SanitizationHelper.SanitizeStringsInClass(slot);
|
|
||||||
|
|
||||||
foreach (Review review in this.database.Reviews) SanitizationHelper.SanitizeStringsInClass(review);
|
|
||||||
|
|
||||||
foreach (Comment comment in this.database.Comments) SanitizationHelper.SanitizeStringsInClass(comment);
|
|
||||||
|
|
||||||
foreach (Score score in this.database.Scores) SanitizationHelper.SanitizeStringsInClass(score);
|
|
||||||
|
|
||||||
foreach (User user in this.database.Users) SanitizationHelper.SanitizeStringsInClass(user);
|
|
||||||
|
|
||||||
foreach (Photo photo in this.database.Photos) SanitizationHelper.SanitizeStringsInClass(photo);
|
|
||||||
|
|
||||||
foreach (GriefReport report in this.database.Reports) SanitizationHelper.SanitizeStringsInClass(report);
|
|
||||||
|
|
||||||
await this.database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Administration.Maintenance.MigrationTasks;
|
||||||
|
|
||||||
|
public class CleanupXmlInjectionMigration : IMigrationTask
|
||||||
|
{
|
||||||
|
public string Name() => "Cleanup XML injections";
|
||||||
|
|
||||||
|
// Weird, but required. Thanks, hejlsberg.
|
||||||
|
async Task<bool> IMigrationTask.Run(Database database)
|
||||||
|
{
|
||||||
|
List<object> objsToBeSanitized = new();
|
||||||
|
|
||||||
|
// Store all the objects we need to sanitize in a list.
|
||||||
|
// The alternative here is to loop through every table, but thats a ton of code...
|
||||||
|
objsToBeSanitized.AddRange(database.Slots);
|
||||||
|
objsToBeSanitized.AddRange(database.Reviews);
|
||||||
|
objsToBeSanitized.AddRange(database.Comments);
|
||||||
|
objsToBeSanitized.AddRange(database.Scores);
|
||||||
|
objsToBeSanitized.AddRange(database.Users);
|
||||||
|
objsToBeSanitized.AddRange(database.Photos);
|
||||||
|
objsToBeSanitized.AddRange(database.Reports);
|
||||||
|
|
||||||
|
foreach (object obj in objsToBeSanitized) SanitizationHelper.SanitizeStringsInClass(obj);
|
||||||
|
|
||||||
|
await database.SaveChangesAsync();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Configuration.ConfigurationCategories;
|
||||||
|
|
||||||
|
public class CustomizationConfiguration
|
||||||
|
{
|
||||||
|
public string ServerName { get; set; } = "Project Lighthouse";
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ public class ServerConfiguration
|
||||||
// You can use an ObsoleteAttribute instead. Make sure you set it to error, though.
|
// You can use an ObsoleteAttribute instead. Make sure you set it to error, though.
|
||||||
//
|
//
|
||||||
// Thanks for listening~
|
// Thanks for listening~
|
||||||
public const int CurrentConfigVersion = 4;
|
public const int CurrentConfigVersion = 5;
|
||||||
|
|
||||||
#region Meta
|
#region Meta
|
||||||
|
|
||||||
|
@ -163,6 +163,9 @@ public class ServerConfiguration
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
// TODO: Find a way to properly remove config options
|
||||||
|
// YamlDotNet hates that and it's fucking annoying.
|
||||||
|
// This seriously sucks. /rant
|
||||||
[Obsolete("Obsolete. Use the Website/GameApi/Api listen URLS instead.")]
|
[Obsolete("Obsolete. Use the Website/GameApi/Api listen URLS instead.")]
|
||||||
public string ListenUrl { get; set; } = "http://localhost:10060";
|
public string ListenUrl { get; set; } = "http://localhost:10060";
|
||||||
|
|
||||||
|
@ -193,5 +196,5 @@ public class ServerConfiguration
|
||||||
public MailConfiguration Mail { get; set; } = new();
|
public MailConfiguration Mail { get; set; } = new();
|
||||||
public UserGeneratedContentLimitConfiguration UserGeneratedContentLimits { get; set; } = new();
|
public UserGeneratedContentLimitConfiguration UserGeneratedContentLimits { get; set; } = new();
|
||||||
public WebsiteConfiguration WebsiteConfiguration { get; set; } = new();
|
public WebsiteConfiguration WebsiteConfiguration { get; set; } = new();
|
||||||
|
public CustomizationConfiguration Customization { get; set; } = new();
|
||||||
}
|
}
|
|
@ -2,13 +2,12 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Configuration;
|
namespace LBPUnion.ProjectLighthouse.Configuration;
|
||||||
|
|
||||||
public static class ServerStatics
|
public static class ServerStatics
|
||||||
{
|
{
|
||||||
public const string ServerName = "ProjectLighthouse";
|
|
||||||
|
|
||||||
public const int PageSize = 20;
|
public const int PageSize = 20;
|
||||||
|
|
||||||
public static bool DbConnected {
|
public static bool DbConnected {
|
||||||
|
@ -25,11 +24,18 @@ public static class ServerStatics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: This needs to go at some point.
|
||||||
public static bool IsUnitTesting => AppDomain.CurrentDomain.GetAssemblies().Any(assembly => assembly.FullName!.StartsWith("xunit"));
|
public static bool IsUnitTesting => AppDomain.CurrentDomain.GetAssemblies().Any(assembly => assembly.FullName!.StartsWith("xunit"));
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
public static readonly bool IsDebug = true;
|
public const bool IsDebug = true;
|
||||||
#else
|
#else
|
||||||
public static readonly bool IsDebug = false;
|
public const bool IsDebug = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The servertype, determined on startup. Shouldn't be null unless very very early in startup.
|
||||||
|
/// </summary>
|
||||||
|
// The way of doing this is kinda weird, but it works.
|
||||||
|
public static ServerType ServerType;
|
||||||
}
|
}
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using LBPUnion.ProjectLighthouse.Administration;
|
||||||
using LBPUnion.ProjectLighthouse.Administration.Reports;
|
using LBPUnion.ProjectLighthouse.Administration.Reports;
|
||||||
using LBPUnion.ProjectLighthouse.Configuration;
|
using LBPUnion.ProjectLighthouse.Configuration;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
@ -21,6 +22,7 @@ namespace LBPUnion.ProjectLighthouse;
|
||||||
|
|
||||||
public class Database : DbContext
|
public class Database : DbContext
|
||||||
{
|
{
|
||||||
|
public DbSet<CompletedMigration> CompletedMigrations { get; set; }
|
||||||
public DbSet<User> Users { get; set; }
|
public DbSet<User> Users { get; set; }
|
||||||
public DbSet<Location> Locations { get; set; }
|
public DbSet<Location> Locations { get; set; }
|
||||||
public DbSet<Slot> Slots { get; set; }
|
public DbSet<Slot> Slots { get; set; }
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using LBPUnion.ProjectLighthouse.Levels;
|
using LBPUnion.ProjectLighthouse.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.PlayerData;
|
using LBPUnion.ProjectLighthouse.PlayerData;
|
||||||
using LBPUnion.ProjectLighthouse.PlayerData.Reviews;
|
using LBPUnion.ProjectLighthouse.PlayerData.Reviews;
|
||||||
|
@ -52,4 +55,7 @@ public static class DatabaseExtensions
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<bool> Has<T>(this IQueryable<T> queryable, Expression<Func<T, bool>> predicate) =>
|
||||||
|
await queryable.FirstOrDefaultAsync(predicate) != null;
|
||||||
}
|
}
|
|
@ -31,8 +31,8 @@ public static class VersionHelper
|
||||||
{
|
{
|
||||||
Logger.Error
|
Logger.Error
|
||||||
(
|
(
|
||||||
"Project Lighthouse was built incorrectly. Please make sure git is available when building. " +
|
"Project Lighthouse was built incorrectly. Please make sure git is available when building.",
|
||||||
"Because of this, you will not be notified of updates.",
|
// "Because of this, you will not be notified of updates.",
|
||||||
LogArea.Startup
|
LogArea.Startup
|
||||||
);
|
);
|
||||||
CommitHash = "invalid";
|
CommitHash = "invalid";
|
||||||
|
@ -54,7 +54,7 @@ public static class VersionHelper
|
||||||
|
|
||||||
public static string CommitHash { get; set; }
|
public static string CommitHash { get; set; }
|
||||||
public static string Branch { get; set; }
|
public static string Branch { get; set; }
|
||||||
public static string FullVersion => $"{ServerStatics.ServerName} {Branch}@{CommitHash} {Build}";
|
public static string FullVersion => $"Project Lighthouse {Branch}@{CommitHash} {Build} ({ServerConfiguration.Instance.Customization.ServerName})";
|
||||||
public static bool IsDirty => CommitHash.EndsWith("-dirty") || CommitsOutOfDate != 1 || CommitHash == "invalid" || Branch == "invalid";
|
public static bool IsDirty => CommitHash.EndsWith("-dirty") || CommitsOutOfDate != 1 || CommitHash == "invalid" || Branch == "invalid";
|
||||||
public static int CommitsOutOfDate { get; set; }
|
public static int CommitsOutOfDate { get; set; }
|
||||||
public static bool CanCheckForUpdates { get; set; }
|
public static bool CanCheckForUpdates { get; set; }
|
||||||
|
|
|
@ -11,7 +11,8 @@ public class ConsoleLogger : ILogger
|
||||||
|
|
||||||
foreach (string line in logLine.Message.Split('\n'))
|
foreach (string line in logLine.Message.Split('\n'))
|
||||||
{
|
{
|
||||||
// The following is scuffed. Beware~
|
// The following is scuffed.
|
||||||
|
// Beware~
|
||||||
|
|
||||||
// Write the level! [Success]
|
// Write the level! [Success]
|
||||||
Console.ForegroundColor = ConsoleColor.White;
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using LBPUnion.ProjectLighthouse.Configuration;
|
||||||
using LBPUnion.ProjectLighthouse.Files;
|
using LBPUnion.ProjectLighthouse.Files;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Logging.Loggers;
|
namespace LBPUnion.ProjectLighthouse.Logging.Loggers;
|
||||||
|
|
||||||
public class LighthouseFileLogger : ILogger
|
public class FileLogger : ILogger
|
||||||
{
|
{
|
||||||
private static readonly string logsDirectory = Path.Combine(Environment.CurrentDirectory, "logs");
|
private static readonly string logsDirectory = Path.Combine(Environment.CurrentDirectory, "logs");
|
||||||
|
|
||||||
|
@ -13,8 +13,8 @@ public class LighthouseFileLogger : ILogger
|
||||||
{
|
{
|
||||||
FileHelper.EnsureDirectoryCreated(logsDirectory);
|
FileHelper.EnsureDirectoryCreated(logsDirectory);
|
||||||
|
|
||||||
string contentFile = $"[{line.Level}] <{line.Trace.Name}:{line.Trace.Section}> {line.Message}\n";
|
string contentFile = $"[{ServerStatics.ServerType}] [{line.Level}] <{line.Trace.Name}:{line.Trace.Section}> {line.Message}\n";
|
||||||
string contentAll = $"[{line.Area}:{line.Level}] <{line.Trace.Name}:{line.Trace.Section}> {line.Message}\n";
|
string contentAll = $"[{ServerStatics.ServerType}] [{line.Area}:{line.Level}] <{line.Trace.Name}:{line.Trace.Section}> {line.Message}\n";
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
|
@ -16,7 +16,8 @@ namespace LBPUnion.ProjectLighthouse.Match.Rooms;
|
||||||
|
|
||||||
public class RoomHelper
|
public class RoomHelper
|
||||||
{
|
{
|
||||||
public static readonly StorableList<Room> Rooms = RoomStore.GetRooms();
|
public static readonly object RoomLock = new();
|
||||||
|
public static StorableList<Room> Rooms => RoomStore.GetRooms();
|
||||||
|
|
||||||
public static void StartCleanupThread()
|
public static void StartCleanupThread()
|
||||||
{
|
{
|
||||||
|
@ -162,7 +163,7 @@ public class RoomHelper
|
||||||
};
|
};
|
||||||
|
|
||||||
CleanupRooms(room.HostId, room);
|
CleanupRooms(room.HostId, room);
|
||||||
lock(Rooms) Rooms.Add(room);
|
lock(RoomLock) Rooms.Add(room);
|
||||||
Logger.Info($"Created room (id: {room.RoomId}) for host {room.HostId}", LogArea.Match);
|
Logger.Info($"Created room (id: {room.RoomId}) for host {room.HostId}", LogArea.Match);
|
||||||
|
|
||||||
return room;
|
return room;
|
||||||
|
@ -193,7 +194,7 @@ public class RoomHelper
|
||||||
[SuppressMessage("ReSharper", "InvertIf")]
|
[SuppressMessage("ReSharper", "InvertIf")]
|
||||||
public static void CleanupRooms(int? hostId = null, Room? newRoom = null, Database? database = null)
|
public static void CleanupRooms(int? hostId = null, Room? newRoom = null, Database? database = null)
|
||||||
{
|
{
|
||||||
lock(Rooms)
|
lock(RoomLock)
|
||||||
{
|
{
|
||||||
int roomCountBeforeCleanup = Rooms.Count();
|
int roomCountBeforeCleanup = Rooms.Count();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
using System;
|
||||||
|
using LBPUnion.ProjectLighthouse;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace ProjectLighthouse.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(Database))]
|
||||||
|
[Migration("20220610061641_AddCompletedMigrations")]
|
||||||
|
public class AddCompletedMigrations : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "CompletedMigrations",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
MigrationName = table.Column<string>(type: "varchar(255)", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
RanAt = table.Column<DateTime>(type: "datetime(6)", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_CompletedMigrations", x => x.MigrationName);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "CompletedMigrations");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
// <auto-generated />
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
using LBPUnion.ProjectLighthouse;
|
using LBPUnion.ProjectLighthouse;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
@ -18,6 +19,19 @@ namespace ProjectLighthouse.Migrations
|
||||||
.HasAnnotation("ProductVersion", "6.0.5")
|
.HasAnnotation("ProductVersion", "6.0.5")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Administration.CompletedMigration", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("MigrationName")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("RanAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.HasKey("MigrationName");
|
||||||
|
|
||||||
|
b.ToTable("CompletedMigrations");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Administration.Reports.GriefReport", b =>
|
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Administration.Reports.GriefReport", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("ReportId")
|
b.Property<int>("ReportId")
|
||||||
|
@ -581,15 +595,16 @@ namespace ProjectLighthouse.Migrations
|
||||||
b.Property<int>("AdminGrantedSlots")
|
b.Property<int>("AdminGrantedSlots")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("Banned")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
b.Property<string>("BannedReason")
|
b.Property<string>("BannedReason")
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<string>("Biography")
|
b.Property<string>("Biography")
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<string>("BooHash")
|
b.Property<string>("BooHash")
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<string>("EmailAddress")
|
b.Property<string>("EmailAddress")
|
||||||
|
@ -602,48 +617,39 @@ namespace ProjectLighthouse.Migrations
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<string>("IconHash")
|
b.Property<string>("IconHash")
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<bool>("IsAdmin")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
b.Property<int>("LocationId")
|
b.Property<int>("LocationId")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<string>("MehHash")
|
b.Property<string>("MehHash")
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<string>("Password")
|
b.Property<string>("Password")
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<bool>("PasswordResetRequired")
|
b.Property<bool>("PasswordResetRequired")
|
||||||
.HasColumnType("tinyint(1)");
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
b.Property<int>("PermissionLevel")
|
|
||||||
.HasColumnType("int");
|
|
||||||
|
|
||||||
b.Property<string>("Pins")
|
b.Property<string>("Pins")
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<string>("PlanetHashLBP2")
|
b.Property<string>("PlanetHashLBP2")
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<string>("PlanetHashLBP3")
|
b.Property<string>("PlanetHashLBP3")
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<string>("PlanetHashLBPVita")
|
b.Property<string>("PlanetHashLBPVita")
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<string>("Username")
|
b.Property<string>("Username")
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<string>("YayHash")
|
b.Property<string>("YayHash")
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.HasKey("UserId");
|
b.HasKey("UserId");
|
||||||
|
|
|
@ -15,9 +15,12 @@ public class LoginResult
|
||||||
public string AuthTicket { get; set; }
|
public string AuthTicket { get; set; }
|
||||||
|
|
||||||
[XmlElement("lbpEnvVer")]
|
[XmlElement("lbpEnvVer")]
|
||||||
public string LbpEnvVer { get; set; }
|
public string ServerBrand { get; set; }
|
||||||
|
|
||||||
public string Serialize()
|
public string Serialize()
|
||||||
=> LbpSerializer.Elements
|
=> LbpSerializer.Elements
|
||||||
(new KeyValuePair<string, object>("authTicket", this.AuthTicket), new KeyValuePair<string, object>("lbpEnvVer", this.LbpEnvVer));
|
(
|
||||||
|
new KeyValuePair<string, object>("authTicket", this.AuthTicket),
|
||||||
|
new KeyValuePair<string, object>("lbpEnvVer", this.ServerBrand)
|
||||||
|
);
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||||
<PackageReference Include="DDSReader" Version="1.0.8-pre" />
|
<PackageReference Include="DDSReader" Version="1.0.8-pre" />
|
||||||
<PackageReference Include="Discord.Net.Webhook" Version="3.6.1" />
|
<PackageReference Include="Discord.Net.Webhook" Version="3.7.2" />
|
||||||
<PackageReference Include="InfluxDB.Client" Version="4.2.0" />
|
<PackageReference Include="InfluxDB.Client" Version="4.2.0" />
|
||||||
<PackageReference Include="JetBrains.Annotations" Version="2022.1.0" />
|
<PackageReference Include="JetBrains.Annotations" Version="2022.1.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="6.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="6.0.5" />
|
||||||
|
@ -50,10 +50,6 @@
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Remove="Migrations\20220522192158_SwitchToPermissionLevels.Designer.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
||||||
<Exec Command="git describe --long --always --dirty --exclude=\* --abbrev=8 > "$(ProjectDir)/gitVersion.txt"" />
|
<Exec Command="git describe --long --always --dirty --exclude=\* --abbrev=8 > "$(ProjectDir)/gitVersion.txt"" />
|
||||||
<Exec Command="git branch --show-current > "$(ProjectDir)/gitBranch.txt"" />
|
<Exec Command="git branch --show-current > "$(ProjectDir)/gitBranch.txt"" />
|
||||||
|
|
|
@ -20,7 +20,6 @@ public class DebugWarmupLifetime : IHostLifetime
|
||||||
private CancellationTokenRegistration applicationStartedRegistration;
|
private CancellationTokenRegistration applicationStartedRegistration;
|
||||||
|
|
||||||
private readonly ConsoleLifetime consoleLifetime;
|
private readonly ConsoleLifetime consoleLifetime;
|
||||||
public static ServerType ServerType;
|
|
||||||
|
|
||||||
public DebugWarmupLifetime
|
public DebugWarmupLifetime
|
||||||
(
|
(
|
||||||
|
@ -39,7 +38,7 @@ public class DebugWarmupLifetime : IHostLifetime
|
||||||
{
|
{
|
||||||
using HttpClient client = new();
|
using HttpClient client = new();
|
||||||
|
|
||||||
string url = ServerType switch
|
string url = ServerStatics.ServerType switch
|
||||||
{
|
{
|
||||||
ServerType.GameServer => ServerConfiguration.Instance.GameApiListenUrl,
|
ServerType.GameServer => ServerConfiguration.Instance.GameApiListenUrl,
|
||||||
ServerType.Website => ServerConfiguration.Instance.WebsiteListenUrl,
|
ServerType.Website => ServerConfiguration.Instance.WebsiteListenUrl,
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using LBPUnion.ProjectLighthouse.Administration;
|
||||||
using LBPUnion.ProjectLighthouse.Administration.Maintenance;
|
using LBPUnion.ProjectLighthouse.Administration.Maintenance;
|
||||||
using LBPUnion.ProjectLighthouse.Configuration;
|
using LBPUnion.ProjectLighthouse.Configuration;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
@ -9,6 +11,7 @@ using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Logging.Loggers;
|
using LBPUnion.ProjectLighthouse.Logging.Loggers;
|
||||||
using LBPUnion.ProjectLighthouse.Match.Rooms;
|
using LBPUnion.ProjectLighthouse.Match.Rooms;
|
||||||
|
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
|
||||||
using LBPUnion.ProjectLighthouse.Startup;
|
using LBPUnion.ProjectLighthouse.Startup;
|
||||||
using LBPUnion.ProjectLighthouse.StorableLists;
|
using LBPUnion.ProjectLighthouse.StorableLists;
|
||||||
using LBPUnion.ProjectLighthouse.Types;
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
|
@ -24,18 +27,16 @@ public static class StartupTasks
|
||||||
Stopwatch stopwatch = new();
|
Stopwatch stopwatch = new();
|
||||||
stopwatch.Start();
|
stopwatch.Start();
|
||||||
|
|
||||||
#if DEBUG
|
ServerStatics.ServerType = serverType;
|
||||||
DebugWarmupLifetime.ServerType = serverType;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Setup logging
|
// Setup logging
|
||||||
Logger.Instance.AddLogger(new ConsoleLogger());
|
Logger.Instance.AddLogger(new ConsoleLogger());
|
||||||
Logger.Instance.AddLogger(new LighthouseFileLogger());
|
Logger.Instance.AddLogger(new FileLogger());
|
||||||
|
|
||||||
Logger.Info($"Welcome to the Project Lighthouse {serverType.ToString()}!", LogArea.Startup);
|
Logger.Info($"Welcome to the Project Lighthouse {serverType.ToString()}!", LogArea.Startup);
|
||||||
Logger.Info($"You are running version {VersionHelper.FullVersion}", LogArea.Startup);
|
Logger.Info($"You are running version {VersionHelper.FullVersion}", LogArea.Startup);
|
||||||
|
|
||||||
// Referencing ServerSettings.Instance here loads the config, see ServerSettings.cs for more information
|
// Referencing ServerConfiguration.Instance here loads the config, see ServerConfiguration.cs for more information
|
||||||
Logger.Success("Loaded config file version " + ServerConfiguration.Instance.ConfigVersion, LogArea.Startup);
|
Logger.Success("Loaded config file version " + ServerConfiguration.Instance.ConfigVersion, LogArea.Startup);
|
||||||
|
|
||||||
Logger.Info("Connecting to the database...", LogArea.Startup);
|
Logger.Info("Connecting to the database...", LogArea.Startup);
|
||||||
|
@ -46,13 +47,15 @@ public static class StartupTasks
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.Success("Connected!", LogArea.Startup);
|
Logger.Success("Connected to the database!", LogArea.Startup);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dbConnected) Environment.Exit(1);
|
if (!dbConnected) Environment.Exit(1);
|
||||||
using Database database = new();
|
using Database database = new();
|
||||||
|
|
||||||
Logger.Info("Migrating database...", LogArea.Database);
|
#if !DEBUG
|
||||||
|
if(serverType == ServerType.GameServer)
|
||||||
|
#endif
|
||||||
migrateDatabase(database);
|
migrateDatabase(database);
|
||||||
|
|
||||||
if (ServerConfiguration.Instance.InfluxDB.InfluxEnabled)
|
if (ServerConfiguration.Instance.InfluxDB.InfluxEnabled)
|
||||||
|
@ -84,24 +87,65 @@ public static class StartupTasks
|
||||||
FileHelper.ConvertAllTexturesToPng();
|
FileHelper.ConvertAllTexturesToPng();
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Info("Starting room cleanup thread...", LogArea.Startup);
|
|
||||||
RoomHelper.StartCleanupThread();
|
|
||||||
|
|
||||||
Logger.Info("Initializing Redis...", LogArea.Startup);
|
Logger.Info("Initializing Redis...", LogArea.Startup);
|
||||||
RedisDatabase.Initialize().Wait();
|
RedisDatabase.Initialize().Wait();
|
||||||
|
|
||||||
|
if (serverType == ServerType.GameServer)
|
||||||
|
{
|
||||||
|
Logger.Info("Starting room cleanup thread...", LogArea.Startup);
|
||||||
|
RoomHelper.StartCleanupThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create admin user if no users exist
|
||||||
|
if (serverType == ServerType.Website && database.Users.CountAsync().Result == 0)
|
||||||
|
{
|
||||||
|
const string passwordClear = "lighthouse";
|
||||||
|
string password = CryptoHelper.BCryptHash(CryptoHelper.Sha256Hash(passwordClear));
|
||||||
|
|
||||||
|
User admin = database.CreateUser("admin", password).Result;
|
||||||
|
admin.IsAdmin = true;
|
||||||
|
admin.PasswordResetRequired = true;
|
||||||
|
|
||||||
|
database.SaveChanges();
|
||||||
|
|
||||||
|
Logger.Success("No users were found, so an admin user was created. " +
|
||||||
|
$"The username is 'admin' and the password is '{passwordClear}'.", LogArea.Startup);
|
||||||
|
}
|
||||||
|
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
Logger.Success($"Ready! Startup took {stopwatch.ElapsedMilliseconds}ms. Passing off control to ASP.NET...", LogArea.Startup);
|
Logger.Success($"Ready! Startup took {stopwatch.ElapsedMilliseconds}ms. Passing off control to ASP.NET...", LogArea.Startup);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void migrateDatabase(Database database)
|
private static void migrateDatabase(Database database)
|
||||||
{
|
{
|
||||||
|
Logger.Info("Migrating database...", LogArea.Database);
|
||||||
|
Stopwatch totalStopwatch = new();
|
||||||
Stopwatch stopwatch = new();
|
Stopwatch stopwatch = new();
|
||||||
|
totalStopwatch.Start();
|
||||||
stopwatch.Start();
|
stopwatch.Start();
|
||||||
|
|
||||||
database.Database.MigrateAsync().Wait();
|
database.Database.MigrateAsync().Wait();
|
||||||
|
stopwatch.Stop();
|
||||||
|
Logger.Success($"Structure migration took {stopwatch.ElapsedMilliseconds}ms.", LogArea.Database);
|
||||||
|
|
||||||
|
stopwatch.Reset();
|
||||||
|
stopwatch.Start();
|
||||||
|
|
||||||
|
List<CompletedMigration> completedMigrations = database.CompletedMigrations.ToList();
|
||||||
|
List<IMigrationTask> migrationsToRun = MaintenanceHelper.MigrationTasks
|
||||||
|
.Where(migrationTask => !completedMigrations
|
||||||
|
.Select(m => m.MigrationName)
|
||||||
|
.Contains(migrationTask.GetType().Name)
|
||||||
|
).ToList();
|
||||||
|
|
||||||
|
foreach (IMigrationTask migrationTask in migrationsToRun)
|
||||||
|
{
|
||||||
|
MaintenanceHelper.RunMigration(migrationTask, database).Wait();
|
||||||
|
}
|
||||||
|
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
Logger.Success($"Migration took {stopwatch.ElapsedMilliseconds}ms.", LogArea.Database);
|
totalStopwatch.Stop();
|
||||||
|
Logger.Success($"Extra migration tasks took {stopwatch.ElapsedMilliseconds}ms.", LogArea.Database);
|
||||||
|
Logger.Success($"Total migration took {totalStopwatch.ElapsedMilliseconds}ms.", LogArea.Database);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -39,8 +39,7 @@ public static class RedisDatabase
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await connection.RecreateIndexAsync(typeof(Room));
|
await createIndexes(connection);
|
||||||
await connection.RecreateIndexAsync(typeof(UserFriendData));
|
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
|
@ -52,6 +51,20 @@ public static class RedisDatabase
|
||||||
Logger.Success("Initialized Redis.", LogArea.Redis);
|
Logger.Success("Initialized Redis.", LogArea.Redis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task FlushAll()
|
||||||
|
{
|
||||||
|
IRedisConnection connection = getConnection();
|
||||||
|
await connection.ExecuteAsync("FLUSHALL");
|
||||||
|
|
||||||
|
await createIndexes(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task createIndexes(IRedisConnection connection)
|
||||||
|
{
|
||||||
|
await connection.RecreateIndexAsync(typeof(Room));
|
||||||
|
await connection.RecreateIndexAsync(typeof(UserFriendData));
|
||||||
|
}
|
||||||
|
|
||||||
private static IRedisConnection getConnection()
|
private static IRedisConnection getConnection()
|
||||||
{
|
{
|
||||||
Logger.Debug("Getting a Redis connection", LogArea.Redis);
|
Logger.Debug("Getting a Redis connection", LogArea.Redis);
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Developer script to create EntityFramework database migrations
|
||||||
|
#
|
||||||
|
# $1: Name of the migration, e.g. SwitchToPermissionLevels
|
||||||
|
# Invoked manually
|
||||||
|
|
||||||
export LIGHTHOUSE_DB_CONNECTION_STRING='server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse'
|
export LIGHTHOUSE_DB_CONNECTION_STRING='server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse'
|
||||||
dotnet ef migrations add "$1" --project ../ProjectLighthouse
|
dotnet ef migrations add "$1" --project ../ProjectLighthouse
|
Loading…
Add table
Add a link
Reference in a new issue