From c0910e41081ebab0d0378f954e1b5e044dedfb40 Mon Sep 17 00:00:00 2001 From: Beyley Thomas Date: Thu, 25 Jul 2024 21:25:32 -0700 Subject: [PATCH] Create a backing database object for all fake users Realm does not let you compare against non-managed objects, so we need to make these objects managed by creating a backing user object. --- Refresh.Common/Constants/FakeUserConstants.cs | 9 +++ .../Database/GameDatabaseContext.Levels.cs | 6 +- .../Database/GameDatabaseContext.Users.cs | 57 ++++++++++++------- .../DataTypes/Response/GameLevelResponse.cs | 10 +--- 4 files changed, 51 insertions(+), 31 deletions(-) create mode 100644 Refresh.Common/Constants/FakeUserConstants.cs diff --git a/Refresh.Common/Constants/FakeUserConstants.cs b/Refresh.Common/Constants/FakeUserConstants.cs new file mode 100644 index 00000000..908d08f9 --- /dev/null +++ b/Refresh.Common/Constants/FakeUserConstants.cs @@ -0,0 +1,9 @@ +namespace Refresh.Common.Constants; + +public class FakeUserConstants +{ + public const char Prefix = '!'; + + public const string DeletedUserName = "!DeletedUser"; + public const string UnknownUserName = "!Unknown"; +} \ No newline at end of file diff --git a/Refresh.GameServer/Database/GameDatabaseContext.Levels.cs b/Refresh.GameServer/Database/GameDatabaseContext.Levels.cs index c968ac8c..6358828b 100644 --- a/Refresh.GameServer/Database/GameDatabaseContext.Levels.cs +++ b/Refresh.GameServer/Database/GameDatabaseContext.Levels.cs @@ -180,17 +180,17 @@ private IQueryable GetLevelsByGameVersion(TokenGame gameVersion) [Pure] public DatabaseList GetLevelsByUser(GameUser user, int count, int skip, LevelFilterSettings levelFilterSettings, GameUser? accessor) { - if (user.Username == DeletedUser.Username) + if (user.Username == FakeUserConstants.DeletedUserName) { return new DatabaseList(this.GetLevelsByGameVersion(levelFilterSettings.GameVersion).FilterByLevelFilterSettings(accessor, levelFilterSettings).Where(l => l.Publisher == null), skip, count); } - if (user.Username == "!Unknown") + if (user.Username == FakeUserConstants.UnknownUserName) { return new DatabaseList(this.GetLevelsByGameVersion(levelFilterSettings.GameVersion).FilterByLevelFilterSettings(null, levelFilterSettings).Where(l => l.IsReUpload && String.IsNullOrEmpty(l.OriginalPublisher)), skip, count); } - if (user.Username.StartsWith("!")) + if (user.Username.StartsWith(FakeUserConstants.Prefix)) { string withoutPrefix = user.Username[1..]; return new DatabaseList(this.GetLevelsByGameVersion(levelFilterSettings.GameVersion).FilterByLevelFilterSettings(accessor, levelFilterSettings).Where(l => l.OriginalPublisher == withoutPrefix), skip, count); diff --git a/Refresh.GameServer/Database/GameDatabaseContext.Users.cs b/Refresh.GameServer/Database/GameDatabaseContext.Users.cs index d0460b9c..f45aedb4 100644 --- a/Refresh.GameServer/Database/GameDatabaseContext.Users.cs +++ b/Refresh.GameServer/Database/GameDatabaseContext.Users.cs @@ -1,5 +1,6 @@ using JetBrains.Annotations; using MongoDB.Bson; +using Refresh.Common.Constants; using Refresh.GameServer.Authentication; using Refresh.GameServer.Endpoints.ApiV3.DataTypes.Request; using Refresh.GameServer.Types; @@ -13,32 +14,46 @@ namespace Refresh.GameServer.Database; public partial class GameDatabaseContext // Users { - private static readonly GameUser DeletedUser = new() - { - Username = "!DeletedUser", - Description = "I'm a fake user that represents deleted users for levels.", - FakeUser = true, - }; - [Pure] - [ContractAnnotation("null => null; notnull => canbenull")] + [ContractAnnotation("username:null => null; username:notnull => canbenull")] public GameUser? GetUserByUsername(string? username, bool caseSensitive = true) { - if (username == null) return null; - if (username == "!DeletedUser") - return DeletedUser; - if (username.StartsWith("!")) - return new() - { - Username = username, - Description = "I'm a fake user that represents a non existent publisher for re-published levels.", - FakeUser = true, - }; + if (username == null) + return null; + + // Try the first pass to get the user + GameUser? user = caseSensitive + ? this.GameUsers.FirstOrDefault(u => u.Username == username) + : this.GameUsers.FirstOrDefault(u => u.Username.Equals(username, StringComparison.OrdinalIgnoreCase)); - if (!caseSensitive) - return this.GameUsers.FirstOrDefault(u => u.Username.Equals(username, StringComparison.OrdinalIgnoreCase)); + // If that failed and the username is the deleted user, then we need to create the backing deleted user + if (username == FakeUserConstants.DeletedUserName && user == null) + { + this.Write(() => + { + this.GameUsers.Add(user = new GameUser + { + Username = FakeUserConstants.DeletedUserName, + Description = "I'm a fake user that represents deleted users for levels.", + FakeUser = true, + }); + }); + } + // If that failed and the username is a fake re-upload user, then we need to create the backing fake user + else if (username.StartsWith(FakeUserConstants.Prefix) && user == null) + { + this.Write(() => + { + this.GameUsers.Add(user = new GameUser + { + Username = username, + Description = "I'm a fake user that represents a non existent publisher for re-published levels.", + FakeUser = true, + }); + }); + } - return this.GameUsers.FirstOrDefault(u => u.Username == username); + return user; } [Pure] diff --git a/Refresh.GameServer/Endpoints/Game/DataTypes/Response/GameLevelResponse.cs b/Refresh.GameServer/Endpoints/Game/DataTypes/Response/GameLevelResponse.cs index c9b070a9..cb55ffd4 100644 --- a/Refresh.GameServer/Endpoints/Game/DataTypes/Response/GameLevelResponse.cs +++ b/Refresh.GameServer/Endpoints/Game/DataTypes/Response/GameLevelResponse.cs @@ -1,18 +1,14 @@ -using System.Diagnostics; using System.Xml.Serialization; -using Bunkum.Core.Storage; +using Refresh.Common.Constants; using Refresh.GameServer.Authentication; -using Refresh.GameServer.Database; using Refresh.GameServer.Endpoints.ApiV3.DataTypes; using Refresh.GameServer.Extensions; -using Refresh.GameServer.Services; using Refresh.GameServer.Types; using Refresh.GameServer.Types.Assets; using Refresh.GameServer.Types.Data; using Refresh.GameServer.Types.Levels; using Refresh.GameServer.Types.Levels.SkillRewards; using Refresh.GameServer.Types.Matching; -using Refresh.GameServer.Types.Relations; using Refresh.GameServer.Types.Reviews; using Refresh.GameServer.Types.UserData; @@ -190,8 +186,8 @@ public static GameLevelResponse FromHash(string hash, DataContext dataContext) publisher = "!DeletedUser"; else publisher = string.IsNullOrEmpty(old.OriginalPublisher) - ? "!Unknown" - : "!" + old.OriginalPublisher; + ? FakeUserConstants.UnknownUserName + : FakeUserConstants.Prefix + old.OriginalPublisher; response.Handle = new SerializedUserHandle {