Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement hearting and queueing levels through ApiV3 #681

Merged
merged 16 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Refresh.GameServer/Database/GameDatabaseContext.Relations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public partial class GameDatabaseContext // Relations
{
#region Favouriting Levels
[Pure]
private bool IsLevelFavouritedByUser(GameLevel level, GameUser user) => this.FavouriteLevelRelations
public bool IsLevelFavouritedByUser(GameLevel level, GameUser user) => this.FavouriteLevelRelations
.FirstOrDefault(r => r.Level == level && r.User == user) != null;

[Pure]
Expand Down Expand Up @@ -143,7 +143,7 @@ public bool UnfavouriteUser(GameUser userToFavourite, GameUser userFavouriting)

#region Queueing
[Pure]
private bool IsLevelQueuedByUser(GameLevel level, GameUser user) => this.QueueLevelRelations
public bool IsLevelQueuedByUser(GameLevel level, GameUser user) => this.QueueLevelRelations
.FirstOrDefault(r => r.Level == level && r.User == user) != null;

[Pure]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,21 @@ public class ApiGameLevelResponse : IApiResponse, IDataConvertableFrom<ApiGameLe
public required bool TeamPicked { get; set; }
public required DateTimeOffset? DateTeamPicked { get; set; }
public required GameLevelType LevelType { get; set; }
public required GameSlotType SlotType { get; set; }
public required bool IsLocked { get; set; }
public required bool IsSubLevel { get; set; }
public required bool IsCopyable { get; set; }
public required float Score { get; set; }
public required IEnumerable<Tag> Tags { get; set; }
public bool IsHearted { get; set; }
public bool IsQueued { get; set; }
jvyden marked this conversation as resolved.
Show resolved Hide resolved

public static ApiGameLevelResponse? FromOld(GameLevel? level, DataContext dataContext)
{
if (level == null) return null;


bool includeRelations = dataContext.User != null;

return new ApiGameLevelResponse
{
IsAdventure = level.IsAdventure,
Expand Down Expand Up @@ -85,6 +90,7 @@ public class ApiGameLevelResponse : IApiResponse, IDataConvertableFrom<ApiGameLe
RootLevelHash = level.RootResource,
GameVersion = level.GameVersion,
LevelType = level.LevelType,
SlotType = level.SlotType,
IsCopyable = level.IsCopyable,
IsLocked = level.IsLocked,
IsSubLevel = level.IsSubLevel,
Expand All @@ -94,6 +100,9 @@ public class ApiGameLevelResponse : IApiResponse, IDataConvertableFrom<ApiGameLe
Reviews = dataContext.Database.GetTotalReviewsForLevel(level),
Tags = dataContext.Database.GetTagsForLevel(level).Select(t => t.Tag),
IsModded = level.IsModded,
// Relation info
IsHearted = includeRelations && dataContext.Database.IsLevelFavouritedByUser(level, dataContext.User),
IsQueued = includeRelations && dataContext.Database.IsLevelQueuedByUser(level, dataContext.User)
};
}

Expand Down
103 changes: 103 additions & 0 deletions Refresh.GameServer/Endpoints/ApiV3/LevelApiEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using Refresh.GameServer.Types.Levels;
using Refresh.GameServer.Types.Levels.Categories;
using Refresh.GameServer.Types.UserData;
using Refresh.GameServer.Types.Roles;

namespace Refresh.GameServer.Endpoints.ApiV3;

Expand Down Expand Up @@ -174,4 +175,106 @@ public ApiOkResponse SetLevelAsOverrideByHash(RequestContext context, GameDataba

return new ApiOkResponse();
}


[ApiV3Endpoint("levels/hearted/username/{username}"), Authentication(false)]
[DocSummary("Gets a list of hearted levels by a user by their username")]
[DocError(typeof(ApiNotFoundError), ApiNotFoundError.UserMissingErrorWhen)]
public ApiListResponse<ApiGameLevelResponse> GetLevelsHeartedByUsername(RequestContext context, GameDatabaseContext database, IDataStore dataStore,
[DocSummary("The username of the user")] string username, DataContext dataContext, GameUser? accessingUser)
{
GameUser? user = database.GetUserByUsername(username);
if(user == null) return ApiNotFoundError.UserMissingError;

(int skip, int count) = context.GetPageData();
DatabaseList<GameLevel> levels = database.GetLevelsFavouritedByUser(user, count, skip, new LevelFilterSettings(context, TokenGame.Website), accessingUser);

DatabaseList<ApiGameLevelResponse> response = DatabaseList<ApiGameLevelResponse>.FromOldList<ApiGameLevelResponse, GameLevel>(levels, dataContext);
return response;
}
Beyley marked this conversation as resolved.
Show resolved Hide resolved

[ApiV3Endpoint("levels/hearted"), MinimumRole(GameUserRole.Restricted)]
[DocSummary("Gets a list of your own hearted levels")]
public ApiListResponse<ApiGameLevelResponse> GetLevelsHeartedByMe(RequestContext context, GameDatabaseContext database,
IDataStore dataStore, GameUser user, DataContext dataContext)
{
(int skip, int count) = context.GetPageData();
DatabaseList<GameLevel> levels = database.GetLevelsFavouritedByUser(user, count, skip, new LevelFilterSettings(context, TokenGame.Website), user);

DatabaseList<ApiGameLevelResponse> response = DatabaseList<ApiGameLevelResponse>.FromOldList<ApiGameLevelResponse, GameLevel>(levels, dataContext);
return response;
}
jvyden marked this conversation as resolved.
Show resolved Hide resolved
jvyden marked this conversation as resolved.
Show resolved Hide resolved

[ApiV3Endpoint("levels/id/{id}/heart", HttpMethods.Post)]
[DocSummary("Adds a specific level by it's ID to your hearted levels")]
[DocError(typeof(ApiNotFoundError), ApiNotFoundError.LevelMissingErrorWhen)]
public ApiOkResponse FavouriteLevel(RequestContext context, GameDatabaseContext database, GameUser user,
[DocSummary("The ID of the level")] int id)
{
GameLevel? level = database.GetLevelById(id);
if (level == null) return ApiNotFoundError.LevelMissingError;

database.FavouriteLevel(level, user);
return new ApiOkResponse();
}

[ApiV3Endpoint("levels/id/{id}/unheart", HttpMethods.Post)]
[DocSummary("Removes a specific level by it's ID from your hearted levels")]
[DocError(typeof(ApiNotFoundError), ApiNotFoundError.LevelMissingErrorWhen)]
public ApiOkResponse UnheartLevel(RequestContext context, GameDatabaseContext database, GameUser user,
[DocSummary("The ID of the level")] int id)
{
GameLevel? level = database.GetLevelById(id);
if (level == null) return ApiNotFoundError.LevelMissingError;

database.UnfavouriteLevel(level, user);
return new ApiOkResponse();
}

[ApiV3Endpoint("levels/queued"), MinimumRole(GameUserRole.Restricted)]
[DocSummary("Gets a list of your queued levels")]
public ApiListResponse<ApiGameLevelResponse> GetQueuedLevels(RequestContext context, GameDatabaseContext database,
IDataStore dataStore, GameUser user, DataContext dataContext)
{
(int skip, int count) = context.GetPageData();
DatabaseList<GameLevel> levels = database.GetLevelsQueuedByUser(user, count, skip, new LevelFilterSettings(context, TokenGame.Website), user);

DatabaseList<ApiGameLevelResponse> response = DatabaseList<ApiGameLevelResponse>.FromOldList<ApiGameLevelResponse, GameLevel>(levels, dataContext);
return response;
}
jvyden marked this conversation as resolved.
Show resolved Hide resolved

[ApiV3Endpoint("levels/queued/clear", HttpMethods.Post)]
[DocSummary("Clears your level queue")]
public ApiOkResponse ClearQueuedLevels(RequestContext context, GameDatabaseContext database,
IDataStore dataStore, GameUser user, DataContext dataContext)
{
database.ClearQueue(user);
return new ApiOkResponse();
}

[ApiV3Endpoint("levels/id/{id}/queue", HttpMethods.Post)]
[DocSummary("Adds a specific level by it's ID to your queue")]
[DocError(typeof(ApiNotFoundError), ApiNotFoundError.LevelMissingErrorWhen)]
public ApiOkResponse QueueLevel(RequestContext context, GameDatabaseContext database, GameUser user,
[DocSummary("The ID of the level")] int id)
{
GameLevel? level = database.GetLevelById(id);
if (level == null) return ApiNotFoundError.LevelMissingError;

database.QueueLevel(level, user);
return new ApiOkResponse();
}

[ApiV3Endpoint("levels/id/{id}/dequeue", HttpMethods.Post)]
[DocSummary("Removes a specific level by it's ID from your queue")]
[DocError(typeof(ApiNotFoundError), ApiNotFoundError.LevelMissingErrorWhen)]
public ApiOkResponse DequeueLevel(RequestContext context, GameDatabaseContext database, GameUser user,
[DocSummary("The ID of the level")] int id)
{
GameLevel? level = database.GetLevelById(id);
if (level == null) return ApiNotFoundError.LevelMissingError;

database.DequeueLevel(level, user);
return new ApiOkResponse();
}
}