Skip to content

Commit 38ad17b

Browse files
authored
Refactor categories to extend GameCategory (#989)
This is a refactor which removes `GameLevelCategory`, `GameUserCategory`, their equivalent game and API serialization classes and makes all category classes directly extend `GameCategory`. De-duplicating category code, especially for the API responses, was suggested in a [previous PR's review](#922 (comment)), and this is the easiest and least hacky way I could think of. While I have tried to implement the suggested strategy of using a generic type for `ApiCategoryResponse`, it became too complicated for me due to one of the two `FromOldList` methods needing to call the `Fetch` method of every category in order to add their preview items to the responses. I've thought to instead have the preview item attribute be of type `IApiResultResponse` which both `ApiGameLevelResponse` and `ApiGameUserResponse` implement. For LBP3 the `Results` attribute, which used to be in `SerializedLevelCategory` and `SerializedUserCategory`, is now in `SerializedCategory` and of type `SerializedCategoryResultsList` so the categories could include either users or levels as previews. This works with LBP3. The overridden `GameCategory.Fetch` method now returns a `DatabaseResultList`, which references a nullable `DatabaseList` of `GameLevel`s, `GameUser`s and `GamePlaylist`s each (3 lists in total). This is so that both level and user categories could override the method without any problems, while also being a preparation to make searching users for LBP1-3 and the API (and then maybe also playlists in LBP1/3/API) alongside levels possible.
2 parents 61e5293 + 66a65af commit 38ad17b

42 files changed

Lines changed: 285 additions & 386 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Refresh.Core/Types/Categories/CategoryService.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ namespace Refresh.Core.Types.Categories;
99
public class CategoryService : EndpointService
1010
{
1111
// Level Categories
12-
public readonly FrozenSet<GameLevelCategory> LevelCategories;
12+
public readonly FrozenSet<GameCategory> LevelCategories;
1313

1414
// ReSharper disable once InconsistentNaming
15-
private readonly List<GameLevelCategory> _levelCategories =
15+
private readonly List<GameCategory> _levelCategories =
1616
[
1717
new CoolLevelsCategory(),
1818
new TeamPickedLevelsCategory(),
@@ -38,10 +38,10 @@ public class CategoryService : EndpointService
3838
];
3939

4040
// User Categories
41-
public readonly FrozenSet<GameUserCategory> UserCategories;
41+
public readonly FrozenSet<GameCategory> UserCategories;
4242

4343
// ReSharper disable once InconsistentNaming
44-
private readonly List<GameUserCategory> _userCategories =
44+
private readonly List<GameCategory> _userCategories =
4545
[
4646
new HeartedUsersByUserCategory(),
4747
new MostHeartedUsersCategory(),
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using Refresh.Database;
2+
using Refresh.Database.Models.Levels;
3+
using Refresh.Database.Models.Playlists;
4+
using Refresh.Database.Models.Users;
5+
6+
namespace Refresh.Core.Types.Categories;
7+
8+
public class DatabaseResultList
9+
{
10+
public DatabaseList<GameLevel>? Levels { get; set; } = null;
11+
public DatabaseList<GameUser>? Users { get; set; } = null;
12+
public DatabaseList<GamePlaylist>? Playlists { get; set; } = null;
13+
14+
/// <summary>
15+
/// All items in total
16+
/// </summary>
17+
public int TotalItems => (Levels?.TotalItems ?? 0)
18+
+ (Users?.TotalItems ?? 0)
19+
+ (Playlists?.TotalItems ?? 0);
20+
21+
public DatabaseResultList(DatabaseList<GameLevel> levels)
22+
{
23+
Levels = levels;
24+
}
25+
26+
public DatabaseResultList(DatabaseList<GameUser> users)
27+
{
28+
Users = users;
29+
}
30+
31+
public DatabaseResultList(DatabaseList<GamePlaylist> playlists)
32+
{
33+
Playlists = playlists;
34+
}
35+
}

Refresh.Core/Types/Categories/GameCategory.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
using Bunkum.Core;
2+
using Refresh.Core.Types.Data;
3+
using Refresh.Database.Models.Users;
4+
using Refresh.Database.Query;
5+
16
namespace Refresh.Core.Types.Categories;
27

38
[JsonObject(MemberSerialization.OptIn)]
@@ -8,11 +13,12 @@ public abstract class GameCategory
813
[JsonProperty] public string IconHash { get; set; } = "0";
914
[JsonProperty] public string FontAwesomeIcon { get; set; } = "faCertificate";
1015
[JsonProperty] public bool Hidden { get; set; } = false;
16+
public ResultType PrimaryResultType { get; set; }
1117

1218
[JsonProperty] public readonly bool RequiresUser;
1319
[JsonProperty] public readonly string ApiRoute;
1420
public readonly string[] GameRoutes;
15-
21+
1622
internal GameCategory(string apiRoute, string gameRoute, bool requiresUser) : this(apiRoute, [gameRoute], requiresUser) {}
1723
internal GameCategory(string apiRoute, string[] gameRoutes, bool requiresUser)
1824
{
@@ -21,4 +27,7 @@ internal GameCategory(string apiRoute, string[] gameRoutes, bool requiresUser)
2127

2228
this.RequiresUser = requiresUser;
2329
}
30+
31+
public abstract DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext,
32+
LevelFilterSettings levelFilterSettings, GameUser? user);
2433
}
Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
11
using Bunkum.Core;
22
using Refresh.Core.Types.Data;
3-
using Refresh.Database;
4-
using Refresh.Database.Models.Levels;
53
using Refresh.Database.Models.Users;
64
using Refresh.Database.Query;
75

86
namespace Refresh.Core.Types.Categories.Levels;
97

10-
public class AdventureCategory : GameLevelCategory
8+
public class AdventureCategory : GameCategory
119
{
1210
public AdventureCategory() : base("adventure", [], false)
1311
{
1412
this.Name = "Adventures";
1513
this.Description = "Storylines and other big projects by the community.";
1614
this.FontAwesomeIcon = "book-bookmark";
1715
this.IconHash = "g820625";
16+
this.PrimaryResultType = ResultType.Level; // Adventures are GameLevels
1817
}
1918

20-
public override DatabaseList<GameLevel>? Fetch(RequestContext context, int skip, int count, DataContext dataContext,
19+
public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext,
2120
LevelFilterSettings levelFilterSettings, GameUser? _)
2221
{
23-
return dataContext.Database.GetAdventureLevels(count, skip, dataContext.User, levelFilterSettings);
22+
return new(dataContext.Database.GetAdventureLevels(count, skip, dataContext.User, levelFilterSettings));
2423
}
2524
}

Refresh.Core/Types/Categories/Levels/ByTagCategory.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
using Bunkum.Core;
22
using Refresh.Core.Types.Data;
3-
using Refresh.Database;
43
using Refresh.Database.Models.Levels;
54
using Refresh.Database.Models.Users;
65
using Refresh.Database.Query;
76

87
namespace Refresh.Core.Types.Categories.Levels;
98

10-
public class ByTagCategory : GameLevelCategory
9+
public class ByTagCategory : GameCategory
1110
{
1211
internal ByTagCategory() : base("tag", "tag", false)
1312
{
@@ -17,9 +16,10 @@ internal ByTagCategory() : base("tag", "tag", false)
1716
this.IconHash = "g820605";
1817
this.FontAwesomeIcon = "tag";
1918
this.Hidden = true; // The by-tag category is not meant to be shown, as it requires a special implementation on all frontends
19+
this.PrimaryResultType = ResultType.Level;
2020
}
2121

22-
public override DatabaseList<GameLevel>? Fetch(RequestContext context, int skip, int count,
22+
public override DatabaseResultList? Fetch(RequestContext context, int skip, int count,
2323
DataContext dataContext,
2424
LevelFilterSettings levelFilterSettings, GameUser? user)
2525
{
@@ -33,6 +33,6 @@ internal ByTagCategory() : base("tag", "tag", false)
3333
if (tag == null)
3434
return null;
3535

36-
return dataContext.Database.GetLevelsByTag(count, skip, user, tag.Value, levelFilterSettings);
36+
return new(dataContext.Database.GetLevelsByTag(count, skip, user, tag.Value, levelFilterSettings));
3737
}
3838
}
Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
using Bunkum.Core;
22
using Refresh.Core.Types.Data;
3-
using Refresh.Database;
4-
using Refresh.Database.Models.Levels;
53
using Refresh.Database.Models.Users;
64
using Refresh.Database.Query;
75

86
namespace Refresh.Core.Types.Categories.Levels;
97

10-
public class ByUserLevelCategory : GameLevelCategory
8+
public class ByUserLevelCategory : GameCategory
119
{
1210
internal ByUserLevelCategory() : base("byUser", "by", true)
1311
{
@@ -16,9 +14,10 @@ internal ByUserLevelCategory() : base("byUser", "by", true)
1614
this.Description = "Levels you've shared with the community!";
1715
this.IconHash = "g820625";
1816
this.FontAwesomeIcon = "user";
17+
this.PrimaryResultType = ResultType.Level;
1918
}
2019

21-
public override DatabaseList<GameLevel>? Fetch(RequestContext context, int skip, int count,
20+
public override DatabaseResultList? Fetch(RequestContext context, int skip, int count,
2221
DataContext dataContext,
2322
LevelFilterSettings levelFilterSettings, GameUser? user)
2423
{
@@ -28,6 +27,6 @@ internal ByUserLevelCategory() : base("byUser", "by", true)
2827

2928
if (user == null) return null;
3029

31-
return dataContext.Database.GetLevelsByUser(user, count, skip, levelFilterSettings, dataContext.User);
30+
return new(dataContext.Database.GetLevelsByUser(user, count, skip, levelFilterSettings, dataContext.User));
3231
}
3332
}

Refresh.Core/Types/Categories/Levels/ContestCategory.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,23 @@
11
using Bunkum.Core;
22
using Refresh.Core.Types.Data;
3-
using Refresh.Database;
43
using Refresh.Database.Models.Contests;
5-
using Refresh.Database.Models.Levels;
64
using Refresh.Database.Models.Users;
75
using Refresh.Database.Query;
86

97
namespace Refresh.Core.Types.Categories.Levels;
108

11-
public class ContestCategory : GameLevelCategory
9+
public class ContestCategory : GameCategory
1210
{
1311
public ContestCategory() : base("contest", [], false)
1412
{
1513
this.Name = "Contests";
1614
this.Description = "Levels from a contest.";
1715
this.FontAwesomeIcon = "certificate";
1816
this.IconHash = "g820608";
17+
this.PrimaryResultType = ResultType.Level;
1918
}
2019

21-
public override DatabaseList<GameLevel>? Fetch(RequestContext context, int skip, int count, DataContext dataContext,
20+
public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext,
2221
LevelFilterSettings levelFilterSettings, GameUser? _)
2322
{
2423
// try to find a contest by the query parameter
@@ -35,6 +34,6 @@ public ContestCategory() : base("contest", [], false)
3534
if (contest == null)
3635
return null;
3736

38-
return dataContext.Database.GetLevelsFromContest(contest, count, skip, dataContext.User, levelFilterSettings);
37+
return new(dataContext.Database.GetLevelsFromContest(contest, count, skip, dataContext.User, levelFilterSettings));
3938
}
4039
}
Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
11
using Bunkum.Core;
22
using Refresh.Core.Types.Data;
3-
using Refresh.Database;
4-
using Refresh.Database.Models.Levels;
53
using Refresh.Database.Models.Users;
64
using Refresh.Database.Query;
75

86
namespace Refresh.Core.Types.Categories.Levels;
97

10-
public class CoolLevelsCategory : GameLevelCategory
8+
public class CoolLevelsCategory : GameCategory
119
{
1210
public CoolLevelsCategory() : base("coolLevels", ["lbpcool", "lbp2cool", "cool", "hot"], false)
1311
{
1412
this.Name = "Cool Levels";
1513
this.Description = "Levels trending with players like you!";
1614
this.FontAwesomeIcon = "fire";
1715
this.IconHash = "g820625";
16+
this.PrimaryResultType = ResultType.Level;
1817
}
1918

20-
public override DatabaseList<GameLevel>? Fetch(RequestContext context, int skip, int count, DataContext dataContext,
19+
public override DatabaseResultList? Fetch(RequestContext context, int skip, int count, DataContext dataContext,
2120
LevelFilterSettings levelFilterSettings, GameUser? _)
2221
{
23-
return dataContext.Database.GetCoolLevels(count, skip, dataContext.User, levelFilterSettings);
22+
return new(dataContext.Database.GetCoolLevels(count, skip, dataContext.User, levelFilterSettings));
2423
}
2524
}

Refresh.Core/Types/Categories/Levels/CurrentlyPlayingCategory.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,18 @@
88

99
namespace Refresh.Core.Types.Categories.Levels;
1010

11-
public class CurrentlyPlayingCategory : GameLevelCategory
11+
public class CurrentlyPlayingCategory : GameCategory
1212
{
1313
internal CurrentlyPlayingCategory() : base("currentlyPlaying", "busiest", false)
1414
{
1515
this.Name = "Popular Now";
1616
this.Description = "Levels people are playing right now!";
1717
this.IconHash = "g820602";
1818
this.FontAwesomeIcon = "users";
19+
this.PrimaryResultType = ResultType.Level;
1920
}
2021

21-
public override DatabaseList<GameLevel>? Fetch(RequestContext context, int skip, int count,
22+
public override DatabaseResultList? Fetch(RequestContext context, int skip, int count,
2223
DataContext dataContext,
2324
LevelFilterSettings levelFilterSettings, GameUser? _)
2425
{
@@ -27,9 +28,9 @@ internal CurrentlyPlayingCategory() : base("currentlyPlaying", "busiest", false)
2728
.GroupBy(r => dataContext.Database.GetLevelById(r.LevelId))
2829
.OrderBy(r => r.Sum(room => room.PlayerIds.Count));
2930

30-
return new DatabaseList<GameLevel>(rooms.Select(r => r.Key)
31+
return new(new DatabaseList<GameLevel>(rooms.Select(r => r.Key)
3132
.Where(l => l != null && l.StoryId == 0)!
3233
.FilterByLevelFilterSettings(dataContext.User, levelFilterSettings)
33-
.FilterByGameVersion(levelFilterSettings.GameVersion), skip, count);
34+
.FilterByGameVersion(levelFilterSettings.GameVersion), skip, count));
3435
}
3536
}
Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
using Bunkum.Core;
22
using Refresh.Core.Types.Data;
3-
using Refresh.Database;
4-
using Refresh.Database.Models.Levels;
53
using Refresh.Database.Models.Users;
64
using Refresh.Database.Query;
75

86
namespace Refresh.Core.Types.Categories.Levels;
97

10-
public class DeveloperLevelsCategory : GameLevelCategory
8+
public class DeveloperLevelsCategory : GameCategory
119
{
1210
internal DeveloperLevelsCategory() : base("developer", [], false)
1311
{
@@ -16,10 +14,11 @@ internal DeveloperLevelsCategory() : base("developer", [], false)
1614
this.FontAwesomeIcon = "certificate";
1715
this.IconHash = "g820604";
1816
this.Hidden = true; // TODO: Set to false when we import story level names
17+
this.PrimaryResultType = ResultType.Level;
1918
}
2019

21-
public override DatabaseList<GameLevel>? Fetch(RequestContext context, int skip, int count,
20+
public override DatabaseResultList? Fetch(RequestContext context, int skip, int count,
2221
DataContext dataContext,
2322
LevelFilterSettings levelFilterSettings, GameUser? _)
24-
=> dataContext.Database.GetDeveloperLevels(count, skip, levelFilterSettings);
23+
=> new(dataContext.Database.GetDeveloperLevels(count, skip, levelFilterSettings));
2524
}

0 commit comments

Comments
 (0)