Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions Runtime/Game/Requests/LootLockerBanRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ public class LootLockerBanInfo
/// </summary>
public string ban_reason { get; set; }

/// <summary>
/// A player-facing message describing the ban. Empty when no detail was provided.
/// </summary>
public string ban_detail { get; set; }
Comment thread
kirre-bylund marked this conversation as resolved.

/// <summary>
/// The time the ban was issued, as an ISO 8601 timestamp.
/// </summary>
Expand Down
17 changes: 15 additions & 2 deletions Tests/LootLockerTestUtils/LootLockerTestConfigurationBan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,21 @@ namespace LootLockerTestConfigurationUtils
{
public static class LootLockerTestPlayerBan
{
/// <summary>
/// Request body for the admin ban endpoint.
/// </summary>
private class BanPlayerRequest
{
public string ban_detail { get; set; }
}

/// <summary>
/// Bans a player using the admin API. Creates a permanent manual ban.
/// </summary>
/// <param name="playerUlid">The ULID of the player to ban.</param>
/// <param name="onComplete">Called with the raw response when the request completes.</param>
public static void BanPlayer(string playerUlid, Action<LootLockerResponse> onComplete)
/// <param name="banDetail">Optional player-facing ban message to store with the ban.</param>
public static void BanPlayer(string playerUlid, Action<LootLockerResponse> onComplete, string banDetail = null)
{
if (string.IsNullOrEmpty(LootLockerConfig.current.adminToken))
{
Expand All @@ -21,7 +30,11 @@ public static void BanPlayer(string playerUlid, Action<LootLockerResponse> onCom
var endpoint = LootLockerTestConfigurationEndpoints.banPlayer;
string formattedEndpoint = string.Format(endpoint.endPoint, playerUlid);

LootLockerAdminRequest.Send(formattedEndpoint, endpoint.httpMethod, "{}", serverResponse =>
string json = string.IsNullOrEmpty(banDetail)
? "{}"
: LootLockerJson.SerializeObject(new BanPlayerRequest { ban_detail = banDetail });

LootLockerAdminRequest.Send(formattedEndpoint, endpoint.httpMethod, json, serverResponse =>
{
onComplete?.Invoke(serverResponse);
}, true);
Expand Down
10 changes: 8 additions & 2 deletions Tests/LootLockerTests/PlayMode/BanTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,15 @@ public IEnumerator StartSession_ForBannedPlayer_Returns403WithBanInfo()
string playerUlid = sessionResponse.player_ulid;
LootLockerStateData.ClearAllSavedStates();

const string banDetail = "Banned by the integration test";

bool banCompleted = false;
LootLockerResponse banResponse = null;
LootLockerTestPlayerBan.BanPlayer(playerUlid, response =>
{
banResponse = response;
banCompleted = true;
});
}, banDetail);
yield return new WaitUntil(() => banCompleted);
Assert.IsTrue(banResponse?.success, "Failed to ban player via admin API");

Expand All @@ -157,6 +159,7 @@ public IEnumerator StartSession_ForBannedPlayer_Returns403WithBanInfo()
Assert.AreEqual("player_banned", bannedSessionResponse.errorData?.code, "Expected player_banned error code");
Assert.IsNotNull(bannedSessionResponse.errorData?.ban, "Expected ban info to be present in the error data");
Assert.IsFalse(string.IsNullOrEmpty(bannedSessionResponse.errorData?.ban?.ban_reason), "Expected ban_reason to be populated");
Assert.AreEqual(banDetail, bannedSessionResponse.errorData?.ban?.ban_detail, "Expected ban_detail to round-trip through the session start error data");
}

[UnityTest, Category("LootLocker"), Category("LootLockerCI")]
Expand All @@ -178,13 +181,15 @@ public IEnumerator GetPlayerBanStatus_ForBannedPlayer_ReturnsIsBannedWithDetails
string playerUlid = sessionResponse.player_ulid;
LootLockerStateData.ClearAllSavedStates();

const string banDetail = "Banned by the integration test";

bool banCompleted = false;
LootLockerResponse banResponse = null;
LootLockerTestPlayerBan.BanPlayer(playerUlid, response =>
{
banResponse = response;
banCompleted = true;
});
}, banDetail);
yield return new WaitUntil(() => banCompleted);
Assert.IsTrue(banResponse?.success, "Failed to ban player via admin API");

Expand All @@ -203,6 +208,7 @@ public IEnumerator GetPlayerBanStatus_ForBannedPlayer_ReturnsIsBannedWithDetails
Assert.IsTrue(banStatusResponse.is_banned, "Expected player to be banned");
Assert.IsNotNull(banStatusResponse.ban, "Expected ban details to be populated");
Assert.IsFalse(string.IsNullOrEmpty(banStatusResponse.ban?.ban_reason), "Expected ban_reason to be populated");
Assert.AreEqual(banDetail, banStatusResponse.ban?.ban_detail, "Expected ban_detail to round-trip through the ban status response");
Assert.IsFalse(string.IsNullOrEmpty(banStatusResponse.ban?.banned_on), "Expected banned_on to be populated");
Assert.IsTrue(banStatusResponse.ban?.permanent ?? false, "Expected permanent ban (no banned_until)");
}
Expand Down
Loading