diff --git a/Refresh.Core/Types/Categories/CategoryService.cs b/Refresh.Core/Types/Categories/CategoryService.cs index 3ed26c54e..1a5cdb1b5 100644 --- a/Refresh.Core/Types/Categories/CategoryService.cs +++ b/Refresh.Core/Types/Categories/CategoryService.cs @@ -9,10 +9,10 @@ namespace Refresh.Core.Types.Categories; public class CategoryService : EndpointService { // Level Categories - public readonly FrozenSet LevelCategories; + public readonly FrozenSet LevelCategories; // ReSharper disable once InconsistentNaming - private readonly List _levelCategories = + private readonly List _levelCategories = [ new CoolLevelsCategory(), new TeamPickedLevelsCategory(), @@ -38,10 +38,10 @@ public class CategoryService : EndpointService ]; // User Categories - public readonly FrozenSet UserCategories; + public readonly FrozenSet UserCategories; // ReSharper disable once InconsistentNaming - private readonly List _userCategories = + private readonly List _userCategories = [ new HeartedUsersByUserCategory(), new MostHeartedUsersCategory(), diff --git a/Refresh.Core/Types/Categories/DatabaseResultList.cs b/Refresh.Core/Types/Categories/DatabaseResultList.cs new file mode 100644 index 000000000..2cc630740 --- /dev/null +++ b/Refresh.Core/Types/Categories/DatabaseResultList.cs @@ -0,0 +1,35 @@ +using Refresh.Database; +using Refresh.Database.Models.Levels; +using Refresh.Database.Models.Playlists; +using Refresh.Database.Models.Users; + +namespace Refresh.Core.Types.Categories; + +public class DatabaseResultList +{ + public DatabaseList? Levels { get; set; } = null; + public DatabaseList? Users { get; set; } = null; + public DatabaseList? Playlists { get; set; } = null; + + /// + /// All items in total + /// + public int TotalItems => (Levels?.TotalItems ?? 0) + + (Users?.TotalItems ?? 0) + + (Playlists?.TotalItems ?? 0); + + public DatabaseResultList(DatabaseList levels) + { + Levels = levels; + } + + public DatabaseResultList(DatabaseList users) + { + Users = users; + } + + public DatabaseResultList(DatabaseList playlists) + { + Playlists = playlists; + } +} \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/GameCategory.cs b/Refresh.Core/Types/Categories/GameCategory.cs index 3b890524c..813382a63 100644 --- a/Refresh.Core/Types/Categories/GameCategory.cs +++ b/Refresh.Core/Types/Categories/GameCategory.cs @@ -1,3 +1,8 @@ +using Bunkum.Core; +using Refresh.Core.Types.Data; +using Refresh.Database.Models.Users; +using Refresh.Database.Query; + namespace Refresh.Core.Types.Categories; [JsonObject(MemberSerialization.OptIn)] @@ -8,11 +13,12 @@ public abstract class GameCategory [JsonProperty] public string IconHash { get; set; } = "0"; [JsonProperty] public string FontAwesomeIcon { get; set; } = "faCertificate"; [JsonProperty] public bool Hidden { get; set; } = false; + public ResultType PrimaryResultType { get; set; } [JsonProperty] public readonly bool RequiresUser; [JsonProperty] public readonly string ApiRoute; public readonly string[] GameRoutes; - + internal GameCategory(string apiRoute, string gameRoute, bool requiresUser) : this(apiRoute, [gameRoute], requiresUser) {} internal GameCategory(string apiRoute, string[] gameRoutes, bool requiresUser) { @@ -21,4 +27,7 @@ internal GameCategory(string apiRoute, string[] gameRoutes, bool requiresUser) this.RequiresUser = requiresUser; } + + public abstract DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, + LevelFilterSettings levelFilterSettings, GameUser? user); } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Levels/AdventureCategory.cs b/Refresh.Core/Types/Categories/Levels/AdventureCategory.cs index 7f9400663..547567c7a 100644 --- a/Refresh.Core/Types/Categories/Levels/AdventureCategory.cs +++ b/Refresh.Core/Types/Categories/Levels/AdventureCategory.cs @@ -1,13 +1,11 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; -using Refresh.Database.Models.Levels; using Refresh.Database.Models.Users; using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Levels; -public class AdventureCategory : GameLevelCategory +public class AdventureCategory : GameCategory { public AdventureCategory() : base("adventure", [], false) { @@ -15,11 +13,12 @@ public AdventureCategory() : base("adventure", [], false) this.Description = "Storylines and other big projects by the community."; this.FontAwesomeIcon = "book-bookmark"; this.IconHash = "g820625"; + this.PrimaryResultType = ResultType.Level; // Adventures are GameLevels } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, LevelFilterSettings levelFilterSettings, GameUser? _) { - return dataContext.Database.GetAdventureLevels(count, skip, dataContext.User, levelFilterSettings); + return new(dataContext.Database.GetAdventureLevels(count, skip, dataContext.User, levelFilterSettings)); } } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Levels/ByTagCategory.cs b/Refresh.Core/Types/Categories/Levels/ByTagCategory.cs index 56691977d..a37055f88 100644 --- a/Refresh.Core/Types/Categories/Levels/ByTagCategory.cs +++ b/Refresh.Core/Types/Categories/Levels/ByTagCategory.cs @@ -1,13 +1,12 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; using Refresh.Database.Models.Levels; using Refresh.Database.Models.Users; using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Levels; -public class ByTagCategory : GameLevelCategory +public class ByTagCategory : GameCategory { internal ByTagCategory() : base("tag", "tag", false) { @@ -17,9 +16,10 @@ internal ByTagCategory() : base("tag", "tag", false) this.IconHash = "g820605"; this.FontAwesomeIcon = "tag"; this.Hidden = true; // The by-tag category is not meant to be shown, as it requires a special implementation on all frontends + this.PrimaryResultType = ResultType.Level; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, LevelFilterSettings levelFilterSettings, GameUser? user) { @@ -33,6 +33,6 @@ internal ByTagCategory() : base("tag", "tag", false) if (tag == null) return null; - return dataContext.Database.GetLevelsByTag(count, skip, user, tag.Value, levelFilterSettings); + return new(dataContext.Database.GetLevelsByTag(count, skip, user, tag.Value, levelFilterSettings)); } } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Levels/ByUserLevelCategory.cs b/Refresh.Core/Types/Categories/Levels/ByUserLevelCategory.cs index 036f0ad9f..08dc963bd 100644 --- a/Refresh.Core/Types/Categories/Levels/ByUserLevelCategory.cs +++ b/Refresh.Core/Types/Categories/Levels/ByUserLevelCategory.cs @@ -1,13 +1,11 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; -using Refresh.Database.Models.Levels; using Refresh.Database.Models.Users; using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Levels; -public class ByUserLevelCategory : GameLevelCategory +public class ByUserLevelCategory : GameCategory { internal ByUserLevelCategory() : base("byUser", "by", true) { @@ -16,9 +14,10 @@ internal ByUserLevelCategory() : base("byUser", "by", true) this.Description = "Levels you've shared with the community!"; this.IconHash = "g820625"; this.FontAwesomeIcon = "user"; + this.PrimaryResultType = ResultType.Level; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, LevelFilterSettings levelFilterSettings, GameUser? user) { @@ -28,6 +27,6 @@ internal ByUserLevelCategory() : base("byUser", "by", true) if (user == null) return null; - return dataContext.Database.GetLevelsByUser(user, count, skip, levelFilterSettings, dataContext.User); + return new(dataContext.Database.GetLevelsByUser(user, count, skip, levelFilterSettings, dataContext.User)); } } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Levels/ContestCategory.cs b/Refresh.Core/Types/Categories/Levels/ContestCategory.cs index 67e7e0261..8e7c98cf0 100644 --- a/Refresh.Core/Types/Categories/Levels/ContestCategory.cs +++ b/Refresh.Core/Types/Categories/Levels/ContestCategory.cs @@ -1,14 +1,12 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; using Refresh.Database.Models.Contests; -using Refresh.Database.Models.Levels; using Refresh.Database.Models.Users; using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Levels; -public class ContestCategory : GameLevelCategory +public class ContestCategory : GameCategory { public ContestCategory() : base("contest", [], false) { @@ -16,9 +14,10 @@ public ContestCategory() : base("contest", [], false) this.Description = "Levels from a contest."; this.FontAwesomeIcon = "certificate"; this.IconHash = "g820608"; + this.PrimaryResultType = ResultType.Level; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, LevelFilterSettings levelFilterSettings, GameUser? _) { // try to find a contest by the query parameter @@ -35,6 +34,6 @@ public ContestCategory() : base("contest", [], false) if (contest == null) return null; - return dataContext.Database.GetLevelsFromContest(contest, count, skip, dataContext.User, levelFilterSettings); + return new(dataContext.Database.GetLevelsFromContest(contest, count, skip, dataContext.User, levelFilterSettings)); } } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Levels/CoolLevelsCategory.cs b/Refresh.Core/Types/Categories/Levels/CoolLevelsCategory.cs index 289b0cfa5..f3c34c087 100644 --- a/Refresh.Core/Types/Categories/Levels/CoolLevelsCategory.cs +++ b/Refresh.Core/Types/Categories/Levels/CoolLevelsCategory.cs @@ -1,13 +1,11 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; -using Refresh.Database.Models.Levels; using Refresh.Database.Models.Users; using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Levels; -public class CoolLevelsCategory : GameLevelCategory +public class CoolLevelsCategory : GameCategory { public CoolLevelsCategory() : base("coolLevels", ["lbpcool", "lbp2cool", "cool", "hot"], false) { @@ -15,11 +13,12 @@ public CoolLevelsCategory() : base("coolLevels", ["lbpcool", "lbp2cool", "cool", this.Description = "Levels trending with players like you!"; this.FontAwesomeIcon = "fire"; this.IconHash = "g820625"; + this.PrimaryResultType = ResultType.Level; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, LevelFilterSettings levelFilterSettings, GameUser? _) { - return dataContext.Database.GetCoolLevels(count, skip, dataContext.User, levelFilterSettings); + return new(dataContext.Database.GetCoolLevels(count, skip, dataContext.User, levelFilterSettings)); } } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Levels/CurrentlyPlayingCategory.cs b/Refresh.Core/Types/Categories/Levels/CurrentlyPlayingCategory.cs index 3561186a7..39c0a0548 100644 --- a/Refresh.Core/Types/Categories/Levels/CurrentlyPlayingCategory.cs +++ b/Refresh.Core/Types/Categories/Levels/CurrentlyPlayingCategory.cs @@ -8,7 +8,7 @@ namespace Refresh.Core.Types.Categories.Levels; -public class CurrentlyPlayingCategory : GameLevelCategory +public class CurrentlyPlayingCategory : GameCategory { internal CurrentlyPlayingCategory() : base("currentlyPlaying", "busiest", false) { @@ -16,9 +16,10 @@ internal CurrentlyPlayingCategory() : base("currentlyPlaying", "busiest", false) this.Description = "Levels people are playing right now!"; this.IconHash = "g820602"; this.FontAwesomeIcon = "users"; + this.PrimaryResultType = ResultType.Level; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, LevelFilterSettings levelFilterSettings, GameUser? _) { @@ -27,9 +28,9 @@ internal CurrentlyPlayingCategory() : base("currentlyPlaying", "busiest", false) .GroupBy(r => dataContext.Database.GetLevelById(r.LevelId)) .OrderBy(r => r.Sum(room => room.PlayerIds.Count)); - return new DatabaseList(rooms.Select(r => r.Key) + return new(new DatabaseList(rooms.Select(r => r.Key) .Where(l => l != null && l.StoryId == 0)! .FilterByLevelFilterSettings(dataContext.User, levelFilterSettings) - .FilterByGameVersion(levelFilterSettings.GameVersion), skip, count); + .FilterByGameVersion(levelFilterSettings.GameVersion), skip, count)); } } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Levels/DeveloperLevelsCategory.cs b/Refresh.Core/Types/Categories/Levels/DeveloperLevelsCategory.cs index 8a62bfeef..c6eeca02d 100644 --- a/Refresh.Core/Types/Categories/Levels/DeveloperLevelsCategory.cs +++ b/Refresh.Core/Types/Categories/Levels/DeveloperLevelsCategory.cs @@ -1,13 +1,11 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; -using Refresh.Database.Models.Levels; using Refresh.Database.Models.Users; using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Levels; -public class DeveloperLevelsCategory : GameLevelCategory +public class DeveloperLevelsCategory : GameCategory { internal DeveloperLevelsCategory() : base("developer", [], false) { @@ -16,10 +14,11 @@ internal DeveloperLevelsCategory() : base("developer", [], false) this.FontAwesomeIcon = "certificate"; this.IconHash = "g820604"; this.Hidden = true; // TODO: Set to false when we import story level names + this.PrimaryResultType = ResultType.Level; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, LevelFilterSettings levelFilterSettings, GameUser? _) - => dataContext.Database.GetDeveloperLevels(count, skip, levelFilterSettings); + => new(dataContext.Database.GetDeveloperLevels(count, skip, levelFilterSettings)); } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Levels/GameLevelCategory.cs b/Refresh.Core/Types/Categories/Levels/GameLevelCategory.cs deleted file mode 100644 index 17bfe9296..000000000 --- a/Refresh.Core/Types/Categories/Levels/GameLevelCategory.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Diagnostics.Contracts; -using Bunkum.Core; -using Refresh.Core.Types.Data; -using Refresh.Database; -using Refresh.Database.Models.Levels; -using Refresh.Database.Models.Users; -using Refresh.Database.Query; - -namespace Refresh.Core.Types.Categories.Levels; - -[JsonObject(MemberSerialization.OptIn)] -public abstract class GameLevelCategory : GameCategory -{ - internal GameLevelCategory(string apiRoute, string gameRoute, bool requiresUser) : base(apiRoute, [gameRoute], requiresUser) {} - - internal GameLevelCategory(string apiRoute, string[] gameRoutes, bool requiresUser) : base(apiRoute, gameRoutes, requiresUser) {} - - [Pure] - public abstract DatabaseList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, - LevelFilterSettings levelFilterSettings, GameUser? user); -} \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Levels/HeartedLevelsByUserCategory.cs b/Refresh.Core/Types/Categories/Levels/HeartedLevelsByUserCategory.cs index 4a974584d..e4f266c5c 100644 --- a/Refresh.Core/Types/Categories/Levels/HeartedLevelsByUserCategory.cs +++ b/Refresh.Core/Types/Categories/Levels/HeartedLevelsByUserCategory.cs @@ -1,13 +1,11 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; -using Refresh.Database.Models.Levels; using Refresh.Database.Models.Users; using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Levels; -public class HeartedLevelsByUserCategory : GameLevelCategory +public class HeartedLevelsByUserCategory : GameCategory { internal HeartedLevelsByUserCategory() : base("hearted", "favouriteSlots", true) { @@ -15,9 +13,10 @@ internal HeartedLevelsByUserCategory() : base("hearted", "favouriteSlots", true) this.Description = "Your personal list filled with your favourite levels!"; this.FontAwesomeIcon = "heart"; this.IconHash = "g820611"; + this.PrimaryResultType = ResultType.Level; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, LevelFilterSettings levelFilterSettings, GameUser? user) { // Prefer username from query, but fallback to user passed into this category if it's missing @@ -26,6 +25,6 @@ internal HeartedLevelsByUserCategory() : base("hearted", "favouriteSlots", true) if (user == null) return null; - return dataContext.Database.GetLevelsFavouritedByUser(user, count, skip, levelFilterSettings, dataContext.User); + return new(dataContext.Database.GetLevelsFavouritedByUser(user, count, skip, levelFilterSettings, dataContext.User)); } } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Levels/HighestRatedLevelsCategory.cs b/Refresh.Core/Types/Categories/Levels/HighestRatedLevelsCategory.cs index 0d7dcb255..db178f944 100644 --- a/Refresh.Core/Types/Categories/Levels/HighestRatedLevelsCategory.cs +++ b/Refresh.Core/Types/Categories/Levels/HighestRatedLevelsCategory.cs @@ -1,13 +1,11 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; -using Refresh.Database.Models.Levels; using Refresh.Database.Models.Users; using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Levels; -public class HighestRatedLevelsCategory : GameLevelCategory +public class HighestRatedLevelsCategory : GameCategory { internal HighestRatedLevelsCategory() : base("mostLiked", ["thumbs", "highestRated"], false) { @@ -15,10 +13,11 @@ internal HighestRatedLevelsCategory() : base("mostLiked", ["thumbs", "highestRat this.Description = "Levels with the most Yays!"; this.FontAwesomeIcon = "thumbs-up"; this.IconHash = "g820603"; + this.PrimaryResultType = ResultType.Level; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, LevelFilterSettings levelFilterSettings, GameUser? _) - => dataContext.Database.GetHighestRatedLevels(count, skip, dataContext.User, levelFilterSettings); + => new(dataContext.Database.GetHighestRatedLevels(count, skip, dataContext.User, levelFilterSettings)); } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Levels/MostHeartedLevelsCategory.cs b/Refresh.Core/Types/Categories/Levels/MostHeartedLevelsCategory.cs index ef4618eba..514169371 100644 --- a/Refresh.Core/Types/Categories/Levels/MostHeartedLevelsCategory.cs +++ b/Refresh.Core/Types/Categories/Levels/MostHeartedLevelsCategory.cs @@ -1,13 +1,11 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; -using Refresh.Database.Models.Levels; using Refresh.Database.Models.Users; using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Levels; -public class MostHeartedLevelsCategory : GameLevelCategory +public class MostHeartedLevelsCategory : GameCategory { internal MostHeartedLevelsCategory() : base("mostHearted", "mostHearted", false) { @@ -15,10 +13,11 @@ internal MostHeartedLevelsCategory() : base("mostHearted", "mostHearted", false) this.Description = "The all-time most hearted levels!"; this.FontAwesomeIcon = "heart"; this.IconHash = "g820607"; + this.PrimaryResultType = ResultType.Level; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, LevelFilterSettings levelFilterSettings, GameUser? _) - => dataContext.Database.GetMostFavouritedLevels(count, skip, dataContext.User, levelFilterSettings); + => new(dataContext.Database.GetMostFavouritedLevels(count, skip, dataContext.User, levelFilterSettings)); } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Levels/MostReplayedLevelsCategory.cs b/Refresh.Core/Types/Categories/Levels/MostReplayedLevelsCategory.cs index b4bf76c84..5b1e24f59 100644 --- a/Refresh.Core/Types/Categories/Levels/MostReplayedLevelsCategory.cs +++ b/Refresh.Core/Types/Categories/Levels/MostReplayedLevelsCategory.cs @@ -1,13 +1,11 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; -using Refresh.Database.Models.Levels; using Refresh.Database.Models.Users; using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Levels; -public class MostReplayedLevelsCategory : GameLevelCategory +public class MostReplayedLevelsCategory : GameCategory { internal MostReplayedLevelsCategory() : base("mostReplayed", "mostPlays", false) { @@ -15,10 +13,11 @@ internal MostReplayedLevelsCategory() : base("mostReplayed", "mostPlays", false) this.Description = "Levels people love to play over and over!"; this.FontAwesomeIcon = "forward"; this.IconHash = "g820608"; + this.PrimaryResultType = ResultType.Level; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, LevelFilterSettings levelFilterSettings, GameUser? _) - => dataContext.Database.GetMostReplayedLevels(count, skip, dataContext.User, levelFilterSettings); + => new(dataContext.Database.GetMostReplayedLevels(count, skip, dataContext.User, levelFilterSettings)); } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Levels/MostUniquelyPlayedLevelsCategory.cs b/Refresh.Core/Types/Categories/Levels/MostUniquelyPlayedLevelsCategory.cs index 04bcb5a80..d382db709 100644 --- a/Refresh.Core/Types/Categories/Levels/MostUniquelyPlayedLevelsCategory.cs +++ b/Refresh.Core/Types/Categories/Levels/MostUniquelyPlayedLevelsCategory.cs @@ -1,13 +1,11 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; -using Refresh.Database.Models.Levels; using Refresh.Database.Models.Users; using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Levels; -public class MostUniquelyPlayedLevelsCategory : GameLevelCategory +public class MostUniquelyPlayedLevelsCategory : GameCategory { internal MostUniquelyPlayedLevelsCategory() : base("mostPlayed", "mostUniquePlays", false) { @@ -15,10 +13,11 @@ internal MostUniquelyPlayedLevelsCategory() : base("mostPlayed", "mostUniquePlay this.Description = "Levels that many people have played."; this.FontAwesomeIcon = "play"; this.IconHash = "g820608"; + this.PrimaryResultType = ResultType.Level; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, LevelFilterSettings levelFilterSettings, GameUser? _) - => dataContext.Database.GetMostUniquelyPlayedLevels(count, skip, dataContext.User, levelFilterSettings); + => new(dataContext.Database.GetMostUniquelyPlayedLevels(count, skip, dataContext.User, levelFilterSettings)); } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Levels/NewestLevelsCategory.cs b/Refresh.Core/Types/Categories/Levels/NewestLevelsCategory.cs index 32e89447c..82afa0db2 100644 --- a/Refresh.Core/Types/Categories/Levels/NewestLevelsCategory.cs +++ b/Refresh.Core/Types/Categories/Levels/NewestLevelsCategory.cs @@ -1,13 +1,11 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; -using Refresh.Database.Models.Levels; using Refresh.Database.Models.Users; using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Levels; -public class NewestLevelsCategory : GameLevelCategory +public class NewestLevelsCategory : GameCategory { internal NewestLevelsCategory() : base("newest", "newest", false) { @@ -15,9 +13,10 @@ internal NewestLevelsCategory() : base("newest", "newest", false) this.Description = "Levels that were most recently uploaded!"; this.IconHash = "g820623"; this.FontAwesomeIcon = "calendar"; + this.PrimaryResultType = ResultType.Level; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, LevelFilterSettings levelFilterSettings, GameUser? _) - => dataContext.Database.GetNewestLevels(count, skip, dataContext.User, levelFilterSettings); + => new(dataContext.Database.GetNewestLevels(count, skip, dataContext.User, levelFilterSettings)); } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Levels/QueuedLevelsByUserCategory.cs b/Refresh.Core/Types/Categories/Levels/QueuedLevelsByUserCategory.cs index 3f8e9623b..bc5e82a26 100644 --- a/Refresh.Core/Types/Categories/Levels/QueuedLevelsByUserCategory.cs +++ b/Refresh.Core/Types/Categories/Levels/QueuedLevelsByUserCategory.cs @@ -1,13 +1,11 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; -using Refresh.Database.Models.Levels; using Refresh.Database.Models.Users; using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Levels; -public class QueuedLevelsByUserCategory : GameLevelCategory +public class QueuedLevelsByUserCategory : GameCategory { internal QueuedLevelsByUserCategory() : base("queued", "lolcatftw", true) { @@ -15,12 +13,13 @@ internal QueuedLevelsByUserCategory() : base("queued", "lolcatftw", true) this.Description = "Levels you'd like to play!"; this.FontAwesomeIcon = "bell"; this.IconHash = "g820614"; + this.PrimaryResultType = ResultType.Level; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, LevelFilterSettings levelFilterSettings, GameUser? user) { if (user == null) return null; - return dataContext.Database.GetLevelsQueuedByUser(user, count, skip, levelFilterSettings, dataContext.User); + return new(dataContext.Database.GetLevelsQueuedByUser(user, count, skip, levelFilterSettings, dataContext.User)); } } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Levels/RandomLevelsCategory.cs b/Refresh.Core/Types/Categories/Levels/RandomLevelsCategory.cs index 93b6f4231..9158143e5 100644 --- a/Refresh.Core/Types/Categories/Levels/RandomLevelsCategory.cs +++ b/Refresh.Core/Types/Categories/Levels/RandomLevelsCategory.cs @@ -1,13 +1,11 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; -using Refresh.Database.Models.Levels; using Refresh.Database.Models.Users; using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Levels; -public class RandomLevelsCategory : GameLevelCategory +public class RandomLevelsCategory : GameCategory { internal RandomLevelsCategory() : base("random", ["lbp2luckydip", "luckydip"], false) { @@ -15,9 +13,10 @@ internal RandomLevelsCategory() : base("random", ["lbp2luckydip", "luckydip"], f this.Description = "A random assortment of levels!"; this.FontAwesomeIcon = "shuffle"; this.IconHash = "g820605"; + this.PrimaryResultType = ResultType.Level; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, LevelFilterSettings levelFilterSettings, GameUser? _) - => dataContext.Database.GetRandomLevels(count, skip, dataContext.User, levelFilterSettings); + => new(dataContext.Database.GetRandomLevels(count, skip, dataContext.User, levelFilterSettings)); } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Levels/SearchLevelCategory.cs b/Refresh.Core/Types/Categories/Levels/SearchLevelCategory.cs index 151abe6b6..e88ac56df 100644 --- a/Refresh.Core/Types/Categories/Levels/SearchLevelCategory.cs +++ b/Refresh.Core/Types/Categories/Levels/SearchLevelCategory.cs @@ -1,13 +1,11 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; -using Refresh.Database.Models.Levels; using Refresh.Database.Models.Users; using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Levels; -public class SearchLevelCategory : GameLevelCategory +public class SearchLevelCategory : GameCategory { internal SearchLevelCategory() : base("search", "search", false) { @@ -16,9 +14,10 @@ internal SearchLevelCategory() : base("search", "search", false) this.FontAwesomeIcon = "magnifying-glass"; // no icon for now, too lazy to find this.Hidden = true; // The search category is not meant to be shown, as it requires a special implementation on all frontends + this.PrimaryResultType = ResultType.Level; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, LevelFilterSettings levelFilterSettings, GameUser? _) { @@ -26,6 +25,6 @@ internal SearchLevelCategory() : base("search", "search", false) ?? context.QueryString["textFilter"]; // LBP3 sends this instead of query if (query == null) return null; - return dataContext.Database.SearchForLevels(count, skip, dataContext.User, levelFilterSettings, query); + return new(dataContext.Database.SearchForLevels(count, skip, dataContext.User, levelFilterSettings, query)); } } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Levels/TeamPickedLevelsCategory.cs b/Refresh.Core/Types/Categories/Levels/TeamPickedLevelsCategory.cs index 041526987..f659a24d5 100644 --- a/Refresh.Core/Types/Categories/Levels/TeamPickedLevelsCategory.cs +++ b/Refresh.Core/Types/Categories/Levels/TeamPickedLevelsCategory.cs @@ -1,13 +1,11 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; -using Refresh.Database.Models.Levels; using Refresh.Database.Models.Users; using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Levels; -public class TeamPickedLevelsCategory : GameLevelCategory +public class TeamPickedLevelsCategory : GameCategory { internal TeamPickedLevelsCategory() : base("teamPicks", "mmpicks", false) { @@ -15,10 +13,11 @@ internal TeamPickedLevelsCategory() : base("teamPicks", "mmpicks", false) this.Description = "High quality levels, hand-picked by us."; this.FontAwesomeIcon = "certificate"; this.IconHash = "g820626"; + this.PrimaryResultType = ResultType.Level; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, LevelFilterSettings levelFilterSettings, GameUser? _) - => dataContext.Database.GetTeamPickedLevels(count, skip, dataContext.User, levelFilterSettings); + => new(dataContext.Database.GetTeamPickedLevels(count, skip, dataContext.User, levelFilterSettings)); } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/ResultType.cs b/Refresh.Core/Types/Categories/ResultType.cs new file mode 100644 index 000000000..3d67f638d --- /dev/null +++ b/Refresh.Core/Types/Categories/ResultType.cs @@ -0,0 +1,8 @@ + + +public enum ResultType : byte +{ + Level, + User, + Playlist +} \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Users/GameUserCategory.cs b/Refresh.Core/Types/Categories/Users/GameUserCategory.cs deleted file mode 100644 index 858463836..000000000 --- a/Refresh.Core/Types/Categories/Users/GameUserCategory.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Diagnostics.Contracts; -using Bunkum.Core; -using Refresh.Core.Types.Data; -using Refresh.Database; -using Refresh.Database.Models.Users; - -namespace Refresh.Core.Types.Categories.Users; - -[JsonObject(MemberSerialization.OptIn)] -public abstract class GameUserCategory : GameCategory -{ - internal GameUserCategory(string apiRoute, string gameRoute, bool requiresUser) : base(apiRoute, [gameRoute], requiresUser) {} - - internal GameUserCategory(string apiRoute, string[] gameRoutes, bool requiresUser) : base(apiRoute, gameRoutes, requiresUser) {} - - [Pure] - public abstract DatabaseList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, GameUser? user); -} \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Users/HeartedUsersByUserCategory.cs b/Refresh.Core/Types/Categories/Users/HeartedUsersByUserCategory.cs index 914439d6f..047346f10 100644 --- a/Refresh.Core/Types/Categories/Users/HeartedUsersByUserCategory.cs +++ b/Refresh.Core/Types/Categories/Users/HeartedUsersByUserCategory.cs @@ -1,11 +1,11 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; using Refresh.Database.Models.Users; +using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Users; -public class HeartedUsersByUserCategory : GameUserCategory +public class HeartedUsersByUserCategory : GameCategory { public HeartedUsersByUserCategory() : base("hearted", [], false) { @@ -13,15 +13,17 @@ public HeartedUsersByUserCategory() : base("hearted", [], false) this.Description = "Users you've hearted."; this.FontAwesomeIcon = "heart"; this.IconHash = "g820612"; + this.PrimaryResultType = ResultType.User; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, GameUser? user) + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, + LevelFilterSettings levelFilterSettings, GameUser? user) { // Prefer username from query, but fallback to user passed into this category if it's missing string? username = context.QueryString["u"] ?? context.QueryString["username"]; if (username != null) user = dataContext.Database.GetUserByUsername(username); if (user == null) return null; - return dataContext.Database.GetUsersFavouritedByUser(user, skip, count); + return new(dataContext.Database.GetUsersFavouritedByUser(user, skip, count)); } } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Users/MostHeartedUsersCategory.cs b/Refresh.Core/Types/Categories/Users/MostHeartedUsersCategory.cs index c65ae1097..4b3f5245d 100644 --- a/Refresh.Core/Types/Categories/Users/MostHeartedUsersCategory.cs +++ b/Refresh.Core/Types/Categories/Users/MostHeartedUsersCategory.cs @@ -1,11 +1,11 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; using Refresh.Database.Models.Users; +using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Users; -public class MostHeartedUsersCategory : GameUserCategory +public class MostHeartedUsersCategory : GameCategory { public MostHeartedUsersCategory() : base("mostHearted", [], false) { @@ -13,10 +13,12 @@ public MostHeartedUsersCategory() : base("mostHearted", [], false) this.Description = "Our most hearted users!"; this.FontAwesomeIcon = "heart"; this.IconHash = "g820627"; + this.PrimaryResultType = ResultType.User; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, GameUser? _) + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, + LevelFilterSettings levelFilterSettings, GameUser? _) { - return dataContext.Database.GetMostFavouritedUsers(skip, count); + return new(dataContext.Database.GetMostFavouritedUsers(skip, count)); } } \ No newline at end of file diff --git a/Refresh.Core/Types/Categories/Users/NewestUsersCategory.cs b/Refresh.Core/Types/Categories/Users/NewestUsersCategory.cs index 8a92ab335..c4264cfbc 100644 --- a/Refresh.Core/Types/Categories/Users/NewestUsersCategory.cs +++ b/Refresh.Core/Types/Categories/Users/NewestUsersCategory.cs @@ -1,11 +1,11 @@ using Bunkum.Core; using Refresh.Core.Types.Data; -using Refresh.Database; using Refresh.Database.Models.Users; +using Refresh.Database.Query; namespace Refresh.Core.Types.Categories.Users; -public class NewestUsersCategory : GameUserCategory +public class NewestUsersCategory : GameCategory { public NewestUsersCategory() : base("newest", [], false) { @@ -13,10 +13,12 @@ public NewestUsersCategory() : base("newest", [], false) this.Description = "Our newest server users."; this.FontAwesomeIcon = "user-plus"; this.IconHash = "g820602"; + this.PrimaryResultType = ResultType.User; } - public override DatabaseList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, GameUser? _) + public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext, + LevelFilterSettings levelFilterSettings, GameUser? _) { - return dataContext.Database.GetUsers(count, skip); + return new(dataContext.Database.GetUsers(count, skip)); } } \ No newline at end of file diff --git a/Refresh.Database/Models/Users/GameUser.cs b/Refresh.Database/Models/Users/GameUser.cs index e2ffb1314..cb4263812 100644 --- a/Refresh.Database/Models/Users/GameUser.cs +++ b/Refresh.Database/Models/Users/GameUser.cs @@ -1,6 +1,5 @@ using MongoDB.Bson; using Bunkum.Core.RateLimit; -using Refresh.Database.Models.Playlists; using Refresh.Database.Models.Statistics; namespace Refresh.Database.Models.Users; diff --git a/Refresh.Interfaces.APIv3/Endpoints/CategoryApiEndpoints.cs b/Refresh.Interfaces.APIv3/Endpoints/CategoryApiEndpoints.cs index 0954ecb93..ddf2ab2c9 100644 --- a/Refresh.Interfaces.APIv3/Endpoints/CategoryApiEndpoints.cs +++ b/Refresh.Interfaces.APIv3/Endpoints/CategoryApiEndpoints.cs @@ -28,19 +28,19 @@ public class CategoryApiEndpoints : EndpointGroup [DocSummary("Retrieves a list of categories you can use to search levels")] [DocQueryParam("includePreviews", "If true, a single level will be added to each category representing a level from that category. False by default.")] [DocError(typeof(ApiValidationError), "The boolean 'includePreviews' could not be parsed by the server.")] - public ApiListResponse GetLevelCategories(RequestContext context, CategoryService categories, + public ApiListResponse GetLevelCategories(RequestContext context, CategoryService categories, DataContext dataContext) { bool result = bool.TryParse(context.QueryString.Get("includePreviews") ?? "false", out bool includePreviews); if (!result) return ApiValidationError.BooleanParseError; - IEnumerable resp; + IEnumerable resp; // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression - if (includePreviews) resp = ApiLevelCategoryResponse.FromOldList(categories.LevelCategories, context, dataContext); - else resp = ApiLevelCategoryResponse.FromOldList(categories.LevelCategories, dataContext); + if (includePreviews) resp = ApiCategoryResponse.FromOldList(categories.LevelCategories, context, dataContext); + else resp = ApiCategoryResponse.FromOldList(categories.LevelCategories, dataContext); - return new ApiListResponse(resp); + return new ApiListResponse(resp); } [ApiV3Endpoint("levels/{route}"), Authentication(false)] @@ -67,7 +67,8 @@ public ApiListResponse GetLevels(RequestContext context, C DatabaseList? list = categories.LevelCategories .FirstOrDefault(c => c.ApiRoute.StartsWith(route))? - .Fetch(context, skip, count, dataContext, LevelFilterSettings.FromApiRequest(context), user); + .Fetch(context, skip, count, dataContext, LevelFilterSettings.FromApiRequest(context), user)? + .Levels; if (list == null) return ApiNotFoundError.Instance; @@ -80,19 +81,19 @@ public ApiListResponse GetLevels(RequestContext context, C [DocSummary("Retrieves a list of categories you can use to search users. Returns an empty list if the instance doesn't allow showing online users.")] [DocQueryParam("includePreviews", "If true, a single user will be added to each category representing a user from that category. False by default.")] [DocError(typeof(ApiValidationError), "The boolean 'includePreviews' could not be parsed by the server.")] - public ApiListResponse GetUserCategories(RequestContext context, CategoryService categories, + public ApiListResponse GetUserCategories(RequestContext context, CategoryService categories, DataContext dataContext, GameServerConfig config) { bool result = bool.TryParse(context.QueryString.Get("includePreviews") ?? "false", out bool includePreviews); if (!result) return ApiValidationError.BooleanParseError; - if (!config.PermitShowingOnlineUsers) return new ApiListResponse([]); - IEnumerable resp; + if (!config.PermitShowingOnlineUsers) return new ApiListResponse([]); + IEnumerable resp; - if (includePreviews) resp = ApiUserCategoryResponse.FromOldList(categories.UserCategories, context, dataContext); - else resp = ApiUserCategoryResponse.FromOldList(categories.UserCategories, dataContext); + if (includePreviews) resp = ApiCategoryResponse.FromOldList(categories.UserCategories, context, dataContext); + else resp = ApiCategoryResponse.FromOldList(categories.UserCategories, dataContext); - return new ApiListResponse(resp); + return new ApiListResponse(resp); } [ApiV3Endpoint("users/{route}"), Authentication(false)] @@ -124,7 +125,8 @@ public Response GetUsers(RequestContext context, CategoryService categories, Gam DatabaseList? list = categories.UserCategories .FirstOrDefault(c => c.ApiRoute.StartsWith(route))? - .Fetch(context, skip, count, dataContext, user); + .Fetch(context, skip, count, dataContext, LevelFilterSettings.FromApiRequest(context), user)? + .Users; if (list == null) return ApiNotFoundError.Instance; diff --git a/Refresh.Interfaces.APIv3/Endpoints/DataTypes/Response/Categories/ApiCategoryResponse.cs b/Refresh.Interfaces.APIv3/Endpoints/DataTypes/Response/Categories/ApiCategoryResponse.cs index 6fffe81f1..0878f2c95 100644 --- a/Refresh.Interfaces.APIv3/Endpoints/DataTypes/Response/Categories/ApiCategoryResponse.cs +++ b/Refresh.Interfaces.APIv3/Endpoints/DataTypes/Response/Categories/ApiCategoryResponse.cs @@ -1,5 +1,9 @@ +using Bunkum.Core; using Refresh.Core.Types.Categories; using Refresh.Core.Types.Data; +using Refresh.Database.Query; +using Refresh.Interfaces.APIv3.Endpoints.DataTypes.Response.Levels; +using Refresh.Interfaces.APIv3.Endpoints.DataTypes.Response.Users; namespace Refresh.Interfaces.APIv3.Endpoints.DataTypes.Response.Categories; @@ -13,8 +17,19 @@ public class ApiCategoryResponse : IApiResponse, IDataConvertableFrom