Fix admin notes and database time nonsense. (#25280)

God bloody christ. There's like three layers of shit here.

So firstly, apparently we were still using Npgsql.EnableLegacyTimestampBehavior. This means that time values (which are stored UTC in the database) were converted to local time when read out. This meant they were passed around as kind Local to clients (instead of UTC in the case of SQLite). That's easy enough to fix just turn off the flag and fix the couple spots we're passing a local DateTime ez.

Oh but it turns out there's a DIFFERENT problem with SQLite: See SQLite we definitely store the DateTimes as UTC, but when Microsoft.Data.Sqlite reads them it reads them as Kind Unspecified instead of Utc.

Why are these so bad? Because the admin notes system passes DateTime instances from EF Core straight to the rest of the game code. And that means it's a PAIN IN THE ASS to run the necessary conversions to fix the DateTime instances. GOD DAMNIT now I have to make a whole new set of "Record" entities so we avoid leaking the EF Core model entities. WAAAAAAA.

Fixes #19897
This commit is contained in:
Pieter-Jan Briers
2024-02-20 10:13:31 +01:00
committed by GitHub
parent 2907e84b6f
commit 2e6eaa45c5
19 changed files with 501 additions and 326 deletions

View File

@@ -1,4 +1,3 @@
using System.Diagnostics;
using Content.Server.Database;
using Content.Shared.Administration.Notes;
using Content.Shared.Database;
@@ -7,7 +6,7 @@ namespace Content.Server.Administration.Notes;
public static class AdminNotesExtensions
{
public static SharedAdminNote ToShared(this IAdminRemarksCommon note)
public static SharedAdminNote ToShared(this IAdminRemarksRecord note)
{
NoteSeverity? severity = null;
var secret = false;
@@ -18,26 +17,26 @@ public static class AdminNotesExtensions
bool? seen = null;
switch (note)
{
case AdminNote adminNote:
case AdminNoteRecord adminNote:
type = NoteType.Note;
severity = adminNote.Severity;
secret = adminNote.Secret;
break;
case AdminWatchlist:
case AdminWatchlistRecord:
type = NoteType.Watchlist;
secret = true;
break;
case AdminMessage adminMessage:
case AdminMessageRecord adminMessage:
type = NoteType.Message;
seen = adminMessage.Seen;
break;
case ServerBanNote ban:
case ServerBanNoteRecord ban:
type = NoteType.ServerBan;
severity = ban.Severity;
unbannedTime = ban.UnbanTime;
unbannedByName = ban.UnbanningAdmin?.LastSeenUserName ?? Loc.GetString("system-user");
break;
case ServerRoleBanNote roleBan:
case ServerRoleBanNoteRecord roleBan:
type = NoteType.RoleBan;
severity = roleBan.Severity;
bannedRoles = roleBan.Roles;
@@ -49,12 +48,13 @@ public static class AdminNotesExtensions
}
// There may be bans without a user, but why would we ever be converting them to shared notes?
if (note.PlayerUserId is null)
throw new ArgumentNullException(nameof(note.PlayerUserId), "Player user ID cannot be null for a note");
if (note.Player is null)
throw new ArgumentNullException(nameof(note), "Player user ID cannot be null for a note");
return new SharedAdminNote(
note.Id,
note.PlayerUserId.Value,
note.RoundId,
note.Player!.UserId,
note.Round?.Id,
note.Round?.Server.Name,
note.PlaytimeAtNote,
type,
@@ -63,9 +63,9 @@ public static class AdminNotesExtensions
secret,
note.CreatedBy?.LastSeenUserName ?? Loc.GetString("system-user"),
note.LastEditedBy?.LastSeenUserName ?? string.Empty,
note.CreatedAt,
note.LastEditedAt,
note.ExpirationTime,
note.CreatedAt.UtcDateTime,
note.LastEditedAt?.UtcDateTime,
note.ExpirationTime?.UtcDateTime,
bannedRoles,
unbannedTime,
unbannedByName,