Refactor serialization system (#702)

* Initial work for serialization refactor

* Experiment with new naming conventions

* Mostly implement user and slot serialization.
Still needs to be fine tuned to match original implementation
Many things are left in a broken state like website features/api endpoints/lbp3 categories

* Fix release building

* Migrate scores, reviews, and more to new serialization system.
Many things are still broken but progress is steadily being made

* Fix Api responses and migrate serialization for most types

* Make serialization better and fix bugs
Fix recursive PrepareSerialization when recursive item is set during root item's PrepareSerialization, items, should be properly indexed in order but it's only tested to 1 level of recursion

* Fix review serialization

* Fix user serialization producing malformed SQL query

* Remove DefaultIfEmpty query

* MariaDB doesn't like double nested queries

* Fix LBP1 tag counter

* Implement lbp3 categories and add better deserialization handling

* Implement expression tree caching to speed up reflection and write new serializer tests

* Remove Game column from UserEntity and rename DatabaseContextModelSnapshot.cs back to DatabaseModelSnapshot.cs

* Make UserEntity username not required

* Fix recursive serialization of lists and add relevant unit tests

* Actually commit the migration

* Fix LocationTests to use new deserialization class

* Fix comments not serializing the right author username

* Replace all occurrences of StatusCode with their respective ASP.NET named result
instead of StatusCode(403) everything is now in the form of Forbid()

* Fix SlotBase.ConvertToEntity and LocationTests

* Fix compilation error

* Give Location a default value in GameUserSlot and GameUser

* Reimplement stubbed website functions

* Convert grief reports to new serialization system

* Update DatabaseModelSnapshot and bump dotnet tool version

* Remove unused directives

* Fix broken type reference

* Fix rated comments on website

* Don't include banned users in website comments

* Optimize score submission

* Fix slot id calculating in in-game comment posting

* Move serialization interfaces to types folder and add more documentation

* Allow uploading of versus scores
This commit is contained in:
Josh 2023-03-27 19:39:54 -05:00 committed by GitHub
commit 329ab66043
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
248 changed files with 4993 additions and 2896 deletions

View file

@ -22,10 +22,10 @@ public class AdminReportController : ControllerBase
[HttpGet("remove")]
public async Task<IActionResult> DeleteReport([FromRoute] int id)
{
User? user = this.database.UserFromWebRequest(this.Request);
if (user == null || !user.IsAdmin) return this.StatusCode(403, "");
UserEntity? user = this.database.UserFromWebRequest(this.Request);
if (user == null || !user.IsAdmin) return this.Forbid();
GriefReport? report = await this.database.Reports.FirstOrDefaultAsync(r => r.ReportId == id);
GriefReportEntity? report = await this.database.Reports.FirstOrDefaultAsync(r => r.ReportId == id);
if (report == null) return this.NotFound();
List<string> hashes = new()
@ -49,10 +49,10 @@ public class AdminReportController : ControllerBase
[HttpGet("dismiss")]
public async Task<IActionResult> DismissReport([FromRoute] int id)
{
User? user = this.database.UserFromWebRequest(this.Request);
if (user == null || !user.IsModerator) return this.StatusCode(403, "");
UserEntity? user = this.database.UserFromWebRequest(this.Request);
if (user == null || !user.IsModerator) return this.Forbid();
GriefReport? report = await this.database.Reports.FirstOrDefaultAsync(r => r.ReportId == id);
GriefReportEntity? report = await this.database.Reports.FirstOrDefaultAsync(r => r.ReportId == id);
if (report == null) return this.NotFound();
FileHelper.DeleteResource(report.JpegHash);

View file

@ -28,10 +28,10 @@ public class AdminUserController : ControllerBase
/// </summary>
[HttpGet("wipePlanets")]
public async Task<IActionResult> WipePlanets([FromRoute] int id) {
User? user = this.database.UserFromWebRequest(this.Request);
UserEntity? user = this.database.UserFromWebRequest(this.Request);
if (user == null || !user.IsModerator) return this.NotFound();
User? targetedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
UserEntity? targetedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
if (targetedUser == null) return this.NotFound();
string[] hashes = {
@ -47,7 +47,7 @@ public class AdminUserController : ControllerBase
if (string.IsNullOrWhiteSpace(hash)) continue;
// Find users with a matching hash
List<User> users = await this.database.Users
List<UserEntity> users = await this.database.Users
.Where(u => u.PlanetHashLBP2 == hash ||
u.PlanetHashLBP3 == hash ||
u.PlanetHashLBPVita == hash)
@ -57,7 +57,7 @@ public class AdminUserController : ControllerBase
System.Diagnostics.Debug.Assert(users.Count != 0);
// Reset each users' hash.
foreach (User userWithPlanet in users)
foreach (UserEntity userWithPlanet in users)
{
userWithPlanet.PlanetHashLBP2 = "";
userWithPlanet.PlanetHashLBP3 = "";
@ -92,10 +92,10 @@ public class AdminUserController : ControllerBase
[HttpPost("/admin/user/{id:int}/setPermissionLevel")]
public async Task<IActionResult> SetUserPermissionLevel([FromRoute] int id, [FromForm] PermissionLevel role)
{
User? user = this.database.UserFromWebRequest(this.Request);
UserEntity? user = this.database.UserFromWebRequest(this.Request);
if (user == null || !user.IsAdmin) return this.NotFound();
User? targetedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
UserEntity? targetedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
if (targetedUser == null) return this.NotFound();
if (role != PermissionLevel.Banned)

View file

@ -22,7 +22,7 @@ public class AuthenticationController : ControllerBase
[HttpGet("unlink/{platform}")]
public async Task<IActionResult> UnlinkPlatform(string platform)
{
User? user = this.database.UserFromWebRequest(this.Request);
UserEntity? user = this.database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");
Platform[] invalidTokens;
@ -48,10 +48,10 @@ public class AuthenticationController : ControllerBase
[HttpGet("approve/{id:int}")]
public async Task<IActionResult> Approve(int id)
{
User? user = this.database.UserFromWebRequest(this.Request);
UserEntity? user = this.database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("/login");
PlatformLinkAttempt? linkAttempt = await this.database.PlatformLinkAttempts
PlatformLinkAttemptEntity? linkAttempt = await this.database.PlatformLinkAttempts
.FirstOrDefaultAsync(l => l.PlatformLinkAttemptId == id);
if (linkAttempt == null) return this.NotFound();
@ -76,10 +76,10 @@ public class AuthenticationController : ControllerBase
[HttpGet("deny/{id:int}")]
public async Task<IActionResult> Deny(int id)
{
User? user = this.database.UserFromWebRequest(this.Request);
UserEntity? user = this.database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("/login");
PlatformLinkAttempt? linkAttempt = await this.database.PlatformLinkAttempts
PlatformLinkAttemptEntity? linkAttempt = await this.database.PlatformLinkAttempts
.FirstOrDefaultAsync(l => l.PlatformLinkAttemptId == id);
if (linkAttempt == null) return this.NotFound();

View file

@ -20,10 +20,10 @@ public class ModerationCaseController : ControllerBase
[HttpGet("dismiss")]
public async Task<IActionResult> DismissCase([FromRoute] int id)
{
User? user = this.database.UserFromWebRequest(this.Request);
if (user == null || !user.IsModerator) return this.StatusCode(403, "");
UserEntity? user = this.database.UserFromWebRequest(this.Request);
if (user == null || !user.IsModerator) return this.Forbid();
ModerationCase? @case = await this.database.Cases.FirstOrDefaultAsync(c => c.CaseId == id);
ModerationCaseEntity? @case = await this.database.Cases.FirstOrDefaultAsync(c => c.CaseId == id);
if (@case == null) return this.NotFound();
@case.DismissedAt = DateTime.Now;

View file

@ -1,6 +1,7 @@
using LBPUnion.ProjectLighthouse.Database;
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
using LBPUnion.ProjectLighthouse.Types.Serialization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
@ -17,9 +18,9 @@ public class ModerationRemovalController : ControllerBase
this.database = database;
}
private async Task<IActionResult> Delete<T>(DbSet<T> dbSet, int id, string? callbackUrl, Func<User, int, Task<T?>> getHandler) where T: class
private async Task<IActionResult> Delete<T>(DbSet<T> dbSet, int id, string? callbackUrl, Func<UserEntity, int, Task<T?>> getHandler) where T: class
{
User? user = this.database.UserFromWebRequest(this.Request);
UserEntity? user = this.database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");
T? item = await getHandler(user, id);
@ -34,9 +35,9 @@ public class ModerationRemovalController : ControllerBase
[HttpGet("deleteScore/{scoreId:int}")]
public async Task<IActionResult> DeleteScore(int scoreId, [FromQuery] string? callbackUrl)
{
return await this.Delete<Score>(this.database.Scores, scoreId, callbackUrl, async (user, id) =>
return await this.Delete<ScoreEntity>(this.database.Scores, scoreId, callbackUrl, async (user, id) =>
{
Score? score = await this.database.Scores.Include(s => s.Slot).FirstOrDefaultAsync(s => s.ScoreId == id);
ScoreEntity? score = await this.database.Scores.Include(s => s.Slot).FirstOrDefaultAsync(s => s.ScoreId == id);
if (score == null) return null;
return user.IsModerator ? score : null;
@ -46,10 +47,10 @@ public class ModerationRemovalController : ControllerBase
[HttpGet("deleteComment/{commentId:int}")]
public async Task<IActionResult> DeleteComment(int commentId, [FromQuery] string? callbackUrl)
{
User? user = this.database.UserFromWebRequest(this.Request);
UserEntity? user = this.database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");
Comment? comment = await this.database.Comments.FirstOrDefaultAsync(c => c.CommentId == commentId);
CommentEntity? comment = await this.database.Comments.FirstOrDefaultAsync(c => c.CommentId == commentId);
if (comment == null) return this.Redirect("~/404");
if (comment.Deleted) return this.Redirect(callbackUrl ?? "~/");
@ -82,10 +83,10 @@ public class ModerationRemovalController : ControllerBase
[HttpGet("deleteReview/{reviewId:int}")]
public async Task<IActionResult> DeleteReview(int reviewId, [FromQuery] string? callbackUrl)
{
User? user = this.database.UserFromWebRequest(this.Request);
UserEntity? user = this.database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");
Review? review = await this.database.Reviews.Include(r => r.Slot).FirstOrDefaultAsync(c => c.ReviewId == reviewId);
ReviewEntity? review = await this.database.Reviews.Include(r => r.Slot).FirstOrDefaultAsync(c => c.ReviewId == reviewId);
if (review == null) return this.Redirect("~/404");
if (review.Deleted) return this.Redirect(callbackUrl ?? "~/");
@ -103,9 +104,9 @@ public class ModerationRemovalController : ControllerBase
[HttpGet("deletePhoto/{photoId:int}")]
public async Task<IActionResult> DeletePhoto(int photoId, [FromQuery] string? callbackUrl)
{
return await this.Delete<Photo>(this.database.Photos, photoId, callbackUrl, async (user, id) =>
return await this.Delete<PhotoEntity>(this.database.Photos, photoId, callbackUrl, async (user, id) =>
{
Photo? photo = await this.database.Photos.Include(p => p.Slot).FirstOrDefaultAsync(p => p.PhotoId == id);
PhotoEntity? photo = await this.database.Photos.Include(p => p.Slot).FirstOrDefaultAsync(p => p.PhotoId == id);
if (photo == null) return null;
if (!user.IsModerator && photo.CreatorId != user.UserId) return null;

View file

@ -23,10 +23,10 @@ public class ModerationSlotController : ControllerBase
[HttpGet("teamPick")]
public async Task<IActionResult> TeamPick([FromRoute] int id)
{
User? user = this.database.UserFromWebRequest(this.Request);
if (user == null || !user.IsModerator) return this.StatusCode(403, "");
UserEntity? user = this.database.UserFromWebRequest(this.Request);
if (user == null || !user.IsModerator) return this.Forbid();
Slot? slot = await this.database.Slots.Include(s => s.Creator).FirstOrDefaultAsync(s => s.SlotId == id);
SlotEntity? slot = await this.database.Slots.Include(s => s.Creator).FirstOrDefaultAsync(s => s.SlotId == id);
if (slot == null) return this.NotFound();
slot.TeamPick = true;
@ -42,10 +42,10 @@ public class ModerationSlotController : ControllerBase
[HttpGet("removeTeamPick")]
public async Task<IActionResult> RemoveTeamPick([FromRoute] int id)
{
User? user = this.database.UserFromWebRequest(this.Request);
if (user == null || !user.IsModerator) return this.StatusCode(403, "");
UserEntity? user = this.database.UserFromWebRequest(this.Request);
if (user == null || !user.IsModerator) return this.Forbid();
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
if (slot == null) return this.NotFound();
slot.TeamPick = false;
@ -58,10 +58,10 @@ public class ModerationSlotController : ControllerBase
[HttpGet("delete")]
public async Task<IActionResult> DeleteLevel([FromRoute] int id)
{
User? user = this.database.UserFromWebRequest(this.Request);
if (user == null || !user.IsModerator) return this.StatusCode(403, "");
UserEntity? user = this.database.UserFromWebRequest(this.Request);
if (user == null || !user.IsModerator) return this.Forbid();
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
if (slot == null) return this.Ok();
await this.database.RemoveSlot(slot);

View file

@ -30,10 +30,10 @@ public class SlotPageController : ControllerBase
[HttpGet("unpublish")]
public async Task<IActionResult> UnpublishSlot([FromRoute] int id)
{
WebToken? token = this.database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("~/login");
Slot? targetSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
SlotEntity? targetSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
if (targetSlot == null) return this.Redirect("~/slots/0");
if (targetSlot.CreatorId != token.UserId) return this.Redirect("~/slot/" + id);
@ -48,7 +48,7 @@ public class SlotPageController : ControllerBase
[HttpGet("rateComment")]
public async Task<IActionResult> RateComment([FromRoute] int id, [FromQuery] int commentId, [FromQuery] int rating)
{
WebToken? token = this.database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("~/login");
await this.database.RateComment(token.UserId, commentId, rating);
@ -59,7 +59,7 @@ public class SlotPageController : ControllerBase
[HttpPost("postComment")]
public async Task<IActionResult> PostComment([FromRoute] int id, [FromForm] string? msg)
{
WebToken? token = this.database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("~/login");
if (msg == null)
@ -90,10 +90,10 @@ public class SlotPageController : ControllerBase
{
if (string.IsNullOrEmpty(callbackUrl)) callbackUrl = "~/slot/" + id;
WebToken? token = this.database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("~/login");
Slot? heartedSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
SlotEntity? heartedSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
if (heartedSlot == null) return this.NotFound();
await this.database.HeartLevel(token.UserId, heartedSlot);
@ -106,10 +106,10 @@ public class SlotPageController : ControllerBase
{
if (string.IsNullOrEmpty(callbackUrl)) callbackUrl = "~/slot/" + id;
WebToken? token = this.database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("~/login");
Slot? heartedSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
SlotEntity? heartedSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
if (heartedSlot == null) return this.NotFound();
await this.database.UnheartLevel(token.UserId, heartedSlot);
@ -122,10 +122,10 @@ public class SlotPageController : ControllerBase
{
if (string.IsNullOrEmpty(callbackUrl)) callbackUrl = "~/slot/" + id;
WebToken? token = this.database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("~/login");
Slot? queuedSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
SlotEntity? queuedSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
if (queuedSlot == null) return this.NotFound();
await this.database.QueueLevel(token.UserId, queuedSlot);
@ -138,10 +138,10 @@ public class SlotPageController : ControllerBase
{
if (string.IsNullOrEmpty(callbackUrl)) callbackUrl = "~/slot/" + id;
WebToken? token = this.database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("~/login");
Slot? queuedSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
SlotEntity? queuedSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
if (queuedSlot == null) return this.NotFound();
await this.database.UnqueueLevel(token.UserId, queuedSlot);

View file

@ -24,7 +24,7 @@ public class UserPageController : ControllerBase
[HttpGet("rateComment")]
public async Task<IActionResult> RateComment([FromRoute] int id, [FromQuery] int? commentId, [FromQuery] int? rating)
{
WebToken? token = this.database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("~/login");
await this.database.RateComment(token.UserId, commentId.GetValueOrDefault(), rating.GetValueOrDefault());
@ -35,7 +35,7 @@ public class UserPageController : ControllerBase
[HttpPost("postComment")]
public async Task<IActionResult> PostComment([FromRoute] int id, [FromForm] string? msg)
{
WebToken? token = this.database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("~/login");
if (msg == null)
@ -64,10 +64,10 @@ public class UserPageController : ControllerBase
[HttpGet("heart")]
public async Task<IActionResult> HeartUser([FromRoute] int id)
{
WebToken? token = this.database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("~/login");
User? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
UserEntity? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
if (heartedUser == null) return this.NotFound();
await this.database.HeartUser(token.UserId, heartedUser);
@ -78,10 +78,10 @@ public class UserPageController : ControllerBase
[HttpGet("unheart")]
public async Task<IActionResult> UnheartUser([FromRoute] int id)
{
WebToken? token = this.database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("~/login");
User? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
UserEntity? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
if (heartedUser == null) return this.NotFound();
await this.database.UnheartUser(token.UserId, heartedUser);
@ -92,10 +92,10 @@ public class UserPageController : ControllerBase
[HttpGet("block")]
public async Task<IActionResult> BlockUser([FromRoute] int id)
{
WebToken? token = this.database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("~/login");
User? blockedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
UserEntity? blockedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
if (blockedUser == null) return this.NotFound();
await this.database.BlockUser(token.UserId, blockedUser);
@ -106,10 +106,10 @@ public class UserPageController : ControllerBase
[HttpGet("unblock")]
public async Task<IActionResult> UnblockUser([FromRoute] int id)
{
WebToken? token = this.database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("~/login");
User? blockedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
UserEntity? blockedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
if (blockedUser == null) return this.NotFound();
await this.database.UnblockUser(token.UserId, blockedUser);

View file

@ -32,15 +32,15 @@ public static class PartialExtensions
}
}
public static Task<IHtmlContent> ToLink<T>(this User user, IHtmlHelper<T> helper, ViewDataDictionary<T> viewData, string language, string timeZone = "", bool includeStatus = false)
public static Task<IHtmlContent> ToLink<T>(this UserEntity user, IHtmlHelper<T> helper, ViewDataDictionary<T> viewData, string language, string timeZone = "", bool includeStatus = false)
=> helper.PartialAsync("Partials/Links/UserLinkPartial", user, viewData.WithLang(language).WithTime(timeZone).WithKeyValue("IncludeStatus", includeStatus));
public static Task<IHtmlContent> ToHtml<T>
(
this Slot slot,
this SlotEntity slot,
IHtmlHelper<T> helper,
ViewDataDictionary<T> viewData,
User? user,
UserEntity? user,
string callbackUrl,
string language = "",
string timeZone = "",
@ -55,6 +55,6 @@ public static class PartialExtensions
.WithKeyValue("IsMini", isMini)
.WithKeyValue("IsMobile", isMobile));
public static Task<IHtmlContent> ToHtml<T>(this Photo photo, IHtmlHelper<T> helper, ViewDataDictionary<T> viewData, string language, string timeZone, bool canDelete = false)
public static Task<IHtmlContent> ToHtml<T>(this PhotoEntity photo, IHtmlHelper<T> helper, ViewDataDictionary<T> viewData, string language, string timeZone, bool canDelete = false)
=> helper.PartialAsync("Partials/PhotoPartial", photo, viewData.WithLang(language).WithTime(timeZone).CanDelete(canDelete));
}

View file

@ -14,14 +14,14 @@ public class UserRequiredRedirectMiddleware : MiddlewareDBContext
public override async Task InvokeAsync(HttpContext ctx, DatabaseContext database)
{
WebToken? token = database.WebTokenFromRequest(ctx.Request);
WebTokenEntity? token = database.WebTokenFromRequest(ctx.Request);
if (token == null || pathContains(ctx, "/logout"))
{
await this.next(ctx);
return;
}
User? user = await database.Users.FirstOrDefaultAsync(u => u.UserId == token.UserId);
UserEntity? user = await database.Users.FirstOrDefaultAsync(u => u.UserId == token.UserId);
if (user == null)
{
await this.next(ctx);

View file

@ -38,7 +38,7 @@
}
<div class="ui four column grid">
@foreach (ApiKey key in Model.ApiKeys)
@foreach (ApiKeyEntity key in Model.ApiKeys)
{
<div id="keyitem-@key.Id" class="five wide column">
<div class="ui blue segment">

View file

@ -9,7 +9,7 @@ namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.Admin;
public class AdminApiKeyPageModel : BaseLayout
{
public List<ApiKey> ApiKeys = new();
public List<ApiKeyEntity> ApiKeys = new();
public int KeyCount;
public AdminApiKeyPageModel(DatabaseContext database) : base(database)
@ -17,7 +17,7 @@ public class AdminApiKeyPageModel : BaseLayout
public async Task<IActionResult> OnGet()
{
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");
if (!user.IsAdmin) return this.NotFound();
@ -29,10 +29,10 @@ public class AdminApiKeyPageModel : BaseLayout
public async Task<IActionResult> OnPost(string keyId)
{
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null || !user.IsAdmin) return this.NotFound();
ApiKey? apiKey = await this.Database.APIKeys.FirstOrDefaultAsync(k => k.Id == int.Parse(keyId));
ApiKeyEntity? apiKey = await this.Database.APIKeys.FirstOrDefaultAsync(k => k.Id == int.Parse(keyId));
if (apiKey == null) return this.NotFound();
this.Database.APIKeys.Remove(apiKey);
await this.Database.SaveChangesAsync();

View file

@ -24,7 +24,7 @@ public class AdminPanelPage : BaseLayout
public async Task<IActionResult> OnGet([FromQuery] string? args, [FromQuery] string? command, [FromQuery] string? maintenanceJob, [FromQuery] string? log)
{
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");
if (!user.IsAdmin) return this.NotFound();

View file

@ -12,7 +12,7 @@
<p><b>Note:</b> Users are ordered by their permissions, then by most-recent-first.</p>
<div class="ui grid">
@foreach (User user in Model.Users)
@foreach (UserEntity user in Model.Users)
{
string color;
string subtitle;

View file

@ -11,13 +11,13 @@ public class AdminPanelUsersPage : BaseLayout
{
public int UserCount;
public List<User> Users = new();
public List<UserEntity> Users = new();
public AdminPanelUsersPage(DatabaseContext database) : base(database)
{}
public async Task<IActionResult> OnGet()
{
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");
if (!user.IsAdmin) return this.NotFound();

View file

@ -12,11 +12,11 @@ public class AdminSetGrantedSlotsPage : BaseLayout
public AdminSetGrantedSlotsPage(DatabaseContext database) : base(database)
{}
public User? TargetedUser;
public UserEntity? TargetedUser;
public async Task<IActionResult> OnGet([FromRoute] int id)
{
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null || !user.IsAdmin) return this.NotFound();
this.TargetedUser = await this.Database.Users.FirstOrDefaultAsync(u => u.UserId == id);
@ -27,7 +27,7 @@ public class AdminSetGrantedSlotsPage : BaseLayout
public async Task<IActionResult> OnPost([FromRoute] int id, int grantedSlotCount)
{
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null || !user.IsAdmin) return this.NotFound();
this.TargetedUser = await this.Database.Users.FirstOrDefaultAsync(u => u.UserId == id);

View file

@ -81,7 +81,7 @@
}
<p>@room.PlayerIds.Count players, state is @room.State, version is @room.RoomVersion.ToPrettyString() on platform @room.RoomPlatform</p>
<p>Slot type: @room.Slot.SlotType, slot id: @room.Slot.SlotId</p>
@foreach (User player in room.GetPlayers(Model.Database))
@foreach (UserEntity player in room.GetPlayers(Model.Database))
{
<div class="ui segment">@player.Username</div>
}

View file

@ -17,7 +17,7 @@ public class RoomVisualizerPage : BaseLayout
public IActionResult OnGet()
{
#if !DEBUG
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null || !user.IsAdmin) return this.NotFound();
#endif

View file

@ -21,14 +21,14 @@ public class CompleteEmailVerificationPage : BaseLayout
{
if (!ServerConfiguration.Instance.Mail.MailEnabled) return this.NotFound();
EmailVerificationToken? emailVerifyToken = await this.Database.EmailVerificationTokens.FirstOrDefaultAsync(e => e.EmailToken == token);
EmailVerificationTokenEntity? emailVerifyToken = await this.Database.EmailVerificationTokens.FirstOrDefaultAsync(e => e.EmailToken == token);
if (emailVerifyToken == null)
{
this.Error = "Invalid verification token";
return this.Page();
}
User user = await this.Database.Users.FirstAsync(u => u.UserId == emailVerifyToken.UserId);
UserEntity user = await this.Database.Users.FirstAsync(u => u.UserId == emailVerifyToken.UserId);
if (DateTime.Now > emailVerifyToken.ExpiresAt)
{
@ -50,7 +50,7 @@ public class CompleteEmailVerificationPage : BaseLayout
if (user.Password != null) return this.Page();
// if user's account was created automatically
WebToken webToken = new()
WebTokenEntity webToken = new()
{
ExpiresAt = DateTime.Now.AddDays(7),
Verified = true,

View file

@ -19,7 +19,7 @@ public class SendVerificationEmailPage : BaseLayout
{
if (!ServerConfiguration.Instance.Mail.MailEnabled) return this.NotFound();
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("/login");
if (user.EmailAddressVerified) return this.Redirect("/");

View file

@ -22,7 +22,7 @@ public class SetEmailForm : BaseLayout
public IActionResult OnGet()
{
if (!ServerConfiguration.Instance.Mail.MailEnabled) return this.NotFound();
WebToken? token = this.Database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.Database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("/login");
return this.Page();
@ -33,10 +33,10 @@ public class SetEmailForm : BaseLayout
{
if (!ServerConfiguration.Instance.Mail.MailEnabled) return this.NotFound();
WebToken? token = this.Database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.Database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("~/login");
User? user = await this.Database.Users.FirstOrDefaultAsync(u => u.UserId == token.UserId);
UserEntity? user = await this.Database.Users.FirstOrDefaultAsync(u => u.UserId == token.UserId);
if (user == null) return this.Redirect("~/login");
if (!SanitizationHelper.IsValidEmail(emailAddress))

View file

@ -22,7 +22,7 @@ else
}
}
@foreach (PlatformLinkAttempt authAttempt in Model.LinkAttempts)
@foreach (PlatformLinkAttemptEntity authAttempt in Model.LinkAttempts)
{
DateTimeOffset timestamp = TimeZoneInfo.ConvertTime(DateTimeOffset.FromUnixTimeMilliseconds(authAttempt.Timestamp), timeZoneInfo);
<div class="ui red segment">

View file

@ -10,7 +10,7 @@ namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.ExternalAuth;
public class AuthenticationPage : BaseLayout
{
public List<PlatformLinkAttempt> LinkAttempts = new();
public List<PlatformLinkAttemptEntity> LinkAttempts = new();
public IPAddress? IpAddress;
public AuthenticationPage(DatabaseContext database) : base(database)
@ -18,7 +18,7 @@ public class AuthenticationPage : BaseLayout
public IActionResult OnGet()
{
if (this.User == null) return this.StatusCode(403, "");
if (this.User == null) return this.Forbid();
this.IpAddress = this.HttpContext.Connection.RemoteIpAddress;

View file

@ -46,7 +46,7 @@
@{
int i = 0;
foreach (User user in Model.PlayersOnline)
foreach (UserEntity user in Model.PlayersOnline)
{
i++;
@await user.ToLink(Html, ViewData, language, timeZone, true)
@ -66,7 +66,7 @@
<h1><i class="star icon"></i>@Model.Translate(LandingPageStrings.LatestTeamPicks)</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 *@
@foreach (SlotEntity slot in Model.LatestTeamPicks!) @* Can't reach a point where this is null *@
{
@await slot.ToHtml(Html, ViewData, Model.User, $"~/slot/{slot.SlotId}", language, timeZone, isMobile, true, true)
<br>
@ -83,7 +83,7 @@
<h1><i class="globe americas icon"></i>@Model.Translate(LandingPageStrings.NewestLevels)</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 *@
@foreach (SlotEntity slot in Model.NewestLevels!) @* Can't reach a point where this is null *@
{
@await slot.ToHtml(Html, ViewData, Model.User, $"~/slot/{slot.SlotId}", language, timeZone, isMobile, true, true)
<br>

View file

@ -17,15 +17,15 @@ public class LandingPage : BaseLayout
{}
public int PendingAuthAttempts;
public List<User> PlayersOnline = new();
public List<UserEntity> PlayersOnline = new();
public List<Slot>? LatestTeamPicks;
public List<Slot>? NewestLevels;
public List<SlotEntity>? LatestTeamPicks;
public List<SlotEntity>? NewestLevels;
[UsedImplicitly]
public async Task<IActionResult> OnGet()
{
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user != null && user.PasswordResetRequired) return this.Redirect("~/passwordResetRequired");
if (user != null)

View file

@ -25,7 +25,7 @@ public class BaseLayout : PageModel
public string Title = string.Empty;
private User? user;
private UserEntity? user;
public BaseLayout(DatabaseContext database)
{
this.Database = database;
@ -35,7 +35,7 @@ public class BaseLayout : PageModel
this.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderSlots, "/slots/0", "globe americas"));
}
public new User? User {
public new UserEntity? User {
get {
if (this.user != null) return this.user;

View file

@ -44,7 +44,7 @@ public class LoginForm : BaseLayout
return this.Page();
}
User? user;
UserEntity? user;
if (!ServerConfiguration.Instance.Mail.MailEnabled)
{
@ -55,7 +55,7 @@ public class LoginForm : BaseLayout
user = await this.Database.Users.FirstOrDefaultAsync(u => u.EmailAddress == username);
if (user == null)
{
User? noEmailUser = await this.Database.Users.FirstOrDefaultAsync(u => u.Username == username);
UserEntity? noEmailUser = await this.Database.Users.FirstOrDefaultAsync(u => u.Username == username);
if (noEmailUser != null && noEmailUser.EmailAddress == null) user = noEmailUser;
}
@ -86,7 +86,7 @@ public class LoginForm : BaseLayout
return this.Page();
}
WebToken webToken = new()
WebTokenEntity webToken = new()
{
UserId = user.UserId,
UserToken = CryptoHelper.GenerateAuthToken(),

View file

@ -12,7 +12,7 @@ public class LogoutPage : BaseLayout
{}
public async Task<IActionResult> OnGet()
{
WebToken? token = this.Database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.Database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("~/");
this.Database.WebTokens.Remove(token);

View file

@ -19,7 +19,7 @@ public class PasswordResetPage : BaseLayout
[UsedImplicitly]
public async Task<IActionResult> OnPost(string password, string confirmPassword)
{
User? user;
UserEntity? user;
if (this.Request.Query.ContainsKey("token"))
{
user = await this.Database.UserFromPasswordResetToken(this.Request.Query["token"][0]);
@ -63,7 +63,7 @@ public class PasswordResetPage : BaseLayout
{
if (this.Request.Query.ContainsKey("token")) return this.Page();
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");
return this.Page();

View file

@ -42,7 +42,7 @@ public class PasswordResetRequestForm : BaseLayout
return this.Page();
}
User? user = await this.Database.Users.FirstOrDefaultAsync(u => u.EmailAddress == email && u.EmailAddressVerified);
UserEntity? user = await this.Database.Users.FirstOrDefaultAsync(u => u.EmailAddress == email && u.EmailAddressVerified);
if (user == null)
{
@ -51,7 +51,7 @@ public class PasswordResetRequestForm : BaseLayout
return this.Page();
}
PasswordResetToken token = new()
PasswordResetTokenEntity token = new()
{
Created = DateTime.Now,
UserId = user.UserId,

View file

@ -15,7 +15,7 @@ public class PasswordResetRequiredPage : BaseLayout
public IActionResult OnGet()
{
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");
if (!user.PasswordResetRequired) return this.Redirect("~/passwordReset");

View file

@ -12,7 +12,7 @@ public class PirateSignupPage : BaseLayout
public IActionResult OnGet()
{
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("/login");
return this.Page();
@ -20,7 +20,7 @@ public class PirateSignupPage : BaseLayout
public async Task<IActionResult> OnPost()
{
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("/login");
user.Language = user.Language == "en-PT" ? "en" : "en-PT";

View file

@ -54,7 +54,7 @@ public class RegisterForm : BaseLayout
return this.Page();
}
User? existingUser = await this.Database.Users.FirstOrDefaultAsync(u => u.Username.ToLower() == username.ToLower());
UserEntity? existingUser = await this.Database.Users.FirstOrDefaultAsync(u => u.Username.ToLower() == username.ToLower());
if (existingUser != null)
{
this.Error = this.Translate(ErrorStrings.UsernameTaken);
@ -74,9 +74,9 @@ public class RegisterForm : BaseLayout
return this.Page();
}
User user = await this.Database.CreateUser(username, CryptoHelper.BCryptHash(password), emailAddress);
UserEntity user = await this.Database.CreateUser(username, CryptoHelper.BCryptHash(password), emailAddress);
WebToken webToken = new()
WebTokenEntity webToken = new()
{
UserId = user.UserId,
UserToken = CryptoHelper.GenerateAuthToken(),

View file

@ -12,7 +12,7 @@
<p>There are @Model.UserCount banned users.</p>
@foreach (User user in Model.Users)
@foreach (UserEntity user in Model.Users)
{
<div class="ui segment">
@await Html.PartialAsync("Partials/UserCardPartial", user, new ViewDataDictionary(ViewData)

View file

@ -13,7 +13,7 @@ public class BannedUsersPage : BaseLayout
public BannedUsersPage(DatabaseContext database) : base(database)
{}
public List<User> Users = new();
public List<UserEntity> Users = new();
public int PageAmount;
@ -23,7 +23,7 @@ public class BannedUsersPage : BaseLayout
public async Task<IActionResult> OnGet([FromRoute] int pageNumber, [FromQuery] string? name)
{
WebToken? token = this.Database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.Database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("/login");
this.Users = await this.Database.Users

View file

@ -21,7 +21,7 @@
<div class="ui divider"></div>
@foreach (ModerationCase @case in Model.Cases)
@foreach (ModerationCaseEntity @case in Model.Cases)
{
@(await Html.PartialAsync("Partials/ModerationCasePartial", @case, ViewData.WithTime(timeZone)))
}

View file

@ -13,7 +13,7 @@ public class CasePage : BaseLayout
public CasePage(DatabaseContext database) : base(database)
{}
public List<ModerationCase> Cases = new();
public List<ModerationCaseEntity> Cases = new();
public int CaseCount;
public int DismissedCaseCount;
@ -23,7 +23,7 @@ public class CasePage : BaseLayout
public async Task<IActionResult> OnGet([FromRoute] int pageNumber, [FromQuery] string? name)
{
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.NotFound();
if (!user.IsModerator) return this.NotFound();

View file

@ -15,7 +15,7 @@
<p>There are @Model.SlotCount hidden levels.</p>
@foreach (Slot slot in Model.Slots)
@foreach (SlotEntity slot in Model.Slots)
{
<div class="ui segment">
@await slot.ToHtml(Html, ViewData, Model.User, $"~/moderation/hiddenLevels/{Model.PageNumber}", language, timeZone, isMobile, true)

View file

@ -19,11 +19,11 @@ public class HiddenLevelsPage : BaseLayout
public int SlotCount;
public List<Slot> Slots = new();
public List<SlotEntity> Slots = new();
public async Task<IActionResult> OnGet([FromRoute] int pageNumber, [FromQuery] string? name)
{
WebToken? token = this.Database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.Database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("/login");
this.Slots = await this.Database.Slots

View file

@ -16,7 +16,7 @@ public class ModPanelPage : BaseLayout
public async Task<IActionResult> OnGet()
{
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");
if (!user.IsModerator) return this.NotFound();

View file

@ -17,7 +17,7 @@ public class NewCasePage : BaseLayout
public IActionResult OnGet([FromQuery] CaseType? type, [FromQuery] int? affectedId)
{
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null || !user.IsModerator) return this.Redirect("/login");
if (type == null) return this.BadRequest();
@ -31,7 +31,7 @@ public class NewCasePage : BaseLayout
public async Task<IActionResult> OnPost(CaseType? type, string? reason, string? modNotes, DateTime expires, int? affectedId)
{
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null || !user.IsModerator) return this.Redirect("/login");
if (type == null) return this.BadRequest();
@ -43,7 +43,7 @@ public class NewCasePage : BaseLayout
// if id is invalid then return bad request
if (!await type.Value.IsIdValid((int)affectedId, this.Database)) return this.BadRequest();
ModerationCase @case = new()
ModerationCaseEntity @case = new()
{
Type = type.Value,
Reason = reason,

View file

@ -14,15 +14,15 @@ public class ReportPage : BaseLayout
public ReportPage(DatabaseContext database) : base(database)
{}
public GriefReport Report = null!; // Report is not used if it's null in OnGet
public GriefReportEntity Report = null!; // Report is not used if it's null in OnGet
public async Task<IActionResult> OnGet([FromRoute] int reportId)
{
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");
if (!user.IsAdmin) return this.NotFound();
GriefReport? report = await this.Database.Reports
GriefReportEntity? report = await this.Database.Reports
.Include(r => r.ReportingPlayer)
.FirstOrDefaultAsync(r => r.ReportId == reportId);
if (report == null) return this.NotFound();

View file

@ -28,7 +28,7 @@
let images = [];
</script>
@foreach (GriefReport report in Model.Reports)
@foreach (GriefReportEntity report in Model.Reports)
{
@await Html.PartialAsync("Partials/ReportPartial", report, ViewData.WithTime(timeZone))
}

View file

@ -19,7 +19,7 @@ public class ReportsPage : BaseLayout
public int ReportCount;
public List<GriefReport> Reports = new();
public List<GriefReportEntity> Reports = new();
public string SearchValue = "";
@ -28,7 +28,7 @@ public class ReportsPage : BaseLayout
public async Task<IActionResult> OnGet([FromRoute] int pageNumber, [FromQuery] string? name)
{
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");
if (!user.IsModerator) return this.NotFound();
@ -51,7 +51,7 @@ public class ReportsPage : BaseLayout
.Take(ServerStatics.PageSize)
.ToListAsync();
foreach (GriefReport r in this.Reports)
foreach (GriefReportEntity r in this.Reports)
{
r.XmlPlayers = (ReportPlayer[]?)JsonSerializer.Deserialize(r.Players, typeof(ReportPlayer[])) ?? Array.Empty<ReportPlayer>();

View file

@ -1,4 +1,4 @@
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.User
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.UserEntity
<form method="post" action="/admin/user/@Model.UserId/setGrantedSlots">
@Html.AntiForgeryToken()

View file

@ -2,6 +2,7 @@
@using System.IO
@using LBPUnion.ProjectLighthouse.Localization
@using LBPUnion.ProjectLighthouse.Servers.Website.Extensions
@using LBPUnion.ProjectLighthouse.Types.Entities.Interaction
@using LBPUnion.ProjectLighthouse.Types.Entities.Profile
@{
@ -42,65 +43,70 @@
<div class="ui divider"></div>
}
}
@{
int i = 0;
foreach (KeyValuePair<CommentEntity, RatedCommentEntity?> commentAndReaction in Model.Comments)
{
CommentEntity comment = commentAndReaction.Key;
int yourThumb = commentAndReaction.Value?.Rating ?? 0;
DateTimeOffset timestamp = DateTimeOffset.FromUnixTimeSeconds(comment.Timestamp / 1000).ToLocalTime();
StringWriter messageWriter = new();
HttpUtility.HtmlDecode(comment.getComment(), messageWriter);
@for(int i = 0; i < Model.Comments.Count; i++)
{
Comment comment = Model.Comments[i];
DateTimeOffset timestamp = DateTimeOffset.FromUnixTimeSeconds(comment.Timestamp / 1000).ToLocalTime();
StringWriter messageWriter = new();
HttpUtility.HtmlDecode(comment.getComment(), messageWriter);
string decodedMessage = messageWriter.ToString();
string? url = Url.RouteUrl(ViewContext.RouteData.Values);
if (url == null) continue;
string decodedMessage = messageWriter.ToString();
string? url = Url.RouteUrl(ViewContext.RouteData.Values);
if (url == null) continue;
int rating = comment.ThumbsUp - comment.ThumbsDown;
int rating = comment.ThumbsUp - comment.ThumbsDown;
<div style="display: flex" id="@comment.CommentId">
@{
string style = "";
if (Model.User?.UserId == comment.PosterUserId)
{
style = "pointer-events: none";
<div style="display: flex" id="@comment.CommentId">
@{
string style = "";
if (Model.User?.UserId == comment.PosterUserId)
{
style = "pointer-events: none";
}
}
}
<div class="voting" style="@(style)">
<a href="@url/rateComment?commentId=@(comment.CommentId)&rating=@(comment.YourThumb == 1 ? 0 : 1)">
<i class="fitted @(comment.YourThumb == 1 ? "green" : "grey") arrow up link icon" style="display: block"></i>
</a>
<span style="text-align: center; margin: auto; @(rating < 0 ? "margin-left: -5px" : "")">@(rating)</span>
<a href="@url/rateComment?commentId=@(comment.CommentId)&rating=@(comment.YourThumb == -1 ? 0 : -1)">
<i class="fitted @(comment.YourThumb == -1 ? "red" : "grey") arrow down link icon" style="display: block"></i>
</a>
</div>
<div class="voting" style="@(style)">
<a href="@url/rateComment?commentId=@(comment.CommentId)&rating=@(yourThumb == 1 ? 0 : 1)">
<i class="fitted @(yourThumb == 1 ? "green" : "grey") arrow up link icon" style="display: block"></i>
</a>
<span style="text-align: center; margin: auto; @(rating < 0 ? "margin-left: -5px" : "")">@(rating)</span>
<a href="@url/rateComment?commentId=@(comment.CommentId)&rating=@(yourThumb == -1 ? 0 : -1)">
<i class="fitted @(yourThumb == -1 ? "red" : "grey") arrow down link icon" style="display: block"></i>
</a>
</div>
<div class="comment">
<b>@await comment.Poster.ToLink(Html, ViewData, language): </b>
@if (comment.Deleted)
{
<i>
<div class="comment">
<b>@await comment.Poster.ToLink(Html, ViewData, language): </b>
@if (comment.Deleted)
{
<i>
<span>@decodedMessage</span>
</i>
}
else
{
<span>@decodedMessage</span>
</i>
}
else
{
<span>@decodedMessage</span>
}
@if (((Model.User?.IsModerator ?? false) || Model.User?.UserId == comment.PosterUserId || Model.User?.UserId == pageOwnerId) && !comment.Deleted)
{
<button class="ui red icon button" style="display:inline-flex; float: right" onclick="deleteComment(@comment.CommentId)">
<i class="trash icon"></i>
</button>
}
<p>
<i>@TimeZoneInfo.ConvertTime(timestamp, timeZoneInfo).ToString("M/d/yyyy @ h:mm:ss tt")</i>
</p>
@if (i != Model.Comments.Count - 1)
{
<div class="ui divider"></div>
}
}
@if (((Model.User?.IsModerator ?? false) || Model.User?.UserId == comment.PosterUserId || Model.User?.UserId == pageOwnerId) && !comment.Deleted)
{
<button class="ui red icon button" style="display:inline-flex; float: right" onclick="deleteComment(@comment.CommentId)">
<i class="trash icon"></i>
</button>
}
<p>
<i>@TimeZoneInfo.ConvertTime(timestamp, timeZoneInfo).ToString("M/d/yyyy @ h:mm:ss tt")</i>
</p>
@if (i != Model.Comments.Count - 1)
{
<div class="ui divider"></div>
}
</div>
</div>
</div>
i++;
}
}
<script>
function deleteComment(commentId){

View file

@ -23,7 +23,7 @@
<div class="ui list">
@for(int i = 0; i < Model.Scores.Count; i++)
{
Score score = Model.Scores[i];
ScoreEntity score = Model.Scores[i];
string[] playerIds = score.PlayerIds;
DatabaseContext database = Model.Database;
<div class="item">
@ -41,7 +41,7 @@
<div class="list" style="padding-top: 0">
@for (int j = 0; j < playerIds.Length; j++)
{
User? user = await database.Users.FirstOrDefaultAsync(u => u.Username == playerIds[j]);
UserEntity? user = await database.Users.FirstOrDefaultAsync(u => u.Username == playerIds[j]);
<div class="item">
<i class="minus icon" style="padding-top: 9px"></i>
<div class="content" style="padding-left: 0">

View file

@ -1,12 +1,14 @@
@using LBPUnion.ProjectLighthouse.Database
@using LBPUnion.ProjectLighthouse.Localization
@using LBPUnion.ProjectLighthouse.Types.Users
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.User
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.UserEntity
@{
string language = (string?)ViewData["Language"] ?? LocalizationManager.DefaultLang;
string timeZone = (string?)ViewData["TimeZone"] ?? TimeZoneInfo.Local.Id;
bool includeStatus = (bool?)ViewData["IncludeStatus"] ?? false;
string userStatus = includeStatus ? Model.Status.ToTranslatedString(language, timeZone) : "";
await using DatabaseContext database = new();
string userStatus = includeStatus ? Model.GetStatus(database).ToTranslatedString(language, timeZone) : "";
}
<a href="/user/@Model.UserId" title="@userStatus" class="user-link">

View file

@ -3,7 +3,7 @@
@using LBPUnion.ProjectLighthouse.Types.Entities.Level
@using LBPUnion.ProjectLighthouse.Types.Entities.Profile
@using LBPUnion.ProjectLighthouse.Types.Moderation.Cases
@model LBPUnion.ProjectLighthouse.Types.Entities.Moderation.ModerationCase
@model LBPUnion.ProjectLighthouse.Types.Entities.Moderation.ModerationCaseEntity
@{
DatabaseContext database = new();
@ -62,7 +62,7 @@
@if (Model.Type.AffectsLevel())
{
Slot? 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>
@ -70,7 +70,7 @@
}
else if (Model.Type.AffectsUser())
{
User? 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>

View file

@ -3,7 +3,8 @@
@using LBPUnion.ProjectLighthouse.Servers.Website.Extensions
@using LBPUnion.ProjectLighthouse.Types.Entities.Profile
@using LBPUnion.ProjectLighthouse.Types.Levels
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.Photo
@using LBPUnion.ProjectLighthouse.Types.Serialization
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.PhotoEntity
@{
string language = (string?)ViewData["Language"] ?? LocalizationManager.DefaultLang;
@ -83,15 +84,17 @@
</p>
}
<div id="hover-subjects-@Model.PhotoId">
@foreach (PhotoSubject subject in Model.PhotoSubjects)
@foreach (PhotoSubjectEntity subject in Model.PhotoSubjects)
{
@await subject.User.ToLink(Html, ViewData, language, timeZone)
}
</div>
@{
PhotoSubject[] subjects = Model.PhotoSubjects.ToArray();
foreach (PhotoSubject subject in subjects) subject.Username = subject.User.Username;
GamePhotoSubject[] subjects = Model.PhotoSubjects.Select(GamePhotoSubject.CreateFromEntity).ToArray();
foreach (GamePhotoSubject subject in subjects)
{
subject.Username = Model.PhotoSubjects.Where(ps => ps.UserId == subject.UserId).Select(ps => ps.User.Username).First();
}
}
<script>

View file

@ -1,5 +1,5 @@
@using LBPUnion.ProjectLighthouse.Types.Moderation.Reports
@model LBPUnion.ProjectLighthouse.Types.Entities.Moderation.GriefReport
@model LBPUnion.ProjectLighthouse.Types.Entities.Moderation.GriefReportEntity
@{
string timeZone = (string?)ViewData["TimeZone"] ?? TimeZoneInfo.Local.Id;

View file

@ -3,6 +3,7 @@
@using LBPUnion.ProjectLighthouse.Files
@using LBPUnion.ProjectLighthouse.Helpers
@using LBPUnion.ProjectLighthouse.Types.Entities.Level
@using LBPUnion.ProjectLighthouse.Types.Serialization
@{
bool isMobile = (bool?)ViewData["IsMobile"] ?? false;
@ -30,7 +31,7 @@
@for(int i = 0; i < Model.Reviews.Count; i++)
{
Review review = Model.Reviews[i];
ReviewEntity review = Model.Reviews[i];
string faceHash = (review.Thumb switch {
-1 => review.Reviewer?.BooHash,
0 => review.Reviewer?.MehHash,

View file

@ -6,10 +6,10 @@
@using LBPUnion.ProjectLighthouse.Types.Entities.Profile
@using LBPUnion.ProjectLighthouse.Types.Users
@using Microsoft.EntityFrameworkCore
@model LBPUnion.ProjectLighthouse.Types.Entities.Level.Slot
@model LBPUnion.ProjectLighthouse.Types.Entities.Level.SlotEntity
@{
User? user = (User?)ViewData["User"];
UserEntity? user = (UserEntity?)ViewData["User"];
await using DatabaseContext database = new();

View file

@ -1,6 +1,7 @@
@using LBPUnion.ProjectLighthouse.Database
@using LBPUnion.ProjectLighthouse.Localization
@using LBPUnion.ProjectLighthouse.Types.Users
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.User
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.UserEntity
@{
bool showLink = (bool?)ViewData["ShowLink"] ?? false;
@ -40,14 +41,22 @@
}
</h1>
}
@{
await using DatabaseContext context = new();
int hearts = Model.GetHeartCount(context);
int comments = Model.GetCommentCount(context);
int levels = Model.GetUsedSlotCount(context);
int photos = Model.GetUploadedPhotoCount(context);
}
<span>
<i>@Model.Status.ToTranslatedString(language, timeZone)</i>
<i>@Model.GetStatus(context).ToTranslatedString(language, timeZone)</i>
</span>
<div class="cardStatsUnderTitle">
<i class="pink heart icon" title="Hearts"></i> <span>@Model.Hearts</span>
<i class="blue comment icon" title="Comments"></i> <span>@Model.Comments</span>
<i class="green upload icon" title="Uploaded Levels"></i><span>@Model.UsedSlots</span>
<i class="purple camera icon" title="Uploaded Photos"></i><span>@Model.PhotosByMe</span>
<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>
</div>
</div>
</div>

View file

@ -22,7 +22,7 @@
</form>
<div class="ui divider"></div>
@foreach (Photo photo in Model.Photos)
@foreach (PhotoEntity photo in Model.Photos)
{
bool canDelete = Model.User != null && (Model.User.IsModerator || Model.User.UserId == photo.CreatorId);
<div class="ui segment">

View file

@ -1,5 +1,4 @@
#nullable enable
using System.Text;
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.Database;
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
@ -18,7 +17,7 @@ public class PhotosPage : BaseLayout
public int PhotoCount;
public List<Photo> Photos = new();
public List<PhotoEntity> Photos = new();
public string? SearchValue;
public PhotosPage(DatabaseContext database) : base(database)
@ -28,7 +27,7 @@ public class PhotosPage : BaseLayout
{
if (string.IsNullOrWhiteSpace(name)) name = "";
IQueryable<Photo> photos = this.Database.Photos.Include(p => p.Creator)
IQueryable<PhotoEntity> photos = this.Database.Photos.Include(p => p.Creator)
.Include(p => p.PhotoSubjects)
.ThenInclude(ps => ps.User);

View file

@ -1,5 +1,6 @@
@page "/slot/{id:int}"
@using System.Web
@using LBPUnion.ProjectLighthouse.Database
@using LBPUnion.ProjectLighthouse.Extensions
@using LBPUnion.ProjectLighthouse.Helpers
@using LBPUnion.ProjectLighthouse.Localization.StringLists
@ -54,7 +55,7 @@
string[] authorLabels;
if (Model.Slot?.GameVersion == GameVersion.LittleBigPlanet1)
{
authorLabels = Model.Slot?.LevelTags ?? Array.Empty<string>();
authorLabels = Model.Slot.LevelTags(new DatabaseContext());
}
else
{
@ -119,7 +120,7 @@
@if (Model.Photos.Count != 0)
{
<div class="ui center aligned grid">
@foreach (Photo photo in Model.Photos)
@foreach (PhotoEntity photo in Model.Photos)
{
string width = isMobile ? "sixteen" : "eight";
bool canDelete = Model.User != null && (Model.User.IsModerator || Model.User.UserId == photo.CreatorId);

View file

@ -14,21 +14,21 @@ namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages;
public class SlotPage : BaseLayout
{
public List<Comment> Comments = new();
public List<Review> Reviews = new();
public List<Photo> Photos = new();
public List<Score> Scores = new();
public Dictionary<CommentEntity, RatedCommentEntity?> Comments = new();
public List<ReviewEntity> Reviews = new();
public List<PhotoEntity> Photos = new();
public List<ScoreEntity> Scores = new();
public bool CommentsEnabled;
public readonly bool ReviewsEnabled = ServerConfiguration.Instance.UserGeneratedContentLimits.LevelReviewsEnabled;
public Slot? Slot;
public SlotEntity? Slot;
public SlotPage(DatabaseContext database) : base(database)
{}
public async Task<IActionResult> OnGet([FromRoute] int id)
{
Slot? slot = await this.Database.Slots.Include(s => s.Creator)
SlotEntity? slot = await this.Database.Slots.Include(s => s.Creator)
.Where(s => s.Type == SlotType.User)
.FirstOrDefaultAsync(s => s.SlotId == id);
if (slot == null) return this.NotFound();
@ -75,12 +75,14 @@ public class SlotPage : BaseLayout
.OrderByDescending(p => p.Timestamp)
.Where(c => c.TargetId == id && c.Type == CommentType.Level)
.Where(c => !blockedUsers.Contains(c.PosterUserId))
.Include(c => c.Poster)
.Where(c => c.Poster.PermissionLevel != PermissionLevel.Banned)
.Take(50)
.ToListAsync();
.ToDictionaryAsync(c => c, _ => (RatedCommentEntity?)null);
}
else
{
this.Comments = new List<Comment>();
this.Comments = new Dictionary<CommentEntity, RatedCommentEntity?>();
}
if (this.ReviewsEnabled)
@ -95,7 +97,7 @@ public class SlotPage : BaseLayout
}
else
{
this.Reviews = new List<Review>();
this.Reviews = new List<ReviewEntity>();
}
this.Photos = await this.Database.Photos.Include(p => p.Creator)
@ -114,10 +116,10 @@ public class SlotPage : BaseLayout
if (this.User == null) return this.Page();
foreach (Comment c in this.Comments)
foreach (KeyValuePair<CommentEntity, RatedCommentEntity?> kvp in this.Comments)
{
Reaction? reaction = await this.Database.Reactions.FirstOrDefaultAsync(r => r.UserId == this.User.UserId && r.TargetId == c.CommentId);
if (reaction != null) c.YourThumb = reaction.Rating;
RatedCommentEntity? reaction = await this.Database.RatedComments.FirstOrDefaultAsync(r => r.UserId == this.User.UserId && r.CommentId == kvp.Key.CommentId);
this.Comments[kvp.Key] = reaction;
}
return this.Page();

View file

@ -12,7 +12,7 @@ namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages;
public class SlotSettingsPage : BaseLayout
{
public Slot? Slot;
public SlotEntity? Slot;
public SlotSettingsPage(DatabaseContext database) : base(database)
{}

View file

@ -24,7 +24,7 @@
</form>
<div class="ui divider"></div>
@foreach (Slot slot in Model.Slots)
@foreach (SlotEntity slot in Model.Slots)
{
<div class="ui segment">
@await slot.ToHtml(Html, ViewData, Model.User, $"~/slots/{Model.PageNumber}", language, timeZone, isMobile, true)

View file

@ -20,7 +20,7 @@ public class SlotsPage : BaseLayout
public int SlotCount;
public List<Slot> Slots = new();
public List<SlotEntity> Slots = new();
public string? SearchValue;
@ -57,7 +57,7 @@ public class SlotsPage : BaseLayout
string trimmedSearch = finalSearch.ToString().Trim();
IQueryable<Slot> slots = this.Database.Slots.Include(p => p.Creator)
IQueryable<SlotEntity> slots = this.Database.Slots.Include(p => p.Creator)
.Where(p => p.Type == SlotType.User && !p.Hidden)
.Where(p => p.Name.Contains(trimmedSearch))
.Where(p => p.Creator != null && (targetAuthor == null || string.Equals(p.Creator.Username.ToLower(), targetAuthor.ToLower())))

View file

@ -18,7 +18,7 @@ public class DisableTwoFactorPage : BaseLayout
{
if (!ServerConfiguration.Instance.TwoFactorConfiguration.TwoFactorEnabled) return this.Redirect("~/login");
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");
if (!user.IsTwoFactorSetup) return this.Redirect("~/user/" + user.UserId + "/settings");
@ -30,7 +30,7 @@ public class DisableTwoFactorPage : BaseLayout
{
if (!ServerConfiguration.Instance.TwoFactorConfiguration.TwoFactorEnabled) return this.Redirect("~/login");
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");
if (!user.IsTwoFactorSetup) return this.Redirect("~/user/" + user.UserId + "/settings");

View file

@ -31,7 +31,7 @@ public class SetupTwoFactorPage : BaseLayout
{
if (!ServerConfiguration.Instance.TwoFactorConfiguration.TwoFactorEnabled) return this.Redirect("~/login");
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");
if (user.IsTwoFactorSetup) return this.Redirect("~/");
@ -87,7 +87,7 @@ public class SetupTwoFactorPage : BaseLayout
return image.ToBase64String(PngFormat.Instance);
}
private static string getQrCode(User user)
private static string getQrCode(UserEntity user)
{
string instanceName = ServerConfiguration.Instance.Customization.ServerName;
string totpLink = CryptoHelper.GenerateTotpLink(user.TwoFactorSecret, HttpUtility.HtmlEncode(instanceName), user.Username);
@ -98,10 +98,10 @@ public class SetupTwoFactorPage : BaseLayout
{
if (!ServerConfiguration.Instance.TwoFactorConfiguration.TwoFactorEnabled) return this.Redirect("~/login");
WebToken? token = this.Database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.Database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("~/login");
User? user = this.Database.UserFromWebRequest(this.Request);
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");
if (user.IsTwoFactorSetup) return this.Redirect("~/");

View file

@ -22,14 +22,14 @@ public class TwoFactorLoginPage : BaseLayout
{
if (!ServerConfiguration.Instance.TwoFactorConfiguration.TwoFactorEnabled) return this.Redirect("~/login");
WebToken? token = this.Database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.Database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("~/login");
this.RedirectUrl = redirect ?? "~/";
if (token.Verified) return this.Redirect(this.RedirectUrl);
User? user = await this.Database.Users.Where(u => u.UserId == token.UserId).FirstOrDefaultAsync();
UserEntity? user = await this.Database.Users.Where(u => u.UserId == token.UserId).FirstOrDefaultAsync();
if (user == null) return this.Redirect("~/login");
if (user.IsTwoFactorSetup) return this.Page();
@ -43,14 +43,14 @@ public class TwoFactorLoginPage : BaseLayout
{
if (!ServerConfiguration.Instance.TwoFactorConfiguration.TwoFactorEnabled) return this.Redirect("~/login");
WebToken? token = this.Database.WebTokenFromRequest(this.Request);
WebTokenEntity? token = this.Database.WebTokenFromRequest(this.Request);
if (token == null) return this.Redirect("~/login");
this.RedirectUrl = redirect ?? "~/";
if (token.Verified) return this.Redirect(this.RedirectUrl);
User? user = await this.Database.Users.Where(u => u.UserId == token.UserId).FirstOrDefaultAsync();
UserEntity? user = await this.Database.Users.Where(u => u.UserId == token.UserId).FirstOrDefaultAsync();
if (user == null) return this.Redirect("~/login");
if (!user.IsTwoFactorSetup)

View file

@ -195,7 +195,7 @@
@if (Model.Photos != null && Model.Photos.Count != 0)
{
<div class="ui center aligned grid">
@foreach (Photo photo in Model.Photos)
@foreach (PhotoEntity photo in Model.Photos)
{
string width = isMobile ? "sixteen" : "eight";
bool canDelete = Model.User != null && (Model.User.IsModerator || Model.User.UserId == photo.CreatorId);
@ -221,7 +221,7 @@
{
<p>This user hasn't published any levels</p>
}
@foreach (Slot slot in Model.Slots ?? new List<Slot>())
@foreach (SlotEntity slot in Model.Slots ?? new List<SlotEntity>())
{
<div class="ui segment">
@await slot.ToHtml(Html, ViewData, Model.User, $"~/user/{Model.ProfileUser.UserId}#levels", language, timeZone, isMobile, true)
@ -246,7 +246,7 @@
{
<p>You have hearted @(Model.HeartedSlots?.Count) levels</p>
}
@foreach (Slot slot in Model.HeartedSlots ?? new List<Slot>())
@foreach (SlotEntity slot in Model.HeartedSlots ?? new List<SlotEntity>())
{
<div class="ui segment">
@await slot.ToHtml(Html, ViewData, Model.User, $"~/user/{Model.ProfileUser.UserId}#hearted", language, timeZone, isMobile, true)
@ -264,7 +264,7 @@
{
<p>There are @(Model.QueuedSlots?.Count) levels in your queue</p>
}
@foreach (Slot slot in Model.QueuedSlots ?? new List<Slot>())
@foreach (SlotEntity slot in Model.QueuedSlots ?? new List<SlotEntity>())
{
<div class="ui segment">
@await slot.ToHtml(Html, ViewData, Model.User, $"~/user/{Model.ProfileUser.UserId}#queued", language, timeZone, isMobile, true)

View file

@ -14,7 +14,7 @@ namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages;
public class UserPage : BaseLayout
{
public List<Comment>? Comments;
public Dictionary<CommentEntity, RatedCommentEntity?> Comments = new();
public bool CommentsEnabled;
@ -22,13 +22,13 @@ public class UserPage : BaseLayout
public bool IsProfileUserBlocked;
public List<Photo>? Photos;
public List<Slot>? Slots;
public List<PhotoEntity>? Photos;
public List<SlotEntity>? Slots;
public List<Slot>? HeartedSlots;
public List<Slot>? QueuedSlots;
public List<SlotEntity>? HeartedSlots;
public List<SlotEntity>? QueuedSlots;
public User? ProfileUser;
public UserEntity? ProfileUser;
public UserPage(DatabaseContext database) : base(database)
{}
@ -105,21 +105,21 @@ public class UserPage : BaseLayout
.Where(p => p.TargetId == userId && p.Type == CommentType.Profile)
.Where(p => !blockedUsers.Contains(p.PosterUserId))
.Take(50)
.ToListAsync();
.ToDictionaryAsync(c => c, _ => (RatedCommentEntity?) null);
}
else
{
this.Comments = new List<Comment>();
this.Comments = new Dictionary<CommentEntity, RatedCommentEntity?>();
}
if (this.User == null) return this.Page();
foreach (Comment c in this.Comments)
foreach (KeyValuePair<CommentEntity, RatedCommentEntity?> kvp in this.Comments)
{
Reaction? reaction = await this.Database.Reactions.Where(r => r.TargetId == c.TargetId)
RatedCommentEntity? reaction = await this.Database.RatedComments.Where(r => r.CommentId == kvp.Key.CommentId)
.Where(r => r.UserId == this.User.UserId)
.FirstOrDefaultAsync();
if (reaction != null) c.YourThumb = reaction.Rating;
this.Comments[kvp.Key] = reaction;
}
this.IsProfileUserHearted = await this.Database.HeartedProfiles

View file

@ -15,7 +15,7 @@ namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages;
public class UserSettingsPage : BaseLayout
{
public User? ProfileUser;
public UserEntity? ProfileUser;
public UserSettingsPage(DatabaseContext database) : base(database)
{}

View file

@ -20,7 +20,7 @@
</form>
<div class="ui divider"></div>
@foreach (User user in Model.Users)
@foreach (UserEntity user in Model.Users)
{
<div class="ui segment">
@await Html.PartialAsync("Partials/UserCardPartial", user, new ViewDataDictionary(ViewData)

View file

@ -17,7 +17,7 @@ public class UsersPage : BaseLayout
public int UserCount;
public List<User> Users = new();
public List<UserEntity> Users = new();
public string? SearchValue;