From 14a291a1fe72b58e707a066da64e4277f8f88afe Mon Sep 17 00:00:00 2001 From: jvyden Date: Sat, 10 Aug 2024 19:34:18 -0400 Subject: [PATCH] Refactor constants in `Refresh.Common` Applied better naming, brought in some variables, applied them to some areas where they weren't used, etc. --- Refresh.Common/Constants/FakeUserConstants.cs | 9 ------ Refresh.Common/Constants/SystemUsers.cs | 20 +++++++++++++ .../{UgcConstantLimits.cs => UgcLimits.cs} | 6 +++- .../Database/GameDatabaseContext.Levels.cs | 30 +++++++++---------- .../Database/GameDatabaseContext.Users.cs | 10 +++---- .../DataTypes/Response/GameLevelResponse.cs | 6 ++-- .../DataTypes/Response/GameUserResponse.cs | 21 +++++++------ .../Endpoints/Game/Levels/PublishEndpoints.cs | 8 ++--- .../Endpoints/Game/UserEndpoints.cs | 6 ++-- .../Tests/Levels/PublishEndpointsTests.cs | 8 ++--- 10 files changed, 69 insertions(+), 55 deletions(-) delete mode 100644 Refresh.Common/Constants/FakeUserConstants.cs create mode 100644 Refresh.Common/Constants/SystemUsers.cs rename Refresh.Common/Constants/{UgcConstantLimits.cs => UgcLimits.cs} (51%) diff --git a/Refresh.Common/Constants/FakeUserConstants.cs b/Refresh.Common/Constants/FakeUserConstants.cs deleted file mode 100644 index 908d08f9..00000000 --- a/Refresh.Common/Constants/FakeUserConstants.cs +++ /dev/null @@ -1,9 +0,0 @@ -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.Common/Constants/SystemUsers.cs b/Refresh.Common/Constants/SystemUsers.cs new file mode 100644 index 00000000..7666ae20 --- /dev/null +++ b/Refresh.Common/Constants/SystemUsers.cs @@ -0,0 +1,20 @@ +namespace Refresh.Common.Constants; + +public static class SystemUsers +{ + /// + /// A system user represents a user that doesn't technically exist. (well, it does for now until postgres or something) + /// This can be used for levels belonging to users who have deleted their accounts, or for re-uploads. + /// + public const char SystemPrefix = '!'; + /// + /// Reserved for clans. https://github.com/LittleBigRefresh/Refresh/issues/77 + /// + public const char ClanPrefix = '$'; + + public const string DeletedUserName = "!DeletedUser"; + public const string DeletedUserDescription = "I'm a fake user that represents deleted users for levels."; + + public const string UnknownUserName = "!Unknown"; + public const string UnknownUserDescription = "I'm a fake user that represents a non existent publisher for re-published levels."; +} \ No newline at end of file diff --git a/Refresh.Common/Constants/UgcConstantLimits.cs b/Refresh.Common/Constants/UgcLimits.cs similarity index 51% rename from Refresh.Common/Constants/UgcConstantLimits.cs rename to Refresh.Common/Constants/UgcLimits.cs index edba0f84..bab1cdb7 100644 --- a/Refresh.Common/Constants/UgcConstantLimits.cs +++ b/Refresh.Common/Constants/UgcLimits.cs @@ -1,7 +1,11 @@ namespace Refresh.Common.Constants; -public static class UgcConstantLimits +public static class UgcLimits { + // Object limits + public const int MaximumLevels = 9_999; + + // String limits public const int TitleLimit = 64; public const int DescriptionLimit = 512; } \ No newline at end of file diff --git a/Refresh.GameServer/Database/GameDatabaseContext.Levels.cs b/Refresh.GameServer/Database/GameDatabaseContext.Levels.cs index 0fc65aad..b2a79cd4 100644 --- a/Refresh.GameServer/Database/GameDatabaseContext.Levels.cs +++ b/Refresh.GameServer/Database/GameDatabaseContext.Levels.cs @@ -22,11 +22,11 @@ public partial class GameDatabaseContext // Levels { public bool AddLevel(GameLevel level) { - if (level.Title is { Length: > UgcConstantLimits.TitleLimit }) - level.Title = level.Title[..UgcConstantLimits.TitleLimit]; + if (level.Title is { Length: > UgcLimits.TitleLimit }) + level.Title = level.Title[..UgcLimits.TitleLimit]; - if (level.Description is { Length: > UgcConstantLimits.DescriptionLimit }) - level.Description = level.Description[..UgcConstantLimits.DescriptionLimit]; + if (level.Description is { Length: > UgcLimits.DescriptionLimit }) + level.Description = level.Description[..UgcLimits.DescriptionLimit]; if (level.Publisher == null) throw new InvalidOperationException("Cannot create a level without a publisher"); @@ -68,11 +68,11 @@ public GameLevel GetStoryLevelById(int id) public GameLevel? UpdateLevel(GameLevel newLevel, GameUser author) { - if (newLevel.Title is { Length: > UgcConstantLimits.TitleLimit }) - newLevel.Title = newLevel.Title[..UgcConstantLimits.TitleLimit]; + if (newLevel.Title is { Length: > UgcLimits.TitleLimit }) + newLevel.Title = newLevel.Title[..UgcLimits.TitleLimit]; - if (newLevel.Description is { Length: > UgcConstantLimits.DescriptionLimit }) - newLevel.Description = newLevel.Description[..UgcConstantLimits.DescriptionLimit]; + if (newLevel.Description is { Length: > UgcLimits.DescriptionLimit }) + newLevel.Description = newLevel.Description[..UgcLimits.DescriptionLimit]; // Verify if this level is able to be republished GameLevel? oldLevel = this.GetLevelById(newLevel.LevelId); @@ -111,11 +111,11 @@ public GameLevel GetStoryLevelById(int id) public GameLevel? UpdateLevel(ApiEditLevelRequest body, GameLevel level) { - if (body.Title is { Length: > UgcConstantLimits.TitleLimit }) - body.Title = body.Title[..UgcConstantLimits.TitleLimit]; + if (body.Title is { Length: > UgcLimits.TitleLimit }) + body.Title = body.Title[..UgcLimits.TitleLimit]; - if (body.Description is { Length: > UgcConstantLimits.DescriptionLimit }) - body.Description = body.Description[..UgcConstantLimits.DescriptionLimit]; + if (body.Description is { Length: > UgcLimits.DescriptionLimit }) + body.Description = body.Description[..UgcLimits.DescriptionLimit]; this.Write(() => { @@ -181,17 +181,17 @@ private IQueryable GetLevelsByGameVersion(TokenGame gameVersion) [Pure] public DatabaseList GetLevelsByUser(GameUser user, int count, int skip, LevelFilterSettings levelFilterSettings, GameUser? accessor) { - if (user.Username == FakeUserConstants.DeletedUserName) + if (user.Username == SystemUsers.DeletedUserName) { return new DatabaseList(this.GetLevelsByGameVersion(levelFilterSettings.GameVersion).FilterByLevelFilterSettings(accessor, levelFilterSettings).Where(l => l.Publisher == null), skip, count); } - if (user.Username == FakeUserConstants.UnknownUserName) + if (user.Username == SystemUsers.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(FakeUserConstants.Prefix)) + if (user.Username.StartsWith(SystemUsers.SystemPrefix)) { 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 9f2f5ef2..42bfa0bc 100644 --- a/Refresh.GameServer/Database/GameDatabaseContext.Users.cs +++ b/Refresh.GameServer/Database/GameDatabaseContext.Users.cs @@ -27,27 +27,27 @@ public partial class GameDatabaseContext // Users : 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) + if (username == SystemUsers.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.", + Username = SystemUsers.DeletedUserName, + Description = SystemUsers.DeletedUserDescription, 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) + else if (username.StartsWith(SystemUsers.SystemPrefix) && 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.", + Description = SystemUsers.UnknownUserDescription, FakeUser = true, }); }); diff --git a/Refresh.GameServer/Endpoints/Game/DataTypes/Response/GameLevelResponse.cs b/Refresh.GameServer/Endpoints/Game/DataTypes/Response/GameLevelResponse.cs index 05f09ff7..0a207923 100644 --- a/Refresh.GameServer/Endpoints/Game/DataTypes/Response/GameLevelResponse.cs +++ b/Refresh.GameServer/Endpoints/Game/DataTypes/Response/GameLevelResponse.cs @@ -187,11 +187,11 @@ public static GameLevelResponse FromHash(string hash, DataContext dataContext) { string publisher; if (!old.IsReUpload) - publisher = FakeUserConstants.DeletedUserName; + publisher = SystemUsers.DeletedUserName; else publisher = string.IsNullOrEmpty(old.OriginalPublisher) - ? FakeUserConstants.UnknownUserName - : FakeUserConstants.Prefix + old.OriginalPublisher; + ? SystemUsers.UnknownUserName + : SystemUsers.SystemPrefix + old.OriginalPublisher; response.Handle = new SerializedUserHandle { diff --git a/Refresh.GameServer/Endpoints/Game/DataTypes/Response/GameUserResponse.cs b/Refresh.GameServer/Endpoints/Game/DataTypes/Response/GameUserResponse.cs index 2f72d91e..0d6d9b78 100644 --- a/Refresh.GameServer/Endpoints/Game/DataTypes/Response/GameUserResponse.cs +++ b/Refresh.GameServer/Endpoints/Game/DataTypes/Response/GameUserResponse.cs @@ -1,4 +1,5 @@ using System.Xml.Serialization; +using Refresh.Common.Constants; using Refresh.GameServer.Authentication; using Refresh.GameServer.Endpoints.ApiV3.DataTypes; using Refresh.GameServer.Endpoints.Game.Levels.FilterSettings; @@ -13,8 +14,6 @@ namespace Refresh.GameServer.Endpoints.Game.DataTypes.Response; [XmlRoot("user")] public class GameUserResponse : IDataConvertableFrom { - public const int MaximumLevels = 9_999; - [XmlAttribute("type")] public string Type { get; set; } = "user"; [XmlElement("biography")] public required string Description { get; set; } [XmlElement("location")] public required GameLocation Location { get; set; } @@ -72,9 +71,9 @@ public class GameUserResponse : IDataConvertableFrom PhotosByMeCount = old.IsManaged ? dataContext.Database.GetTotalPhotosByUser(old) : 0, PhotosWithMeCount = old.IsManaged ? dataContext.Database.GetTotalPhotosWithUser(old) : 0, - EntitledSlots = MaximumLevels, - EntitledSlotsLBP2 = MaximumLevels, - EntitledSlotsLBP3 = MaximumLevels, + EntitledSlots = UgcLimits.MaximumLevels, + EntitledSlotsLBP2 = UgcLimits.MaximumLevels, + EntitledSlotsLBP3 = UgcLimits.MaximumLevels, UsedSlots = 0, UsedSlotsLBP2 = 0, UsedSlotsLBP3 = 0, @@ -110,21 +109,21 @@ public class GameUserResponse : IDataConvertableFrom case TokenGame.LittleBigPlanet3: { //Match all LBP3 levels response.UsedSlotsLBP3 = dataContext.Database.GetTotalLevelsPublishedByUser(old, TokenGame.LittleBigPlanet3); - response.FreeSlotsLBP3 = MaximumLevels - response.UsedSlotsLBP3; + response.FreeSlotsLBP3 = UgcLimits.MaximumLevels - response.UsedSlotsLBP3; //Fill out LBP2/LBP1 levels goto case TokenGame.LittleBigPlanet2; } case TokenGame.LittleBigPlanet2: { //Match all LBP2 levels response.UsedSlotsLBP2 = dataContext.Database.GetTotalLevelsPublishedByUser(old, TokenGame.LittleBigPlanet2); - response.FreeSlotsLBP2 = MaximumLevels - response.UsedSlotsLBP2; + response.FreeSlotsLBP2 = UgcLimits.MaximumLevels - response.UsedSlotsLBP2; //Fill out LBP1 levels goto case TokenGame.LittleBigPlanet1; } case TokenGame.LittleBigPlanetVita: { //Match all LBP Vita levels response.UsedSlotsLBP2 = dataContext.Database.GetTotalLevelsPublishedByUser(old, TokenGame.LittleBigPlanetVita); - response.FreeSlotsLBP2 = MaximumLevels - response.UsedSlotsLBP2; + response.FreeSlotsLBP2 = UgcLimits.MaximumLevels - response.UsedSlotsLBP2; //Apply Vita-specific icon hash response.Handle.IconHash = old.VitaIconHash; @@ -133,13 +132,13 @@ public class GameUserResponse : IDataConvertableFrom case TokenGame.LittleBigPlanet1: { //Match all LBP1 levels response.UsedSlots = dataContext.Database.GetTotalLevelsPublishedByUser(old, TokenGame.LittleBigPlanet1); - response.FreeSlots = MaximumLevels - response.UsedSlots; + response.FreeSlots = UgcLimits.MaximumLevels - response.UsedSlots; break; } case TokenGame.LittleBigPlanetPSP: { //Match all LBP PSP levels response.UsedSlots = dataContext.Database.GetTotalLevelsPublishedByUser(old, TokenGame.LittleBigPlanetPSP); - response.FreeSlots = MaximumLevels - response.UsedSlots; + response.FreeSlots = UgcLimits.MaximumLevels - response.UsedSlots; // Apply PSP-specific icon hash response.Handle.IconHash = old.PspIconHash; @@ -161,7 +160,7 @@ public class GameUserResponse : IDataConvertableFrom { // only beta levels response.UsedSlots = dataContext.Database.GetTotalLevelsPublishedByUser(old, TokenGame.BetaBuild); - response.FreeSlots = MaximumLevels - response.UsedSlotsLBP2; + response.FreeSlots = UgcLimits.MaximumLevels - response.UsedSlotsLBP2; // use the same values for LBP3 and LBP2 since they're all shared under one count response.UsedSlotsLBP3 = response.UsedSlots; diff --git a/Refresh.GameServer/Endpoints/Game/Levels/PublishEndpoints.cs b/Refresh.GameServer/Endpoints/Game/Levels/PublishEndpoints.cs index 4eb09cef..a5593b9f 100644 --- a/Refresh.GameServer/Endpoints/Game/Levels/PublishEndpoints.cs +++ b/Refresh.GameServer/Endpoints/Game/Levels/PublishEndpoints.cs @@ -29,11 +29,11 @@ public class PublishEndpoints : EndpointGroup /// Whether or not validation succeeded private static bool VerifyLevel(GameLevelRequest body, DataContext dataContext) { - if (body.Title.Length > UgcConstantLimits.TitleLimit) - body.Title = body.Title[..UgcConstantLimits.TitleLimit]; + if (body.Title.Length > UgcLimits.TitleLimit) + body.Title = body.Title[..UgcLimits.TitleLimit]; - if (body.Description.Length > UgcConstantLimits.DescriptionLimit) - body.Description = body.Description[..UgcConstantLimits.DescriptionLimit]; + if (body.Description.Length > UgcLimits.DescriptionLimit) + body.Description = body.Description[..UgcLimits.DescriptionLimit]; if (body.MaxPlayers is > 4 or < 0 || body.MinPlayers is > 4 or < 0) return false; diff --git a/Refresh.GameServer/Endpoints/Game/UserEndpoints.cs b/Refresh.GameServer/Endpoints/Game/UserEndpoints.cs index 14cca142..a24544b9 100644 --- a/Refresh.GameServer/Endpoints/Game/UserEndpoints.cs +++ b/Refresh.GameServer/Endpoints/Game/UserEndpoints.cs @@ -4,6 +4,7 @@ using Bunkum.Core.Storage; using Bunkum.Listener.Protocol; using Bunkum.Protocols.Http; +using Refresh.Common.Constants; using Refresh.GameServer.Authentication; using Refresh.GameServer.Database; using Refresh.GameServer.Endpoints.Game.DataTypes.Response; @@ -129,10 +130,9 @@ public SerializedFriendsList GetFriends(RequestContext context, GameDatabaseCont return null; } - const int maxDescriptionLength = 4096; - if (data.Description is { Length: > maxDescriptionLength }) + if (data.Description is { Length: > UgcLimits.DescriptionLimit }) { - database.AddErrorNotification("Profile update failed", $"Your profile failed to update because the description was too long. The max length is {maxDescriptionLength}.", user); + database.AddErrorNotification("Profile update failed", $"Your profile failed to update because the description was too long. The max length is {UgcLimits.DescriptionLimit} characters.", user); return null; } diff --git a/RefreshTests.GameServer/Tests/Levels/PublishEndpointsTests.cs b/RefreshTests.GameServer/Tests/Levels/PublishEndpointsTests.cs index a72ef602..d739f2f6 100644 --- a/RefreshTests.GameServer/Tests/Levels/PublishEndpointsTests.cs +++ b/RefreshTests.GameServer/Tests/Levels/PublishEndpointsTests.cs @@ -93,7 +93,7 @@ public void LevelWithLongTitleGetsTruncated() { LevelId = 0, IsAdventure = false, - Title = new string('*', UgcConstantLimits.TitleLimit * 2), + Title = new string('*', UgcLimits.TitleLimit * 2), IconHash = "g0", Description = "Normal length", Location = new GameLocation(), @@ -117,7 +117,7 @@ public void LevelWithLongTitleGetsTruncated() message = client.PostAsync("/lbp/publish", new StringContent(level.AsXML())).Result; Assert.That(message.StatusCode, Is.EqualTo(OK)); - Assert.That(message.Content.ReadAsXML().Title.Length, Is.EqualTo(UgcConstantLimits.TitleLimit)); + Assert.That(message.Content.ReadAsXML().Title.Length, Is.EqualTo(UgcLimits.TitleLimit)); } [Test] @@ -134,7 +134,7 @@ public void LevelWithLongDescriptionGetsTruncated() IsAdventure = false, Title = "Normal Title!", IconHash = "g0", - Description = new string('=', UgcConstantLimits.DescriptionLimit * 2), + Description = new string('=', UgcLimits.DescriptionLimit * 2), Location = new GameLocation(), GameVersion = 0, RootResource = TEST_ASSET_HASH, @@ -156,7 +156,7 @@ public void LevelWithLongDescriptionGetsTruncated() message = client.PostAsync("/lbp/publish", new StringContent(level.AsXML())).Result; Assert.That(message.StatusCode, Is.EqualTo(OK)); - Assert.That(message.Content.ReadAsXML().Description.Length, Is.EqualTo(UgcConstantLimits.DescriptionLimit)); + Assert.That(message.Content.ReadAsXML().Description.Length, Is.EqualTo(UgcLimits.DescriptionLimit)); } [Test]