Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
0b99031
Reports -> GameGriefReports
Toastbrot236 Oct 12, 2026
2ad92e5
Forgot to rename the file itself
Toastbrot236 Oct 12, 2026
6d0fbf0
Make grief report struct classes used for uploads follow naming rules
Toastbrot236 Oct 12, 2026
4e283ab
Minor grouping issue
Toastbrot236 Oct 12, 2026
21877f6
Compare entities referenced by grief reports by FK
Toastbrot236 Oct 12, 2026
f3da274
WHY WAS THIS REQUIRED?
Toastbrot236 Oct 12, 2026
1be64cd
Add username to ReportPlayerRelation, replace UserId with player numb…
Toastbrot236 Oct 13, 2026
0d7f513
Grief report upload's "levelType" is actually slot type, rename props…
Toastbrot236 Oct 13, 2026
bdfe3bd
Revert GameGriefReport.LevelType -> SlotType, it's also called LevelT…
Toastbrot236 Oct 13, 2026
fc620f9
Add DB migration for grief report stuff
Toastbrot236 Oct 13, 2026
922b4d5
Fix update migration SQL
Toastbrot236 Oct 13, 2026
ce54c7f
Minor update SQL improvement
Toastbrot236 Oct 13, 2026
0bbff60
Forgot to fix the typo in the other migration operations
Toastbrot236 Oct 13, 2026
ce2487a
Fix all ReportPlayerRelations.Timestamps being -infinity
Toastbrot236 Oct 13, 2026
2d106f5
Drop ReportPlayerRelation.Timestamp because unused and never set
Toastbrot236 Oct 13, 2026
33c73a3
Accidentally made GameGriefReport.ReviewedByUserId required, undo
Toastbrot236 Oct 17, 2026
5bf8a72
No unnecessary index bs, move table renames to end, drop PK before al…
Toastbrot236 Oct 17, 2026
2022cd3
Fix my update SQL to actually update player nums
Toastbrot236 Oct 17, 2026
105df3d
Fix ReportPlayerRelations rollback SQL
Toastbrot236 Oct 17, 2026
d6a2d20
Don't make ReviewedByUserId non-nullable again in the rollback
Toastbrot236 Oct 17, 2026
8c47d31
Forgot to drop username on rollback
Toastbrot236 Oct 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 20 additions & 21 deletions Refresh.Database/GameDatabaseContext.Reports.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Refresh.Database;

