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

@ -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>();