Skip to content

Commit

Permalink
Allow admins to edit user's levels (#318)
Browse files Browse the repository at this point in the history
Also adds the ability for admins to adjust the level's GameVersion

Closes #129
  • Loading branch information
jvyden authored Jan 2, 2024
2 parents 04b7c60 + 0f9120d commit 6707393
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 4 deletions.
2 changes: 1 addition & 1 deletion Refresh.GameServer/Database/GameDatabaseContext.Levels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public GameLevel UpdateLevel(ApiEditLevelRequest body, GameLevel level)
{
this._realm.Write(() =>
{
PropertyInfo[] userProps = typeof(ApiEditLevelRequest).GetProperties();
PropertyInfo[] userProps = body.GetType().GetProperties();
foreach (PropertyInfo prop in userProps)
{
if (!prop.CanWrite || !prop.CanRead) continue;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using AttribDoc.Attributes;
using Bunkum.Core;
using Bunkum.Core.Endpoints;
using Bunkum.Listener.Protocol;
using Bunkum.Protocols.Http;
using Refresh.GameServer.Database;
using Refresh.GameServer.Endpoints.ApiV3.ApiTypes;
using Refresh.GameServer.Endpoints.ApiV3.ApiTypes.Errors;
using Refresh.GameServer.Endpoints.ApiV3.DataTypes.Request;
using Refresh.GameServer.Endpoints.ApiV3.DataTypes.Response;
using Refresh.GameServer.Types.Levels;
using Refresh.GameServer.Types.Roles;
using Refresh.GameServer.Types.UserData;
Expand Down Expand Up @@ -39,6 +40,21 @@ public ApiOkResponse RemoveTeamPickFromLevel(RequestContext context, GameDatabas
return new ApiOkResponse();
}

[ApiV3Endpoint("admin/levels/id/{id}", HttpMethods.Patch), MinimumRole(GameUserRole.Admin)]
[DocSummary("Updates a level.")]
[DocError(typeof(ApiNotFoundError), ApiNotFoundError.LevelMissingErrorWhen)]
[DocError(typeof(ApiAuthenticationError), ApiAuthenticationError.NoPermissionsForObjectWhen)]
public ApiResponse<ApiGameLevelResponse> EditLevelById(RequestContext context, GameDatabaseContext database, GameUser user,
[DocSummary("The ID of the level")] int id, ApiAdminEditLevelRequest body)
{
GameLevel? level = database.GetLevelById(id);
if (level == null) return ApiNotFoundError.LevelMissingError;

level = database.UpdateLevel(body, level);

return ApiGameLevelResponse.FromOld(level);
}

[ApiV3Endpoint("admin/levels/id/{id}", HttpMethods.Delete), MinimumRole(GameUserRole.Admin)]
[DocSummary("Deletes a level.")]
[DocError(typeof(ApiNotFoundError), ApiNotFoundError.LevelMissingErrorWhen)]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Refresh.GameServer.Authentication;

namespace Refresh.GameServer.Endpoints.ApiV3.DataTypes.Request;

[JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
public class ApiAdminEditLevelRequest : ApiEditLevelRequest
{
public TokenGame? GameVersion { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Refresh.GameServer.Authentication;

namespace Refresh.GameServer.Endpoints.ApiV3.DataTypes.Request;

[JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
Expand Down
5 changes: 3 additions & 2 deletions Refresh.GameServer/Endpoints/ApiV3/LevelApiEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Refresh.GameServer.Services;
using Refresh.GameServer.Types.Levels;
using Refresh.GameServer.Types.Levels.Categories;
using Refresh.GameServer.Types.Roles;
using Refresh.GameServer.Types.UserData;

namespace Refresh.GameServer.Endpoints.ApiV3;
Expand Down Expand Up @@ -79,11 +80,11 @@ public ApiResponse<ApiGameLevelResponse> EditLevelById(RequestContext context, G
{
GameLevel? level = database.GetLevelById(id);
if (level == null) return ApiNotFoundError.LevelMissingError;

if (level.Publisher?.UserId != user.UserId)
return ApiAuthenticationError.NoPermissionsForObject;

database.UpdateLevel(body, level);
level = database.UpdateLevel(body, level);

return ApiGameLevelResponse.FromOld(level);
}
Expand Down
8 changes: 8 additions & 0 deletions RefreshTests.GameServer/TestContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Refresh.GameServer.Database;
using Refresh.GameServer.Types;
using Refresh.GameServer.Types.Levels;
using Refresh.GameServer.Types.Roles;
using Refresh.GameServer.Types.UserData;
using Refresh.GameServer.Types.UserData.Leaderboard;
using RefreshTests.GameServer.Time;
Expand Down Expand Up @@ -95,6 +96,13 @@ public GameUser CreateUser(string? username = null)
return this.Database.CreateUser(username, $"{username}@{username}.local");
}

public GameUser CreateAdmin(string? username = null)
{
GameUser user = this.CreateUser(username);
this.Database.SetUserRole(user, GameUserRole.Admin);
return user;
}

public Token CreateToken(GameUser user, TokenType type = TokenType.Game, TokenGame game = TokenGame.LittleBigPlanet2, TokenPlatform platform = TokenPlatform.PS3)
{
return this.Database.GenerateTokenForUser(user, type, game, platform);
Expand Down
33 changes: 33 additions & 0 deletions RefreshTests.GameServer/Tests/ApiV3/EditApiTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Refresh.GameServer.Authentication;
using Refresh.GameServer.Endpoints.ApiV3.DataTypes.Request;
using Refresh.GameServer.Types.Levels;
using Refresh.GameServer.Types.Roles;
using Refresh.GameServer.Types.UserData;

namespace RefreshTests.GameServer.Tests.ApiV3;
Expand Down Expand Up @@ -60,6 +61,38 @@ public void OtherUserCantUpdateLevel()
Assert.That(level.Title, Is.EqualTo("Not updated"));
});
}

[Test]
public void AdminCanUpdateLevel()
{
using TestContext context = this.GetServer();
GameUser user = context.CreateUser();
GameUser admin = context.CreateAdmin();
GameLevel level = context.CreateLevel(user, "Not updated");

long oldUpdate = level.UpdateDate;

ApiAdminEditLevelRequest payload = new()
{
Title = "Updated",
GameVersion = TokenGame.LittleBigPlanetPSP,
};

context.Time.TimestampMilliseconds = 1;

using HttpClient client = context.GetAuthenticatedClient(TokenType.Api, admin);
HttpResponseMessage response = client.PatchAsync($"/api/v3/admin/levels/id/{level.LevelId}", JsonContent.Create(payload)).Result;
Assert.That(response.StatusCode, Is.EqualTo(OK));

context.Database.Refresh();
Assert.Multiple(() =>
{
Assert.That(level.Title, Is.EqualTo("Updated"));
Assert.That(level.GameVersion, Is.EqualTo(TokenGame.LittleBigPlanetPSP));
Assert.That(level.UpdateDate, Is.Not.EqualTo(oldUpdate));
Assert.That(level.UpdateDate, Is.EqualTo(context.Time.TimestampMilliseconds));
});
}

[Test]
public void CantUpdateMissingLevel()
Expand Down

0 comments on commit 6707393

Please sign in to comment.