public partial class GameDatabaseContext // Reports
{
private IQueryable<GriefReport> ReportsIncluded => this.Reports
private IQueryable<GameGriefReport> GameGriefReportsIncluded => this.GameGriefReports
.Include(r => r.Reporter)
.Include(r => r.Reporter.Statistics)
.Include(r => r.Level)
Expand All @@ -16,20 +16,19 @@ public partial class GameDatabaseContext // Reports
.Include(r => r.ReviewedBy)
.Include(r => r.ReviewedBy!.Statistics)
.Include(r => r.Players)
.ThenInclude(p => p.User)
.Include(r => r.Players)
.ThenInclude(p => p.User.Statistics);
.ThenInclude(p => p.User!)
.ThenInclude(p => p.Statistics);

public void CreateReport(GriefReport griefReport)
public void CreateReport(GameGriefReport griefReport)
{
this.Write(() =>
{
griefReport.ReportDate = this._time.Now;
this.Reports.Add(griefReport);
this.GameGriefReports.Add(griefReport);
});
}

public void UpdateReportStatus(GriefReport griefReport, GriefReportStatus status, GameUser? reviewer = null, string? notes = null)
public void UpdateReportStatus(GameGriefReport griefReport, GriefReportStatus status, GameUser? reviewer = null, string? notes = null)
{
this.Write(() =>
{
Expand All @@ -40,41 +39,41 @@ public void UpdateReportStatus(GriefReport griefReport, GriefReportStatus status
});
}

public void RemoveReport(GriefReport griefReport)
public void RemoveReport(GameGriefReport griefReport)
{
this.Write(() =>
{
this.Reports.Remove(griefReport);
this.GameGriefReports.Remove(griefReport);
});
}

[Pure]
public GriefReport? GetReportById(int id) =>
this.ReportsIncluded.FirstOrDefault(r => r.ReportId == id);
public GameGriefReport? GetReportById(int id) =>
this.GameGriefReportsIncluded.FirstOrDefault(r => r.ReportId == id);

[Pure]
public DatabaseList<GriefReport> GetReportsByStatus(GriefReportStatus status, int count, int skip) =>
new(this.ReportsIncluded
public DatabaseList<GameGriefReport> GetReportsByStatus(GriefReportStatus status, int count, int skip) =>
new(this.GameGriefReportsIncluded
.Where(r => r.Status == status)
.OrderByDescending(r => r.ReportDate), skip, count);

[Pure]
public DatabaseList<GriefReport> GetReportsByReporter(GameUser reporter, int count, int skip) =>
new(this.ReportsIncluded
.Where(r => r.Reporter == reporter)
public DatabaseList<GameGriefReport> GetReportsByReporter(GameUser reporter, int count, int skip) =>
new(this.GameGriefReportsIncluded
.Where(r => r.ReporterUserId == reporter.UserId)
.OrderByDescending(r => r.ReportDate), skip, count);

[Pure]
public DatabaseList<GriefReport> GetReportsForLevel(GameLevel level, int count, int skip) =>
new(this.ReportsIncluded
.Where(r => r.Level == level)
public DatabaseList<GameGriefReport> GetReportsForLevel(GameLevel level, int count, int skip) =>
new(this.GameGriefReportsIncluded
.Where(r => r.LevelId == level.LevelId)
.OrderByDescending(r => r.ReportDate), skip, count);

[Pure]
public DatabaseList<GriefReport> GetStaleReports(TimeSpan maxAge, int count, int skip)
public DatabaseList<GameGriefReport> GetStaleReports(TimeSpan maxAge, int count, int skip)
{
DateTimeOffset cutoff = this._time.Now - maxAge;
return new(this.ReportsIncluded
return new(this.GameGriefReportsIncluded
.Where(r => r.Status == GriefReportStatus.Pending && r.ReportDate < cutoff)
.OrderBy(r => r.ReportDate), skip, count);
}
Expand Down
4 changes: 2 additions & 2 deletions Refresh.Database/GameDatabaseContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ public partial class GameDatabaseContext : DbContext, IDatabaseContext
internal DbSet<PinProgressRelation> PinProgressRelations { get; set; }
internal DbSet<ProfilePinRelation> ProfilePinRelations { get; set; }
internal DbSet<GameSkillReward> GameSkillRewards { get; set; }
internal DbSet<GriefReport> Reports { get; set; }
internal DbSet<ReportPlayerRelation> ReportPlayersRelations { get; set; }
internal DbSet<GameGriefReport> GameGriefReports { get; set; }
internal DbSet<ReportPlayerRelation> ReportPlayerRelations { get; set; }
internal DbSet<WorkerInfo> Workers { get; set; }
internal DbSet<PersistentJobState> JobStates { get; set; }
internal DbSet<GameLevelRevision> GameLevelRevisions { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace Refresh.Database.Migrations
{
/// <inheritdoc />
[DbContext(typeof(GameDatabaseContext))]
[Migration("20261013102558_MiscGriefReportQualityUpdates")]
public partial class MiscGriefReportQualityUpdates : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "PlayerRect",
table: "ReportPlayersRelations",
type: "text",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);

migrationBuilder.AddColumn<string>(
name: "Username",
table: "ReportPlayersRelations",
type: "text",
nullable: false,
defaultValue: "");

// ReportPlayerRelations PK changes (since we're altering UserId, which is part of PK at this point)

migrationBuilder.DropPrimaryKey(
name: "PK_ReportPlayersRelations",
table: "ReportPlayersRelations");

migrationBuilder.AlterColumn<string>(
name: "UserId",
table: "ReportPlayersRelations",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");

// (Re)init the player number column so we can ensure it only has unique values per report ID,
// so we can safely use it to replace UserId in the primary key
// https://stackoverflow.com/questions/65231516/add-and-update-a-column-with-sequential-numbering-based-on-grouping
migrationBuilder.Sql
("""
UPDATE "ReportPlayersRelations" SET "PlayerNumber" = u.newNum
FROM (
SELECT *, row_number() OVER (
PARTITION BY "ReportId"
ORDER BY "ReportId"
) AS newNum
FROM "ReportPlayersRelations"
) AS u
WHERE "ReportPlayersRelations"."ReportId" = u."ReportId"
AND "ReportPlayersRelations"."UserId" = u."UserId"
""");

migrationBuilder.AddPrimaryKey(
name: "PK_ReportPlayerRelations",
table: "ReportPlayersRelations",
columns: new[] { "ReportId", "PlayerNumber" });

// Doing this in the middle caused random issues with the following DB commands,
// so rename the tables after everything.

migrationBuilder.RenameTable(
name: "Reports",
newName: "GameGriefReports");

// thank you for this typo smh
migrationBuilder.RenameTable(
name: "ReportPlayersRelations",
newName: "ReportPlayerRelations");
}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{

migrationBuilder.AlterColumn<string>(
name: "UserId",
table: "ReportPlayerRelations",
type: "text",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);

migrationBuilder.AlterColumn<string>(
name: "PlayerRect",
table: "ReportPlayerRelations",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");

migrationBuilder.DropColumn(
name: "Username",
table: "ReportPlayerRelations");

// Just remove all with duplicate user IDs. Usually we won't have duplicate IDs anyway,
// but we should ensure we don't anyway; also, this should be enough for a rollback on this,
// better than dropping the whole table or something.
// We can just use PlayerNumber to uniquely identify rows per ReportId, that and ReportId
// are the only PK attributes after the update above.
migrationBuilder.Sql
("""
DELETE FROM "ReportPlayerRelations"
USING (
SELECT min ("PlayerNumber") as keepNumber, "ReportId", "UserId"
FROM "ReportPlayerRelations"
GROUP BY "UserId", "ReportId"
) AS d
WHERE "PlayerNumber" != d.keepNumber
AND "ReportPlayerRelations"."ReportId" = d."ReportId"
AND "ReportPlayerRelations"."UserId" = d."UserId"
""");

migrationBuilder.DropPrimaryKey(
name: "PK_ReportPlayerRelations",
table: "ReportPlayerRelations");

migrationBuilder.AddPrimaryKey(
name: "PK_ReportPlayersRelations",
table: "ReportPlayerRelations",
columns: new[] { "ReportId", "UserId" });

migrationBuilder.RenameTable(
name: "GameGriefReports",
newName: "Reports");

migrationBuilder.RenameTable(
name: "ReportPlayerRelations",
newName: "ReportPlayersRelations");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace Refresh.Database.Migrations
{
/// <inheritdoc />
[DbContext(typeof(GameDatabaseContext))]
[Migration("20261013122831_DropReportPlayerRelationTimestamp")]
public partial class DropReportPlayerRelationTimestamp : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
// This column had no setters at all, meaning all rows had this set to -infinity.
// The report uploads also don't actually contain any player-specific timestamps,
// so this is safe to drop.
migrationBuilder.DropColumn(
name: "Timestamp",
table: "ReportPlayerRelations");
}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTimeOffset>(
name: "Timestamp",
table: "ReportPlayerRelations",
type: "timestamp with time zone",
nullable: false,
defaultValue: new DateTimeOffset(2026, 1, 1, 0, 0, 0, TimeSpan.Zero));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace Refresh.Database.Migrations
{
/// <inheritdoc />
[DbContext(typeof(GameDatabaseContext))]
[Migration("20261017093718_MakeReviewedByUserIdNotRequiredAgain")]
public partial class MakeReviewedByUserIdNotRequiredAgain : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "ReviewedByUserId",
table: "GameGriefReports",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");
}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
// Nothing needed, just leave it at null since we already want it like that, else SQL exception
}
}
}
Loading
Loading