mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-04-19 19:14:51 +00:00
Implement property dependency injection for the website (#806)
* Remove most non DI usages of DbContext * Optimize website queries and refactor startup to use top level statements * Remove unused functions in UserEntity and SlotEntity * Optimize LBP1 LevelTags
This commit is contained in:
parent
727dd4e903
commit
e43397ac6a
47 changed files with 333 additions and 430 deletions
|
@ -1,36 +1,22 @@
|
|||
using LBPUnion.ProjectLighthouse;
|
||||
using LBPUnion.ProjectLighthouse.Configuration;
|
||||
using LBPUnion.ProjectLighthouse.Logging.Loggers.AspNet;
|
||||
using LBPUnion.ProjectLighthouse.Servers.API.Startup;
|
||||
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Servers.API;
|
||||
await StartupTasks.Run(ServerType.Api);
|
||||
|
||||
public static class Program
|
||||
IHostBuilder builder = Host.CreateDefaultBuilder();
|
||||
builder.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
StartupTasks.Run(args, ServerType.Api);
|
||||
webBuilder.UseStartup<ApiStartup>();
|
||||
webBuilder.UseUrls(ServerConfiguration.Instance.ApiListenUrl);
|
||||
});
|
||||
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
builder.ConfigureLogging(logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.AddProvider(new AspNetToLighthouseLoggerProvider());
|
||||
});
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args)
|
||||
=> Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults
|
||||
(
|
||||
webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<ApiStartup>();
|
||||
webBuilder.UseUrls(ServerConfiguration.Instance.ApiListenUrl);
|
||||
}
|
||||
)
|
||||
.ConfigureLogging
|
||||
(
|
||||
logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, AspNetToLighthouseLoggerProvider>());
|
||||
}
|
||||
);
|
||||
}
|
||||
await builder.Build().RunAsync();
|
|
@ -68,7 +68,7 @@ public struct ApiSlot
|
|||
PlaysUnique = slot.PlaysUnique,
|
||||
PlaysComplete = slot.PlaysComplete,
|
||||
CommentsEnabled = slot.CommentsEnabled,
|
||||
AverageRating = slot.RatingLBP1,
|
||||
AverageRating = context.RatedLevels.Where(r => r.SlotId == slot.SlotId).Average(r => (double?)r.RatingLBP1) ?? 3.0,
|
||||
LevelType = slot.LevelType,
|
||||
};
|
||||
}
|
|
@ -98,17 +98,22 @@ public class MatchController : ControllerBase
|
|||
case FindBestRoom diveInData when MatchHelper.UserLocations.Count > 1:
|
||||
#endif
|
||||
{
|
||||
FindBestRoomResponse? response = RoomHelper.FindBestRoom
|
||||
(user, token.GameVersion, diveInData.RoomSlot, token.Platform, token.UserLocation);
|
||||
FindBestRoomResponse? response = RoomHelper.FindBestRoom(this.database,
|
||||
user,
|
||||
token.GameVersion,
|
||||
diveInData.RoomSlot,
|
||||
token.Platform,
|
||||
token.UserLocation);
|
||||
|
||||
if (response == null) return this.NotFound();
|
||||
|
||||
string serialized = JsonSerializer.Serialize(response, typeof(FindBestRoomResponse));
|
||||
foreach (Player player in response.Players) MatchHelper.AddUserRecentlyDivedIn(user.UserId, player.User.UserId);
|
||||
foreach (Player player in response.Players)
|
||||
MatchHelper.AddUserRecentlyDivedIn(user.UserId, player.User.UserId);
|
||||
|
||||
return this.Ok($"[{{\"StatusCode\":200}},{serialized}]");
|
||||
}
|
||||
case CreateRoom createRoom when MatchHelper.UserLocations.Count >= 1:
|
||||
case CreateRoom createRoom when !MatchHelper.UserLocations.IsEmpty:
|
||||
{
|
||||
List<int> users = new();
|
||||
foreach (string playerUsername in createRoom.Players)
|
||||
|
@ -139,9 +144,8 @@ public class MatchController : ControllerBase
|
|||
}
|
||||
|
||||
room.PlayerIds = users.Select(u => u.UserId).ToList();
|
||||
await RoomHelper.CleanupRooms(null, room);
|
||||
await RoomHelper.CleanupRooms(this.database, null, room);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,17 +34,17 @@ public class PhotosController : ControllerBase
|
|||
[HttpPost("uploadPhoto")]
|
||||
public async Task<IActionResult> UploadPhoto()
|
||||
{
|
||||
UserEntity? user = await this.database.UserFromGameToken(this.GetToken());
|
||||
if (user == null) return this.Forbid();
|
||||
GameTokenEntity token = this.GetToken();
|
||||
|
||||
if (user.GetUploadedPhotoCount(this.database) >= ServerConfiguration.Instance.UserGeneratedContentLimits.PhotosQuota) return this.BadRequest();
|
||||
int photoCount = await this.database.Photos.CountAsync(p => p.CreatorId == token.UserId);
|
||||
if (photoCount >= ServerConfiguration.Instance.UserGeneratedContentLimits.PhotosQuota) return this.BadRequest();
|
||||
|
||||
GamePhoto? photo = await this.DeserializeBody<GamePhoto>();
|
||||
if (photo == null) return this.BadRequest();
|
||||
|
||||
foreach (PhotoEntity p in this.database.Photos.Where(p => p.CreatorId == user.UserId))
|
||||
foreach (PhotoEntity p in this.database.Photos.Where(p => p.CreatorId == token.UserId))
|
||||
{
|
||||
if (p.LargeHash == photo.LargeHash) return this.Ok(); // photo already uplaoded
|
||||
if (p.LargeHash == photo.LargeHash) return this.Ok(); // photo already uploaded
|
||||
if (p.MediumHash == photo.MediumHash) return this.Ok();
|
||||
if (p.SmallHash == photo.SmallHash) return this.Ok();
|
||||
if (p.PlanHash == photo.PlanHash) return this.Ok();
|
||||
|
@ -52,8 +52,7 @@ public class PhotosController : ControllerBase
|
|||
|
||||
PhotoEntity photoEntity = new()
|
||||
{
|
||||
CreatorId = user.UserId,
|
||||
Creator = user,
|
||||
CreatorId = token.UserId,
|
||||
SmallHash = photo.SmallHash,
|
||||
MediumHash = photo.MediumHash,
|
||||
LargeHash = photo.LargeHash,
|
||||
|
@ -145,12 +144,14 @@ public class PhotosController : ControllerBase
|
|||
|
||||
await this.database.SaveChangesAsync();
|
||||
|
||||
string username = await this.database.UsernameFromGameToken(token);
|
||||
|
||||
await WebhookHelper.SendWebhook
|
||||
(
|
||||
new EmbedBuilder
|
||||
{
|
||||
Title = "New photo uploaded!",
|
||||
Description = $"{user.Username} uploaded a new photo.",
|
||||
Description = $"{username} uploaded a new photo.",
|
||||
ImageUrl = $"{ServerConfiguration.Instance.ExternalUrl}/gameAssets/{photo.LargeHash}",
|
||||
Color = WebhookHelper.GetEmbedColor(),
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
|||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||
using LBPUnion.ProjectLighthouse.Types.Matchmaking.Rooms;
|
||||
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||
|
|
|
@ -1,36 +1,22 @@
|
|||
using LBPUnion.ProjectLighthouse;
|
||||
using LBPUnion.ProjectLighthouse.Configuration;
|
||||
using LBPUnion.ProjectLighthouse.Logging.Loggers.AspNet;
|
||||
using LBPUnion.ProjectLighthouse.Servers.GameServer.Startup;
|
||||
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer;
|
||||
await StartupTasks.Run(ServerType.GameServer);
|
||||
|
||||
public static class Program
|
||||
IHostBuilder builder = Host.CreateDefaultBuilder();
|
||||
builder.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
StartupTasks.Run(args, ServerType.GameServer);
|
||||
webBuilder.UseStartup<GameServerStartup>();
|
||||
webBuilder.UseUrls(ServerConfiguration.Instance.GameApiListenUrl);
|
||||
});
|
||||
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
builder.ConfigureLogging(logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.AddProvider(new AspNetToLighthouseLoggerProvider());
|
||||
});
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args)
|
||||
=> Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults
|
||||
(
|
||||
webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<GameServerStartup>();
|
||||
webBuilder.UseUrls(ServerConfiguration.Instance.GameApiListenUrl);
|
||||
}
|
||||
)
|
||||
.ConfigureLogging
|
||||
(
|
||||
logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, AspNetToLighthouseLoggerProvider>());
|
||||
}
|
||||
);
|
||||
}
|
||||
await builder.Build().RunAsync();
|
|
@ -113,6 +113,5 @@ public class GameServerStartup
|
|||
app.UseAuthorization();
|
||||
|
||||
app.UseEndpoints(endpoints => endpoints.MapControllers());
|
||||
app.UseEndpoints(endpoints => endpoints.MapRazorPages());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,14 +8,12 @@ using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
|
|||
using LBPUnion.ProjectLighthouse.Servers.Website.Types;
|
||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Types.Maintenance;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.Admin;
|
||||
|
||||
public class AdminPanelPage : BaseLayout
|
||||
{
|
||||
public List<ICommand> Commands = MaintenanceHelper.Commands;
|
||||
public AdminPanelPage(DatabaseContext database) : base(database)
|
||||
{ }
|
||||
|
||||
|
@ -40,7 +38,7 @@ public class AdminPanelPage : BaseLayout
|
|||
args = command + " " + args;
|
||||
string[] split = args.Split(" ");
|
||||
|
||||
List<LogLine> runCommand = await MaintenanceHelper.RunCommand(split);
|
||||
List<LogLine> runCommand = await MaintenanceHelper.RunCommand(this.HttpContext.RequestServices, split);
|
||||
return this.Redirect($"~/admin?log={CryptoHelper.ToBase64(runCommand.ToLogString())}");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
@page "/debug/roomVisualizer"
|
||||
@using LBPUnion.ProjectLighthouse.Database
|
||||
@using LBPUnion.ProjectLighthouse.Extensions
|
||||
@using LBPUnion.ProjectLighthouse.Helpers
|
||||
@using LBPUnion.ProjectLighthouse.Types.Entities.Profile
|
||||
@using LBPUnion.ProjectLighthouse.Types.Matchmaking.Rooms
|
||||
@using LBPUnion.ProjectLighthouse.Types.Users
|
||||
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.Debug.RoomVisualizerPage
|
||||
@inject DatabaseContext Database
|
||||
|
||||
@{
|
||||
Layout = "Layouts/BaseLayout";
|
||||
|
@ -59,7 +61,7 @@
|
|||
#nullable enable
|
||||
if (version == GameVersion.LittleBigPlanet1 || version == GameVersion.LittleBigPlanetPSP || version == GameVersion.Unknown) continue;
|
||||
|
||||
FindBestRoomResponse? response = RoomHelper.FindBestRoom(null, version, null, null, null);
|
||||
FindBestRoomResponse? response = RoomHelper.FindBestRoom(Database, null, version, null, null, null);
|
||||
string text = response == null ? "No room found." : "Room " + response.RoomId;
|
||||
|
||||
<p><b>Best room for @version.ToPrettyString()</b>: @text</p>
|
||||
|
|
|
@ -29,7 +29,7 @@ public class BaseLayout : PageModel
|
|||
public BaseLayout(DatabaseContext database)
|
||||
{
|
||||
this.Database = database;
|
||||
|
||||
|
||||
this.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderUsers, "/users/0", "user friends"));
|
||||
this.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderPhotos, "/photos/0", "camera"));
|
||||
this.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderSlots, "/slots/0", "globe americas"));
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
@using System.Web
|
||||
@using System.IO
|
||||
@using LBPUnion.ProjectLighthouse.Database
|
||||
@using LBPUnion.ProjectLighthouse.Localization
|
||||
@using LBPUnion.ProjectLighthouse.Servers.Website.Extensions
|
||||
@using LBPUnion.ProjectLighthouse.Types.Entities.Interaction
|
||||
@using LBPUnion.ProjectLighthouse.Types.Entities.Profile
|
||||
@inject DatabaseContext Database
|
||||
|
||||
@{
|
||||
string language = (string?)ViewData["Language"] ?? LocalizationManager.DefaultLang;
|
||||
|
@ -50,7 +52,7 @@
|
|||
int yourThumb = commentAndReaction.Value?.Rating ?? 0;
|
||||
DateTimeOffset timestamp = DateTimeOffset.FromUnixTimeSeconds(comment.Timestamp / 1000).ToLocalTime();
|
||||
StringWriter messageWriter = new();
|
||||
HttpUtility.HtmlDecode(comment.GetCommentMessage(), messageWriter);
|
||||
HttpUtility.HtmlDecode(comment.GetCommentMessage(Database), messageWriter);
|
||||
|
||||
string decodedMessage = messageWriter.ToString();
|
||||
string? url = Url.RouteUrl(ViewContext.RouteData.Values);
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
@using LBPUnion.ProjectLighthouse.Database
|
||||
@using LBPUnion.ProjectLighthouse.Localization
|
||||
@using LBPUnion.ProjectLighthouse.Servers.Website.Extensions
|
||||
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.UserEntity
|
||||
@using LBPUnion.ProjectLighthouse.Types.Entities.Profile
|
||||
@model UserEntity
|
||||
@inject DatabaseContext Database
|
||||
|
||||
@{
|
||||
string language = (string?)ViewData["Language"] ?? LocalizationManager.DefaultLang;
|
||||
string timeZone = (string?)ViewData["TimeZone"] ?? TimeZoneInfo.Local.Id;
|
||||
bool includeStatus = (bool?)ViewData["IncludeStatus"] ?? false;
|
||||
await using DatabaseContext database = DatabaseContext.CreateNewInstance();
|
||||
string userStatus = includeStatus ? Model.GetStatus(database).ToTranslatedString(language, timeZone) : "";
|
||||
string userStatus = includeStatus ? Model.GetStatus(Database).ToTranslatedString(language, timeZone) : "";
|
||||
}
|
||||
|
||||
<a href="/user/@Model.UserId" title="@userStatus" class="user-link">
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
@using LBPUnion.ProjectLighthouse.Types.Entities.Profile
|
||||
@using LBPUnion.ProjectLighthouse.Types.Moderation.Cases
|
||||
@model LBPUnion.ProjectLighthouse.Types.Entities.Moderation.ModerationCaseEntity
|
||||
@inject DatabaseContext Database
|
||||
|
||||
@{
|
||||
DatabaseContext database = DatabaseContext.CreateNewInstance();
|
||||
string color = "blue";
|
||||
|
||||
string timeZone = (string?)ViewData["TimeZone"] ?? TimeZoneInfo.Local.Id;
|
||||
|
@ -70,7 +70,7 @@
|
|||
|
||||
@if (Model.Type.AffectsLevel())
|
||||
{
|
||||
SlotEntity? slot = await Model.GetSlotAsync(database);
|
||||
SlotEntity? slot = await Model.GetSlotAsync(Database);
|
||||
if (slot != null)
|
||||
{
|
||||
<p><strong>Affected level:</strong> <a href="/slot/@slot.SlotId">@slot.Name</a></p>
|
||||
|
@ -78,7 +78,7 @@
|
|||
}
|
||||
else if (Model.Type.AffectsUser())
|
||||
{
|
||||
UserEntity? user = await Model.GetUserAsync(database);
|
||||
UserEntity? user = await Model.GetUserAsync(Database);
|
||||
if (user != null)
|
||||
{
|
||||
<p><strong>Affected user:</strong> <a href="/user/@user.UserId">@user.Username</a></p>
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
@using LBPUnion.ProjectLighthouse.Types.Users
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@model LBPUnion.ProjectLighthouse.Types.Entities.Level.SlotEntity
|
||||
@inject DatabaseContext Database
|
||||
|
||||
@{
|
||||
UserEntity? user = (UserEntity?)ViewData["User"];
|
||||
|
||||
await using DatabaseContext database = DatabaseContext.CreateNewInstance();
|
||||
|
||||
string slotName = HttpUtility.HtmlDecode(string.IsNullOrEmpty(Model!.Name) ? "Unnamed Level" : Model.Name);
|
||||
|
||||
bool isMobile = (bool?)ViewData["IsMobile"] ?? false;
|
||||
|
@ -26,8 +25,8 @@
|
|||
|
||||
if (user != null)
|
||||
{
|
||||
isQueued = await database.QueuedLevels.FirstOrDefaultAsync(h => h.SlotId == Model.SlotId && h.UserId == user.UserId) != null;
|
||||
isHearted = await database.HeartedLevels.FirstOrDefaultAsync(h => h.SlotId == Model.SlotId && h.UserId == user.UserId) != null;
|
||||
isQueued = await Database.QueuedLevels.AnyAsync(h => h.SlotId == Model.SlotId && h.UserId == user.UserId);
|
||||
isHearted = await Database.HeartedLevels.AnyAsync(h => h.SlotId == Model.SlotId && h.UserId == user.UserId);
|
||||
}
|
||||
|
||||
string callbackUrl = (string)ViewData["CallbackUrl"]!;
|
||||
|
@ -81,15 +80,24 @@
|
|||
}
|
||||
|
||||
<div class="cardStatsUnderTitle">
|
||||
<i class="pink heart icon" title="Hearts"></i> <span>@Model.Hearts</span>
|
||||
@{
|
||||
var slotStats = await Database.Slots.Where(s => s.SlotId == Model.SlotId).Select(_ => new
|
||||
{
|
||||
HeartCount = Database.HeartedLevels.Count(h => h.SlotId == Model.SlotId),
|
||||
ThumbsUp = Database.RatedLevels.Count(r => r.SlotId == Model.SlotId && r.Rating == 1),
|
||||
ThumbsDown = Database.RatedLevels.Count(r => r.SlotId == Model.SlotId && r.Rating == -1),
|
||||
RatingLbp1 = Database.RatedLevels.Where(r => r.SlotId == Model.SlotId).Average(r => (double?)r.RatingLBP1) ?? 3.0,
|
||||
}).OrderBy(_ => 1).FirstAsync();
|
||||
}
|
||||
<i class="pink heart icon" title="Hearts"></i> <span>@slotStats.HeartCount</span>
|
||||
<i class="blue play icon" title="Plays"></i> <span>@Model.PlaysUnique</span>
|
||||
<i class="green thumbs up icon" title="Yays"></i> <span>@Model.Thumbsup</span>
|
||||
<i class="red thumbs down icon" title="Boos"></i> <span>@Model.Thumbsdown</span>
|
||||
<i class="green thumbs up icon" title="Yays"></i> <span>@slotStats.ThumbsUp</span>
|
||||
<i class="red thumbs down icon" title="Boos"></i> <span>@slotStats.ThumbsDown</span>
|
||||
|
||||
@if (Model.GameVersion == GameVersion.LittleBigPlanet1)
|
||||
{
|
||||
<i class="yellow star icon" title="Star Rating"></i>
|
||||
<span>@(Math.Round(Model.RatingLBP1 * 10) / 10)</span>
|
||||
<span>@(Math.Round(slotStats.RatingLbp1 * 10) / 10)</span>
|
||||
}
|
||||
</div>
|
||||
@if (Model.Creator != null)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
@using LBPUnion.ProjectLighthouse.Database
|
||||
@using LBPUnion.ProjectLighthouse.Localization
|
||||
@using LBPUnion.ProjectLighthouse.Servers.Website.Extensions;
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.UserEntity
|
||||
@inject DatabaseContext Database
|
||||
|
||||
@{
|
||||
bool showLink = (bool?)ViewData["ShowLink"] ?? false;
|
||||
|
@ -42,21 +44,22 @@
|
|||
</h1>
|
||||
}
|
||||
@{
|
||||
await using DatabaseContext context = DatabaseContext.CreateNewInstance();
|
||||
|
||||
int hearts = Model.GetHeartCount(context);
|
||||
int comments = Model.GetCommentCount(context);
|
||||
int levels = Model.GetUsedSlotCount(context);
|
||||
int photos = Model.GetUploadedPhotoCount(context);
|
||||
var stats = await Database.Users.Where(u => u.UserId == Model.UserId).Select(_ => new
|
||||
{
|
||||
HeartCount = Database.HeartedProfiles.Count(hp => hp.HeartedUserId == Model.UserId),
|
||||
CommentCount = Database.Comments.Count(c => c.PosterUserId == Model.UserId),
|
||||
LevelCount = Database.Slots.Count(s => s.CreatorId == Model.UserId),
|
||||
PhotoCount = Database.Photos.Count(p => p.CreatorId == Model.UserId),
|
||||
}).OrderBy(_ => 1).FirstAsync();
|
||||
}
|
||||
<span>
|
||||
<i>@Model.GetStatus(context).ToTranslatedString(language, timeZone)</i>
|
||||
<i>@Model.GetStatus(Database).ToTranslatedString(language, timeZone)</i>
|
||||
</span>
|
||||
<div class="cardStatsUnderTitle">
|
||||
<i class="pink heart icon" title="Hearts"></i> <span>@hearts</span>
|
||||
<i class="blue comment icon" title="Comments"></i> <span>@comments</span>
|
||||
<i class="green upload icon" title="Uploaded Levels"></i><span>@levels</span>
|
||||
<i class="purple camera icon" title="Uploaded Photos"></i><span>@photos</span>
|
||||
<i class="pink heart icon" title="Hearts"></i> <span>@stats.HeartCount</span>
|
||||
<i class="blue comment icon" title="Comments"></i> <span>@stats.CommentCount</span>
|
||||
<i class="green upload icon" title="Uploaded Levels"></i><span>@stats.LevelCount</span>
|
||||
<i class="purple camera icon" title="Uploaded Photos"></i><span>@stats.PhotoCount</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -10,7 +10,6 @@ namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages;
|
|||
|
||||
public class PhotosPage : BaseLayout
|
||||
{
|
||||
|
||||
public int PageAmount;
|
||||
|
||||
public int PageNumber;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
@using LBPUnion.ProjectLighthouse.Types.Moderation.Cases
|
||||
@using LBPUnion.ProjectLighthouse.Types.Users
|
||||
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.SlotPage
|
||||
@inject DatabaseContext Database
|
||||
|
||||
@{
|
||||
Layout = "Layouts/BaseLayout";
|
||||
|
@ -55,7 +56,7 @@
|
|||
string[] authorLabels;
|
||||
if (Model.Slot?.GameVersion == GameVersion.LittleBigPlanet1)
|
||||
{
|
||||
authorLabels = Model.Slot.LevelTags(DatabaseContext.CreateNewInstance());
|
||||
authorLabels = Model.Slot.LevelTags(Database);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1,38 +1,22 @@
|
|||
#nullable enable
|
||||
using LBPUnion.ProjectLighthouse;
|
||||
using LBPUnion.ProjectLighthouse.Configuration;
|
||||
using LBPUnion.ProjectLighthouse.Logging.Loggers.AspNet;
|
||||
using LBPUnion.ProjectLighthouse.Servers.Website.Startup;
|
||||
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Servers.Website;
|
||||
await StartupTasks.Run(ServerType.Website);
|
||||
|
||||
public static class Program
|
||||
IHostBuilder builder = Host.CreateDefaultBuilder();
|
||||
builder.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
StartupTasks.Run(args, ServerType.Website);
|
||||
webBuilder.UseStartup<WebsiteStartup>();
|
||||
webBuilder.UseUrls(ServerConfiguration.Instance.WebsiteListenUrl);
|
||||
webBuilder.UseWebRoot("StaticFiles");
|
||||
});
|
||||
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args)
|
||||
=> Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults
|
||||
(
|
||||
webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<WebsiteStartup>();
|
||||
webBuilder.UseWebRoot("StaticFiles");
|
||||
webBuilder.UseUrls(ServerConfiguration.Instance.WebsiteListenUrl);
|
||||
}
|
||||
)
|
||||
.ConfigureLogging
|
||||
(
|
||||
logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, AspNetToLighthouseLoggerProvider>());
|
||||
}
|
||||
);
|
||||
}
|
||||
builder.ConfigureLogging(logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.AddProvider(new AspNetToLighthouseLoggerProvider());
|
||||
});
|
||||
await builder.Build().RunAsync();
|
|
@ -42,7 +42,7 @@ public class WebsiteStartup
|
|||
{
|
||||
// jank but works
|
||||
string projectDir = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..", "..", ".."));
|
||||
|
||||
|
||||
options.FileProviders.Clear();
|
||||
options.FileProviders.Add(new PhysicalFileProvider(projectDir));
|
||||
});
|
||||
|
@ -131,7 +131,10 @@ public class WebsiteStartup
|
|||
|
||||
app.UseRequestLocalization();
|
||||
|
||||
app.UseEndpoints(endpoints => endpoints.MapControllers());
|
||||
app.UseEndpoints(endpoints => endpoints.MapRazorPages());
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapControllers();
|
||||
endpoints.MapRazorPages();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LBPUnion.ProjectLighthouse.Filter;
|
||||
using LBPUnion.ProjectLighthouse.Filter;
|
||||
using LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||
using LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
|
||||
using LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions;
|
||||
using LBPUnion.ProjectLighthouse.Tests.Helpers;
|
||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Xunit;
|
||||
|
|
|
@ -8,9 +8,12 @@ namespace LBPUnion.ProjectLighthouse.Tests.Helpers;
|
|||
|
||||
public static class IntegrationHelper
|
||||
{
|
||||
private static readonly Lazy<bool> dbConnected = new(IsDbConnected);
|
||||
private static readonly Lazy<bool> dbConnected = new(() =>
|
||||
{
|
||||
using DatabaseContext database = DatabaseContext.CreateNewInstance();
|
||||
return database.Database.CanConnect();
|
||||
});
|
||||
|
||||
private static bool IsDbConnected() => ServerStatics.DbConnected;
|
||||
|
||||
/// <summary>
|
||||
/// Resets the database to a clean state and returns a new DatabaseContext.
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
using LBPUnion.ProjectLighthouse.Configuration;
|
||||
using LBPUnion.ProjectLighthouse.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Xunit;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Tests.Integration;
|
||||
|
||||
public sealed class DatabaseFactAttribute : FactAttribute
|
||||
{
|
||||
private static readonly object migrateLock = new();
|
||||
|
||||
public DatabaseFactAttribute()
|
||||
{
|
||||
ServerConfiguration.Instance.DbConnectionString = "server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse";
|
||||
if (!ServerStatics.DbConnected) this.Skip = "Database not available";
|
||||
else
|
||||
lock (migrateLock)
|
||||
{
|
||||
using DatabaseContext database = DatabaseContext.CreateNewInstance();
|
||||
database.Database.Migrate();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,31 +6,34 @@ using LBPUnion.ProjectLighthouse.Helpers;
|
|||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Types.Maintenance;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Administration.Maintenance.Commands
|
||||
namespace LBPUnion.ProjectLighthouse.Administration.Maintenance.Commands;
|
||||
|
||||
public class CreateApiKeyCommand : ICommand
|
||||
{
|
||||
public class CreateApiKeyCommand : ICommand
|
||||
{
|
||||
public string Name() => "Create API Key";
|
||||
public string[] Aliases() => new[] { "createAPIKey", };
|
||||
public string Arguments() => "<description>";
|
||||
public int RequiredArgs() => 1;
|
||||
|
||||
public async Task Run(string[] args, Logger logger)
|
||||
public string Name() => "Create API Key";
|
||||
public string[] Aliases() =>
|
||||
new[]
|
||||
{
|
||||
ApiKeyEntity key = new() { Description = args[0], };
|
||||
if (string.IsNullOrWhiteSpace(key.Description))
|
||||
{
|
||||
key.Description = "<no description specified>";
|
||||
}
|
||||
key.Key = CryptoHelper.GenerateAuthToken();
|
||||
key.Created = DateTime.Now;
|
||||
DatabaseContext database = DatabaseContext.CreateNewInstance();
|
||||
await database.APIKeys.AddAsync(key);
|
||||
await database.SaveChangesAsync();
|
||||
logger.LogSuccess($"The API key has been created (id: {key.Id}), however for security the token will only be shown once.", LogArea.Command);
|
||||
logger.LogInfo($"Key: {key.Key}", LogArea.Command);
|
||||
}
|
||||
}
|
||||
}
|
||||
"createAPIKey",
|
||||
};
|
||||
public string Arguments() => "<description>";
|
||||
public int RequiredArgs() => 1;
|
||||
|
||||
public async Task Run(IServiceProvider provider, string[] args, Logger logger)
|
||||
{
|
||||
ApiKeyEntity key = new() { Description = args[0], };
|
||||
if (string.IsNullOrWhiteSpace(key.Description))
|
||||
{
|
||||
key.Description = "<no description specified>";
|
||||
}
|
||||
key.Key = CryptoHelper.GenerateAuthToken();
|
||||
key.Created = DateTime.Now;
|
||||
DatabaseContext database = provider.GetRequiredService<DatabaseContext>();
|
||||
await database.APIKeys.AddAsync(key);
|
||||
await database.SaveChangesAsync();
|
||||
logger.LogSuccess($"The API key has been created (id: {key.Id}), however for security the token will only be shown once.", LogArea.Command);
|
||||
logger.LogInfo($"Key: {key.Key}", LogArea.Command);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using LBPUnion.ProjectLighthouse.Database;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
|
@ -7,47 +8,46 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
|||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Types.Maintenance;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Administration.Maintenance.Commands;
|
||||
|
||||
public class CreateUserCommand : ICommand
|
||||
{
|
||||
private readonly DatabaseContext _database = DatabaseContext.CreateNewInstance();
|
||||
public string Name() => "Create New User";
|
||||
public string[] Aliases() =>
|
||||
new[]
|
||||
{
|
||||
"useradd", "adduser", "newuser", "createUser",
|
||||
};
|
||||
public string Arguments() => "<OnlineID> <Password>";
|
||||
public int RequiredArgs() => 2;
|
||||
|
||||
public async Task Run(string[] args, Logger logger)
|
||||
public async Task Run(IServiceProvider provider, string[] args, Logger logger)
|
||||
{
|
||||
|
||||
DatabaseContext database = provider.GetRequiredService<DatabaseContext>();
|
||||
string onlineId = args[0];
|
||||
string password = args[1];
|
||||
|
||||
password = CryptoHelper.Sha256Hash(password);
|
||||
|
||||
UserEntity? user = await this._database.Users.FirstOrDefaultAsync(u => u.Username == onlineId);
|
||||
UserEntity? user = await database.Users.FirstOrDefaultAsync(u => u.Username == onlineId);
|
||||
if (user == null)
|
||||
{
|
||||
user = await this._database.CreateUser(onlineId, CryptoHelper.BCryptHash(password));
|
||||
logger.LogSuccess($"Created user {user.UserId} with online ID (username) {user.Username} and the specified password.", LogArea.Command);
|
||||
|
||||
user.PasswordResetRequired = true;
|
||||
logger.LogInfo("This user will need to reset their password when they log in.", LogArea.Command);
|
||||
|
||||
await this._database.SaveChangesAsync();
|
||||
logger.LogInfo("Database changes saved.", LogArea.Command);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogError("A user with this username already exists.", LogArea.Command);
|
||||
return;
|
||||
}
|
||||
|
||||
user = await database.CreateUser(onlineId, CryptoHelper.BCryptHash(password));
|
||||
logger.LogSuccess(
|
||||
$"Created user {user.UserId} with online ID (username) {user.Username} and the specified password.",
|
||||
LogArea.Command);
|
||||
|
||||
user.PasswordResetRequired = true;
|
||||
logger.LogInfo("This user will need to reset their password when they log in.", LogArea.Command);
|
||||
|
||||
await database.SaveChangesAsync();
|
||||
logger.LogInfo("Database changes saved.", LogArea.Command);
|
||||
}
|
||||
|
||||
public string Name() => "Create New User";
|
||||
|
||||
public string[] Aliases()
|
||||
=> new[]
|
||||
{
|
||||
"useradd", "adduser", "newuser", "createUser",
|
||||
};
|
||||
|
||||
public string Arguments() => "<OnlineID> <Password>";
|
||||
|
||||
public int RequiredArgs() => 2;
|
||||
}
|
|
@ -7,12 +7,12 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
|||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Types.Maintenance;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Administration.Maintenance.Commands;
|
||||
|
||||
public class DeleteUserCommand : ICommand
|
||||
{
|
||||
private readonly DatabaseContext database = DatabaseContext.CreateNewInstance();
|
||||
public string Name() => "Delete User";
|
||||
public string[] Aliases()
|
||||
=> new[]
|
||||
|
@ -21,22 +21,22 @@ public class DeleteUserCommand : ICommand
|
|||
};
|
||||
public string Arguments() => "<username/userId>";
|
||||
public int RequiredArgs() => 1;
|
||||
public async Task Run(string[] args, Logger logger)
|
||||
|
||||
public async Task Run(IServiceProvider provider, string[] args, Logger logger)
|
||||
{
|
||||
UserEntity? user = await this.database.Users.FirstOrDefaultAsync(u => u.Username.Length > 0 && u.Username == args[0]);
|
||||
DatabaseContext database = provider.GetRequiredService<DatabaseContext>();
|
||||
UserEntity? user = await database.Users.FirstOrDefaultAsync(u => u.Username.Length > 0 && u.Username == args[0]);
|
||||
if (user == null)
|
||||
try
|
||||
{
|
||||
user = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == Convert.ToInt32(args[0]));
|
||||
if (user == null) throw new Exception();
|
||||
}
|
||||
catch
|
||||
{
|
||||
user = await database.Users.FirstOrDefaultAsync(u => u.UserId == Convert.ToInt32(args[0]));
|
||||
if (user == null)
|
||||
{
|
||||
logger.LogError($"Could not find user by parameter '{args[0]}'", LogArea.Command);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await this.database.RemoveUser(user);
|
||||
await database.RemoveUser(user);
|
||||
logger.LogSuccess($"Successfully deleted user {user.Username}", LogArea.Command);
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
using LBPUnion.ProjectLighthouse.StorableLists;
|
||||
|
@ -8,14 +9,14 @@ namespace LBPUnion.ProjectLighthouse.Administration.Maintenance.Commands;
|
|||
public class FlushRedisCommand : ICommand
|
||||
{
|
||||
public string Name() => "Flush Redis";
|
||||
public string[] Aliases() => new[] {
|
||||
"flush", "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();
|
||||
}
|
||||
public async Task Run(IServiceProvider provider, string[] args, Logger logger) => await RedisDatabase.FlushAll();
|
||||
|
||||
}
|
|
@ -7,32 +7,12 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
|||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Types.Maintenance;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Administration.Maintenance.Commands;
|
||||
|
||||
public class RenameUserCommand : ICommand
|
||||
{
|
||||
private readonly DatabaseContext database = DatabaseContext.CreateNewInstance();
|
||||
public async Task Run(string[] args, Logger logger)
|
||||
{
|
||||
UserEntity? user = await this.database.Users.FirstOrDefaultAsync(u => u.Username == args[0]);
|
||||
if (user == null)
|
||||
try
|
||||
{
|
||||
user = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == Convert.ToInt32(args[0]));
|
||||
if (user == null) throw new Exception();
|
||||
}
|
||||
catch
|
||||
{
|
||||
logger.LogError($"Could not find user by parameter '{args[0]}'", LogArea.Command);
|
||||
return;
|
||||
}
|
||||
|
||||
user.Username = args[1];
|
||||
await this.database.SaveChangesAsync();
|
||||
|
||||
logger.LogSuccess($"The username for user {user.Username} (id: {user.UserId}) has been changed.", LogArea.Command);
|
||||
}
|
||||
public string Name() => "Rename User";
|
||||
public string[] Aliases()
|
||||
=> new[]
|
||||
|
@ -41,4 +21,26 @@ public class RenameUserCommand : ICommand
|
|||
};
|
||||
public string Arguments() => "<username/userId> <newUsername>";
|
||||
public int RequiredArgs() => 2;
|
||||
|
||||
public async Task Run(IServiceProvider provider, string[] args, Logger logger)
|
||||
{
|
||||
DatabaseContext database = provider.GetRequiredService<DatabaseContext>();
|
||||
UserEntity? user = await database.Users.FirstOrDefaultAsync(u => u.Username == args[0]);
|
||||
if (user == null)
|
||||
{
|
||||
_ = int.TryParse(args[0], out int userId);
|
||||
user = await database.Users.FirstOrDefaultAsync(u => u.UserId == userId);
|
||||
if (user == null)
|
||||
{
|
||||
logger.LogError($"Could not find user by parameter '{args[0]}'", LogArea.Command);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
user.Username = args[1];
|
||||
await database.SaveChangesAsync();
|
||||
|
||||
logger.LogSuccess($"The username for user {user.Username} (id: {user.UserId}) has been changed.",
|
||||
LogArea.Command);
|
||||
}
|
||||
}
|
|
@ -8,12 +8,12 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
|||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Types.Maintenance;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Administration.Maintenance.Commands;
|
||||
|
||||
public class ResetPasswordCommand : ICommand
|
||||
{
|
||||
private readonly DatabaseContext database = DatabaseContext.CreateNewInstance();
|
||||
public string Name() => "Reset Password";
|
||||
public string[] Aliases()
|
||||
=> new[]
|
||||
|
@ -23,28 +23,28 @@ public class ResetPasswordCommand : ICommand
|
|||
public string Arguments() => "<username/userId> <sha256/plaintext>";
|
||||
public int RequiredArgs() => 2;
|
||||
|
||||
public async Task Run(string[] args, Logger logger)
|
||||
public async Task Run(IServiceProvider provider, string[] args, Logger logger)
|
||||
{
|
||||
UserEntity? user = await this.database.Users.FirstOrDefaultAsync(u => u.Username == args[0]);
|
||||
DatabaseContext database = provider.GetRequiredService<DatabaseContext>();
|
||||
UserEntity? user = await database.Users.FirstOrDefaultAsync(u => u.Username == args[0]);
|
||||
if (user == null)
|
||||
try
|
||||
{
|
||||
user = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == Convert.ToInt32(args[0]));
|
||||
if (user == null) throw new Exception();
|
||||
}
|
||||
catch
|
||||
{
|
||||
_ = int.TryParse(args[0], out int userId);
|
||||
user = await database.Users.FirstOrDefaultAsync(u => u.UserId == userId);
|
||||
if (user == null)
|
||||
{
|
||||
logger.LogError($"Could not find user by parameter '{args[0]}'", LogArea.Command);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
string password = args[1];
|
||||
if (password.Length != 64) password = CryptoHelper.Sha256Hash(password);
|
||||
|
||||
user.Password = CryptoHelper.BCryptHash(password);
|
||||
user.PasswordResetRequired = true;
|
||||
|
||||
await this.database.SaveChangesAsync();
|
||||
await database.SaveChangesAsync();
|
||||
|
||||
logger.LogSuccess($"The password for user {user.Username} (id: {user.UserId}) has been reset.", LogArea.Command);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
|
@ -7,10 +8,6 @@ namespace LBPUnion.ProjectLighthouse.Administration.Maintenance.Commands;
|
|||
|
||||
public class TestWebhookCommand : ICommand
|
||||
{
|
||||
public async Task Run(string[] args, Logger logger)
|
||||
{
|
||||
await WebhookHelper.SendWebhook("Testing 123", "Someone is testing the Discord webhook from the admin panel.");
|
||||
}
|
||||
public string Name() => "Test Discord Webhook";
|
||||
public string[] Aliases()
|
||||
=> new[]
|
||||
|
@ -19,4 +16,7 @@ public class TestWebhookCommand : ICommand
|
|||
};
|
||||
public string Arguments() => "";
|
||||
public int RequiredArgs() => 0;
|
||||
|
||||
public async Task Run(IServiceProvider provider, string[] args, Logger logger) =>
|
||||
await WebhookHelper.SendWebhook("Testing 123", "Someone is testing the Discord webhook from the admin panel.");
|
||||
}
|
|
@ -1,19 +1,18 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using LBPUnion.ProjectLighthouse.Database;
|
||||
using LBPUnion.ProjectLighthouse.Extensions;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||
using LBPUnion.ProjectLighthouse.Types.Maintenance;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Administration.Maintenance.Commands;
|
||||
|
||||
public class WipeTokensForUserCommand : ICommand
|
||||
{
|
||||
private readonly DatabaseContext database = DatabaseContext.CreateNewInstance();
|
||||
|
||||
public string Name() => "Wipe tokens for user";
|
||||
public string[] Aliases()
|
||||
=> new[]
|
||||
|
@ -22,25 +21,24 @@ public class WipeTokensForUserCommand : ICommand
|
|||
};
|
||||
public string Arguments() => "<username/userId>";
|
||||
public int RequiredArgs() => 1;
|
||||
public async Task Run(string[] args, Logger logger)
|
||||
|
||||
public async Task Run(IServiceProvider provider, string[] args, Logger logger)
|
||||
{
|
||||
UserEntity? user = await this.database.Users.FirstOrDefaultAsync(u => u.Username == args[0]);
|
||||
DatabaseContext database = provider.GetRequiredService<DatabaseContext>();
|
||||
UserEntity? user = await database.Users.FirstOrDefaultAsync(u => u.Username == args[0]);
|
||||
if (user == null)
|
||||
try
|
||||
{
|
||||
user = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == Convert.ToInt32(args[0]));
|
||||
if (user == null) throw new Exception();
|
||||
}
|
||||
catch
|
||||
{
|
||||
_ = int.TryParse(args[0], out int userId);
|
||||
user = await database.Users.FirstOrDefaultAsync(u => u.UserId == userId);
|
||||
if (user == null)
|
||||
{
|
||||
Console.WriteLine(@$"Could not find user by parameter '{args[0]}'");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.database.GameTokens.RemoveRange(this.database.GameTokens.Where(t => t.UserId == user.UserId));
|
||||
this.database.WebTokens.RemoveRange(this.database.WebTokens.Where(t => t.UserId == user.UserId));
|
||||
|
||||
await this.database.SaveChangesAsync();
|
||||
await database.GameTokens.RemoveWhere(t => t.UserId == user.UserId);
|
||||
await database.WebTokens.RemoveWhere(t => t.UserId == user.UserId);
|
||||
|
||||
Console.WriteLine(@$"Deleted all tokens for {user.Username} (id: {user.UserId}).");
|
||||
}
|
||||
|
|
|
@ -30,11 +30,11 @@ public static class MaintenanceHelper
|
|||
public static List<IMigrationTask> MigrationTasks { get; }
|
||||
public static List<IRepeatingTask> RepeatingTasks { get; }
|
||||
|
||||
public static async Task<List<LogLine>> RunCommand(string[] args)
|
||||
public static async Task<List<LogLine>> RunCommand(IServiceProvider provider, string[] args)
|
||||
{
|
||||
if (args.Length < 1)
|
||||
throw new Exception
|
||||
("This should never happen. " + "If it did, its because you tried to run a command before validating that the user actually wants to run one.");
|
||||
throw new Exception("This should never happen. " +
|
||||
"If it did, its because you tried to run a command before validating that the user actually wants to run one.");
|
||||
|
||||
string baseCmd = args[0];
|
||||
args = args.Skip(1).ToArray();
|
||||
|
@ -44,21 +44,32 @@ public static class MaintenanceHelper
|
|||
InMemoryLogger memoryLogger = new();
|
||||
logger.AddLogger(memoryLogger);
|
||||
|
||||
IEnumerable<ICommand> suitableCommands = Commands.Where
|
||||
(command => command.Aliases().Any(a => a.ToLower() == baseCmd.ToLower()))
|
||||
.Where(command => args.Length >= command.RequiredArgs());
|
||||
foreach (ICommand command in suitableCommands)
|
||||
ICommand? command = Commands
|
||||
.Where(command =>
|
||||
command.Aliases().Any(a => string.Equals(a, baseCmd, StringComparison.CurrentCultureIgnoreCase)))
|
||||
.FirstOrDefault(command => args.Length >= command.RequiredArgs());
|
||||
if (command == null)
|
||||
{
|
||||
logger.LogInfo("Running command " + command.Name(), LogArea.Command);
|
||||
|
||||
await command.Run(args, logger);
|
||||
logger.LogError("Failed to find command", LogArea.Command);
|
||||
logger.Flush();
|
||||
return memoryLogger.Lines;
|
||||
}
|
||||
try
|
||||
{
|
||||
logger.LogInfo("Running command " + command.Name(), LogArea.Command);
|
||||
|
||||
logger.LogError("Command not found.", LogArea.Command);
|
||||
logger.Flush();
|
||||
return memoryLogger.Lines;
|
||||
await command.Run(provider, args, logger);
|
||||
|
||||
logger.Flush();
|
||||
return memoryLogger.Lines;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
logger.LogError($"Failed to run command: {e.Message}", LogArea.Command);
|
||||
logger.LogError(e.ToDetailedException(), LogArea.Command);
|
||||
logger.Flush();
|
||||
return memoryLogger.Lines;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task RunMaintenanceJob(string jobName)
|
||||
|
@ -69,9 +80,8 @@ public static class MaintenanceHelper
|
|||
await job.Run();
|
||||
}
|
||||
|
||||
public static async Task RunMigration(IMigrationTask migrationTask, DatabaseContext? database = null)
|
||||
public static async Task RunMigration(DatabaseContext database, IMigrationTask migrationTask)
|
||||
{
|
||||
database ??= DatabaseContext.CreateNewInstance();
|
||||
|
||||
// Migrations should never be run twice.
|
||||
Debug.Assert(!await database.CompletedMigrations.Has(m => m.MigrationName == migrationTask.GetType().Name));
|
||||
|
|
|
@ -14,14 +14,15 @@ namespace LBPUnion.ProjectLighthouse.Administration.Maintenance.MaintenanceJobs;
|
|||
|
||||
public class CleanupBrokenPhotosMaintenanceJob : IMaintenanceJob
|
||||
{
|
||||
private readonly DatabaseContext database = DatabaseContext.CreateNewInstance();
|
||||
public string Name() => "Cleanup Broken Photos";
|
||||
public string Description() => "Deletes all photos that have missing assets or invalid photo subjects.";
|
||||
|
||||
[SuppressMessage("ReSharper", "LoopCanBePartlyConvertedToQuery")]
|
||||
public async Task Run()
|
||||
{
|
||||
foreach (PhotoEntity photo in this.database.Photos)
|
||||
|
||||
await using DatabaseContext database = DatabaseContext.CreateNewInstance();
|
||||
foreach (PhotoEntity photo in database.Photos)
|
||||
{
|
||||
bool hashNullOrEmpty = false;
|
||||
bool noHashesExist = false;
|
||||
|
@ -44,8 +45,7 @@ public class CleanupBrokenPhotosMaintenanceJob : IMaintenanceJob
|
|||
goto removePhoto;
|
||||
}
|
||||
|
||||
hashNullOrEmpty = string.IsNullOrEmpty
|
||||
(photo.LargeHash) ||
|
||||
hashNullOrEmpty = string.IsNullOrEmpty(photo.LargeHash) ||
|
||||
string.IsNullOrEmpty(photo.MediumHash) ||
|
||||
string.IsNullOrEmpty(photo.SmallHash) ||
|
||||
string.IsNullOrEmpty(photo.PlanHash);
|
||||
|
@ -86,18 +86,18 @@ public class CleanupBrokenPhotosMaintenanceJob : IMaintenanceJob
|
|||
|
||||
Console.WriteLine
|
||||
(
|
||||
$"Removing photo (id: {photo.PhotoId}): " +
|
||||
$"{nameof(hashNullOrEmpty)}: {hashNullOrEmpty}, " +
|
||||
$"{nameof(noHashesExist)}: {noHashesExist}, " +
|
||||
$"{nameof(largeHashIsInvalidFile)}: {largeHashIsInvalidFile}, " +
|
||||
$"{nameof(tooManyPhotoSubjects)}: {tooManyPhotoSubjects}" +
|
||||
$"{nameof(duplicatePhotoSubjects)}: {duplicatePhotoSubjects}" +
|
||||
$"{nameof(takenInTheFuture)}: {takenInTheFuture}"
|
||||
@$"Removing photo (id: {photo.PhotoId}): " +
|
||||
@$"{nameof(hashNullOrEmpty)}: {hashNullOrEmpty}, " +
|
||||
@$"{nameof(noHashesExist)}: {noHashesExist}, " +
|
||||
@$"{nameof(largeHashIsInvalidFile)}: {largeHashIsInvalidFile}, " +
|
||||
@$"{nameof(tooManyPhotoSubjects)}: {tooManyPhotoSubjects}" +
|
||||
@$"{nameof(duplicatePhotoSubjects)}: {duplicatePhotoSubjects}" +
|
||||
@$"{nameof(takenInTheFuture)}: {takenInTheFuture}"
|
||||
);
|
||||
|
||||
this.database.Photos.Remove(photo);
|
||||
database.Photos.Remove(photo);
|
||||
}
|
||||
|
||||
await this.database.SaveChangesAsync();
|
||||
await database.SaveChangesAsync();
|
||||
}
|
||||
}
|
|
@ -1,23 +1,21 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using LBPUnion.ProjectLighthouse.Database;
|
||||
using LBPUnion.ProjectLighthouse.Extensions;
|
||||
using LBPUnion.ProjectLighthouse.Types.Maintenance;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Administration.Maintenance.MaintenanceJobs;
|
||||
|
||||
public class DeleteAllTokensMaintenanceJob : IMaintenanceJob
|
||||
{
|
||||
private readonly DatabaseContext database = DatabaseContext.CreateNewInstance();
|
||||
|
||||
public string Name() => "Delete ALL Tokens";
|
||||
public string Description() => "Deletes ALL game tokens and web tokens.";
|
||||
|
||||
public async Task Run()
|
||||
{
|
||||
this.database.GameTokens.RemoveRange(this.database.GameTokens);
|
||||
this.database.WebTokens.RemoveRange(this.database.WebTokens);
|
||||
|
||||
await this.database.SaveChangesAsync();
|
||||
|
||||
Console.WriteLine("Deleted ALL tokens.");
|
||||
await using DatabaseContext database = DatabaseContext.CreateNewInstance();
|
||||
await database.GameTokens.RemoveWhere(t => true);
|
||||
await database.WebTokens.RemoveWhere(t => true);
|
||||
Console.WriteLine(@"Deleted ALL tokens.");
|
||||
}
|
||||
}
|
|
@ -11,5 +11,5 @@ public class CleanupRoomsTask : IRepeatingTask
|
|||
public string Name => "Cleanup Rooms";
|
||||
public TimeSpan RepeatInterval => TimeSpan.FromSeconds(10);
|
||||
public DateTime LastRan { get; set; }
|
||||
public Task Run(DatabaseContext database) => RoomHelper.CleanupRooms();
|
||||
public Task Run(DatabaseContext database) => RoomHelper.CleanupRooms(database);
|
||||
}
|
|
@ -1,9 +1,6 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.Linq;
|
||||
using LBPUnion.ProjectLighthouse.Database;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Configuration;
|
||||
|
@ -12,21 +9,6 @@ public static class ServerStatics
|
|||
{
|
||||
public const int PageSize = 20;
|
||||
|
||||
public static bool DbConnected {
|
||||
get {
|
||||
try
|
||||
{
|
||||
using DatabaseContext db = DatabaseContext.CreateNewInstance();
|
||||
return db.Database.CanConnect();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Logger.Error(e.ToString(), LogArea.Database);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This needs to go at some point.
|
||||
public static bool IsUnitTesting => AppDomain.CurrentDomain.GetAssemblies().Any(assembly => assembly.FullName!.StartsWith("xunit"));
|
||||
|
||||
|
|
|
@ -11,6 +11,13 @@ public static class DatabaseExtensions
|
|||
public static async Task<bool> Has<T>(this IQueryable<T> queryable, Expression<Func<T, bool>> predicate)
|
||||
=> await queryable.FirstOrDefaultAsync(predicate) != null;
|
||||
|
||||
public static async Task RemoveWhere<T>(this DbSet<T> queryable, Expression<Func<T, bool>> predicate) where T : class
|
||||
=> await queryable.Where(predicate).ExecuteDeleteAsync();
|
||||
/// <summary>
|
||||
/// Deletes all records matching a given predicate
|
||||
/// <para>Deletes are executed immediately without calling SaveChanges()</para>
|
||||
/// </summary>
|
||||
/// <param name="dbSet">The database set to source from</param>
|
||||
/// <param name="predicate">The predicate used to determine which records to delete</param>
|
||||
/// <typeparam name="T">The record type contained within the DbSet</typeparam>
|
||||
public static async Task RemoveWhere<T>(this DbSet<T> dbSet, Expression<Func<T, bool>> predicate) where T : class
|
||||
=> await dbSet.Where(predicate).ExecuteDeleteAsync();
|
||||
}
|
|
@ -27,7 +27,7 @@ public static class RoomHelper
|
|||
private static int roomIdIncrement;
|
||||
internal static int RoomIdIncrement => roomIdIncrement++;
|
||||
|
||||
public static FindBestRoomResponse? FindBestRoom(UserEntity? user, GameVersion roomVersion, RoomSlot? slot, Platform? platform, string? location)
|
||||
public static FindBestRoomResponse? FindBestRoom(DatabaseContext database, UserEntity? user, GameVersion roomVersion, RoomSlot? slot, Platform? platform, string? location)
|
||||
{
|
||||
if (roomVersion == GameVersion.LittleBigPlanet1 || roomVersion == GameVersion.LittleBigPlanetPSP)
|
||||
{
|
||||
|
@ -87,7 +87,7 @@ public static class RoomHelper
|
|||
Locations = new List<string>(),
|
||||
};
|
||||
|
||||
foreach (UserEntity player in room.GetPlayers(DatabaseContext.CreateNewInstance()))
|
||||
foreach (UserEntity player in room.GetPlayers(database))
|
||||
{
|
||||
response.Players.Add
|
||||
(
|
||||
|
@ -157,8 +157,8 @@ public static class RoomHelper
|
|||
RoomVersion = roomVersion,
|
||||
RoomPlatform = roomPlatform,
|
||||
};
|
||||
|
||||
CleanupRooms(room.HostId, room);
|
||||
using DatabaseContext database = DatabaseContext.CreateNewInstance();
|
||||
CleanupRooms(database, room.HostId, room);
|
||||
lock(RoomLock) Rooms.Add(room);
|
||||
Logger.Info($"Created room (id: {room.RoomId}) for host {room.HostId}", LogArea.Match);
|
||||
|
||||
|
@ -175,20 +175,11 @@ public static class RoomHelper
|
|||
|
||||
public static Room? FindRoomByUserId(int userId)
|
||||
{
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||
foreach (Room room in Rooms)
|
||||
{
|
||||
if (room.PlayerIds.Any(p => p == userId))
|
||||
{
|
||||
return room;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return Rooms.FirstOrDefault(room => room.PlayerIds.Any(p => p == userId));
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "InvertIf")]
|
||||
public static Task CleanupRooms(int? hostId = null, Room? newRoom = null, DatabaseContext? database = null)
|
||||
public static Task CleanupRooms(DatabaseContext database, int? hostId = null, Room? newRoom = null)
|
||||
{
|
||||
#if DEBUG
|
||||
Stopwatch stopwatch = new();
|
||||
|
@ -204,8 +195,6 @@ public static class RoomHelper
|
|||
#endif
|
||||
int roomCountBeforeCleanup = rooms.Count();
|
||||
|
||||
database ??= DatabaseContext.CreateNewInstance();
|
||||
|
||||
// Remove offline players from rooms
|
||||
foreach (Room room in rooms)
|
||||
{
|
||||
|
|
|
@ -9,7 +9,6 @@ namespace LBPUnion.ProjectLighthouse.Helpers;
|
|||
|
||||
public static class StatisticsHelper
|
||||
{
|
||||
|
||||
public static async Task<int> RecentMatches(DatabaseContext database) => await database.LastContacts.Where(l => TimeHelper.Timestamp - l.Timestamp < 300).CountAsync();
|
||||
|
||||
public static async Task<int> RecentMatchesForGame(DatabaseContext database, GameVersion gameVersion)
|
||||
|
|
|
@ -23,6 +23,5 @@ public class FileLogger : ILogger
|
|||
File.AppendAllText(Path.Combine(logsDirectory, "all.log"), contentAll);
|
||||
}
|
||||
catch(IOException) {} // windows, ya goofed
|
||||
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ namespace LBPUnion.ProjectLighthouse;
|
|||
|
||||
public static class StartupTasks
|
||||
{
|
||||
public static void Run(string[] args, ServerType serverType)
|
||||
public static async Task Run(ServerType serverType)
|
||||
{
|
||||
// Log startup time
|
||||
Stopwatch stopwatch = new();
|
||||
|
@ -42,7 +42,7 @@ public static class StartupTasks
|
|||
Logger.Info($"Welcome to the Project Lighthouse {serverType.ToString()}!", LogArea.Startup);
|
||||
|
||||
Logger.Info("Loading configurations...", LogArea.Startup);
|
||||
if (!loadConfigurations())
|
||||
if (!LoadConfigurations())
|
||||
{
|
||||
Logger.Error("Failed to load one or more configurations", LogArea.Config);
|
||||
Environment.Exit(1);
|
||||
|
@ -50,22 +50,26 @@ public static class StartupTasks
|
|||
|
||||
// Version info depends on ServerConfig
|
||||
Logger.Info($"You are running version {VersionHelper.FullVersion}", LogArea.Startup);
|
||||
|
||||
Logger.Info("Connecting to the database...", LogArea.Startup);
|
||||
bool dbConnected = ServerStatics.DbConnected;
|
||||
if (!dbConnected)
|
||||
|
||||
await using DatabaseContext database = DatabaseContext.CreateNewInstance();
|
||||
try
|
||||
{
|
||||
Logger.Error("Database unavailable! Exiting.", LogArea.Startup);
|
||||
if (!await database.Database.CanConnectAsync())
|
||||
{
|
||||
Logger.Error("Database unavailable! Exiting.", LogArea.Startup);
|
||||
Logger.Error("Ensure that you have set the dbConnectionString field in lighthouse.yml", LogArea.Startup);
|
||||
Environment.Exit(-1);
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Success("Connected to the database!", LogArea.Startup);
|
||||
Logger.Error("There was an error connecting to the database:", LogArea.Startup);
|
||||
Logger.Error(e.ToDetailedException(), LogArea.Startup);
|
||||
Environment.Exit(-1);
|
||||
}
|
||||
|
||||
if (!dbConnected) Environment.Exit(1);
|
||||
using DatabaseContext database = DatabaseContext.CreateNewInstance();
|
||||
|
||||
migrateDatabase(database).Wait();
|
||||
await MigrateDatabase(database);
|
||||
|
||||
Logger.Debug
|
||||
(
|
||||
|
@ -76,13 +80,6 @@ public static class StartupTasks
|
|||
);
|
||||
Logger.Debug("You can do so by running any dotnet command with the flag: \"-c Release\". ", LogArea.Startup);
|
||||
|
||||
if (args.Length != 0)
|
||||
{
|
||||
List<LogLine> logLines = MaintenanceHelper.RunCommand(args).Result;
|
||||
Console.WriteLine(logLines.ToLogString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (ServerConfiguration.Instance.WebsiteConfiguration.ConvertAssetsOnStartup
|
||||
&& serverType == ServerType.Website)
|
||||
{
|
||||
|
@ -102,7 +99,7 @@ public static class StartupTasks
|
|||
admin.PermissionLevel = PermissionLevel.Administrator;
|
||||
admin.PasswordResetRequired = true;
|
||||
|
||||
database.SaveChanges();
|
||||
await database.SaveChangesAsync();
|
||||
|
||||
Logger.Success("No users were found, so an admin user was created. " +
|
||||
$"The username is 'admin' and the password is '{passwordClear}'.", LogArea.Startup);
|
||||
|
@ -112,7 +109,7 @@ public static class StartupTasks
|
|||
Logger.Success($"Ready! Startup took {stopwatch.ElapsedMilliseconds}ms. Passing off control to ASP.NET...", LogArea.Startup);
|
||||
}
|
||||
|
||||
private static bool loadConfigurations()
|
||||
private static bool LoadConfigurations()
|
||||
{
|
||||
Assembly assembly = Assembly.GetAssembly(typeof(ConfigurationBase<>));
|
||||
if (assembly == null) return false;
|
||||
|
@ -147,7 +144,7 @@ public static class StartupTasks
|
|||
return didLoad;
|
||||
}
|
||||
|
||||
private static async Task migrateDatabase(DatabaseContext database)
|
||||
private static async Task MigrateDatabase(DatabaseContext database)
|
||||
{
|
||||
int? originalTimeout = database.Database.GetCommandTimeout();
|
||||
database.Database.SetCommandTimeout(TimeSpan.FromMinutes(5));
|
||||
|
@ -179,7 +176,7 @@ public static class StartupTasks
|
|||
|
||||
foreach (IMigrationTask migrationTask in migrationsToRun)
|
||||
{
|
||||
MaintenanceHelper.RunMigration(migrationTask, database).Wait();
|
||||
MaintenanceHelper.RunMigration(database, migrationTask).Wait();
|
||||
}
|
||||
|
||||
stopwatch.Stop();
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using LBPUnion.ProjectLighthouse.Database;
|
||||
using LBPUnion.ProjectLighthouse.Types.Entities.Interaction;
|
||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||
|
@ -79,21 +77,13 @@ public class SlotEntity
|
|||
|
||||
public string[] LevelTags(DatabaseContext database)
|
||||
{
|
||||
|
||||
if (this.GameVersion != GameVersion.LittleBigPlanet1) return Array.Empty<string>();
|
||||
|
||||
// Sort tags by most popular
|
||||
SortedDictionary<string, int> occurrences = new();
|
||||
foreach (RatedLevelEntity r in database.RatedLevels.Where(r => r.SlotId == this.SlotId && r.TagLBP1.Length > 0))
|
||||
{
|
||||
if (!occurrences.ContainsKey(r.TagLBP1))
|
||||
occurrences.Add(r.TagLBP1, 1);
|
||||
else
|
||||
occurrences[r.TagLBP1]++;
|
||||
}
|
||||
|
||||
return occurrences.OrderBy(r => r.Value).Select(r => r.Key).ToArray();
|
||||
|
||||
return database.RatedLevels.Where(r => r.SlotId == this.SlotId && r.TagLBP1.Length > 0)
|
||||
.GroupBy(r => r.TagLBP1)
|
||||
.OrderByDescending(kvp => kvp.Count())
|
||||
.Select(kvp => kvp.Key)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public string BackgroundHash { get; set; } = "";
|
||||
|
@ -140,18 +130,6 @@ public class SlotEntity
|
|||
|
||||
public bool CommentsEnabled { get; set; } = true;
|
||||
|
||||
[NotMapped]
|
||||
public int Hearts => DatabaseContext.CreateNewInstance().HeartedLevels.Count(s => s.SlotId == this.SlotId);
|
||||
|
||||
[NotMapped]
|
||||
public int Comments => DatabaseContext.CreateNewInstance().Comments.Count(c => c.Type == CommentType.Level && c.TargetId == this.SlotId);
|
||||
|
||||
[NotMapped]
|
||||
public int Photos => DatabaseContext.CreateNewInstance().Photos.Count(p => p.SlotId == this.SlotId);
|
||||
|
||||
[NotMapped]
|
||||
public int PhotosWithAuthor => DatabaseContext.CreateNewInstance().Photos.Count(p => p.SlotId == this.SlotId && p.CreatorId == this.CreatorId);
|
||||
|
||||
[NotMapped]
|
||||
public int Plays => this.PlaysLBP1 + this.PlaysLBP2 + this.PlaysLBP3;
|
||||
|
||||
|
@ -160,12 +138,4 @@ public class SlotEntity
|
|||
|
||||
[NotMapped]
|
||||
public int PlaysComplete => this.PlaysLBP1Complete + this.PlaysLBP2Complete + this.PlaysLBP3Complete;
|
||||
|
||||
public double RatingLBP1 => DatabaseContext.CreateNewInstance().RatedLevels.Where(r => r.SlotId == this.SlotId).Average(r => (double?)r.RatingLBP1) ?? 3.0;
|
||||
|
||||
[NotMapped]
|
||||
public int Thumbsup => DatabaseContext.CreateNewInstance().RatedLevels.Count(r => r.SlotId == this.SlotId && r.Rating == 1);
|
||||
|
||||
[NotMapped]
|
||||
public int Thumbsdown => DatabaseContext.CreateNewInstance().RatedLevels.Count(r => r.SlotId == this.SlotId && r.Rating == -1);
|
||||
}
|
|
@ -38,7 +38,7 @@ public class CommentEntity
|
|||
public int ThumbsUp { get; set; }
|
||||
public int ThumbsDown { get; set; }
|
||||
|
||||
public string GetCommentMessage()
|
||||
public string GetCommentMessage(DatabaseContext database)
|
||||
{
|
||||
if (!this.Deleted)
|
||||
{
|
||||
|
@ -50,7 +50,6 @@ public class CommentEntity
|
|||
return "This comment has been deleted by the author.";
|
||||
}
|
||||
|
||||
using DatabaseContext database = DatabaseContext.CreateNewInstance();
|
||||
UserEntity deletedBy = database.Users.FirstOrDefault(u => u.Username == this.DeletedBy);
|
||||
|
||||
if (deletedBy != null && deletedBy.UserId == this.TargetId)
|
||||
|
|
|
@ -2,7 +2,6 @@ using System;
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using LBPUnion.ProjectLighthouse.Configuration;
|
||||
using LBPUnion.ProjectLighthouse.Database;
|
||||
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||
|
@ -49,10 +48,6 @@ public class UserEntity
|
|||
}
|
||||
|
||||
public UserStatus GetStatus(DatabaseContext database) => new(database, this.UserId);
|
||||
public int GetHeartCount(DatabaseContext database) => database.HeartedProfiles.Count(hp => hp.HeartedUserId == this.UserId);
|
||||
public int GetCommentCount(DatabaseContext database) => database.Comments.Count(c => c.TargetId == this.UserId && c.Type == CommentType.Profile);
|
||||
public int GetUsedSlotCount(DatabaseContext database) => database.Slots.Count(s => s.CreatorId == this.UserId);
|
||||
public int GetUploadedPhotoCount(DatabaseContext database) => database.Photos.Count(p => p.CreatorId == this.UserId);
|
||||
|
||||
/// <summary>
|
||||
/// The location of the profile card on the user's earth
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
|
@ -8,7 +9,7 @@ namespace LBPUnion.ProjectLighthouse.Types.Maintenance;
|
|||
public interface ICommand
|
||||
{
|
||||
public string FirstAlias => this.Aliases()[0];
|
||||
public Task Run(string[] args, Logger logger);
|
||||
public Task Run(IServiceProvider provider, string[] args, Logger logger);
|
||||
|
||||
public string Name();
|
||||
|
||||
|
|
|
@ -32,7 +32,8 @@ public class GameDeveloperSlot : SlotBase, INeedsPreparationForSerialization
|
|||
|
||||
public async Task PrepareSerialization(DatabaseContext database)
|
||||
{
|
||||
var stats = await database.Slots.Select(_ => new
|
||||
var stats = await database.Slots.Where(s => s.SlotId == this.InternalSlotId)
|
||||
.Select(_ => new
|
||||
{
|
||||
CommentCount = database.Comments.Count(c => c.TargetId == this.SlotId && c.Type == CommentType.Level),
|
||||
PhotoCount = database.Photos.Count(p => p.SlotId == this.SlotId),
|
||||
|
|
|
@ -235,7 +235,7 @@ public class GameUserSlot : SlotBase, INeedsPreparationForSerialization
|
|||
|
||||
public async Task PrepareSerialization(DatabaseContext database)
|
||||
{
|
||||
var stats = await database.Slots
|
||||
var stats = await database.Slots.Where(s => s.SlotId == this.SlotId)
|
||||
.Select(_ => new
|
||||
{
|
||||
ThumbsUp = database.RatedLevels.Count(r => r.SlotId == this.SlotId && r.Rating == 1),
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue