mirror of
https://github.com/JogmansonReal/Radicade.git
synced 2026-10-25 23:18:56 -07:00
Radicade Public Code
This commit is contained in:
@@ -0,0 +1,269 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using RadicadeServer.API.Moderation;
|
||||
using RadicadeServer.DB;
|
||||
using RadicadeServer.RecNet.Accounts;
|
||||
using RadicadeServer.RecNet.Auth;
|
||||
using RadicadeServer.RecNet.Enums.Moderation;
|
||||
using RadicadeServer.RecNet.Moderation;
|
||||
using RadicadeServer.Utils;
|
||||
using Xunit;
|
||||
|
||||
namespace RadicadeServer.Tests;
|
||||
|
||||
[Collection(DbFactoryCollection.Name)]
|
||||
public class ModerationBlockDetailsTests
|
||||
{
|
||||
private static RecDBContext NewDb() => new(
|
||||
TestDbOptions.Create()
|
||||
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
||||
.Options);
|
||||
|
||||
private static PlayerReportingAPI NewApi(RecDBContext db, long? accountId)
|
||||
{
|
||||
var identity = new ClaimsIdentity("TestAuth");
|
||||
if (accountId.HasValue)
|
||||
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, accountId.Value.ToString()));
|
||||
return new PlayerReportingAPI(
|
||||
db)
|
||||
{
|
||||
ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal(identity) }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static void AssertReportSucceeded(ActionResult<OkResponse> result)
|
||||
{
|
||||
var ok = Assert.IsType<OkObjectResult>(result.Result);
|
||||
Assert.True(Assert.IsType<OkResponse>(ok.Value).Success);
|
||||
}
|
||||
|
||||
private static async Task AddReporterAsync(RecDBContext db, long accountId, string? roles = null)
|
||||
{
|
||||
db.Profiles.Add(new Profile
|
||||
{
|
||||
accountId = accountId,
|
||||
username = $"reporter{accountId}",
|
||||
displayName = $"Reporter {accountId}",
|
||||
profileImage = DBConfig.DefaultProfileImage,
|
||||
role = roles
|
||||
});
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, false)]
|
||||
[InlineData(5, false)]
|
||||
[InlineData(6, true)]
|
||||
[InlineData(7, true)]
|
||||
public void AutomaticTimeoutRequiresMoreThanFiveReportsFromAPlayer(int reportCount, bool expected)
|
||||
{
|
||||
Assert.Equal(expected, PlayerReportingAPI.ShouldApplyAutomaticTimeout(reportCount, reporterIsModerator: false));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TheSixthPublicReportCreatesAnAutomaticTimeout()
|
||||
{
|
||||
using var db = NewDb();
|
||||
await AddReporterAsync(db, 6);
|
||||
db.Reputations.Add(new Reputation { AccountId = 42, ReportCount = 5 });
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
AssertReportSucceeded(await NewApi(db, 6).CreateReport(new CreateReportRequest
|
||||
{
|
||||
PlayerIdReported = 42,
|
||||
ReportCategory = ReportCategory.CoC_Trolling,
|
||||
Details = "report details",
|
||||
RoomId = 0
|
||||
}));
|
||||
|
||||
var moderation = await db.Moderation.SingleAsync();
|
||||
Assert.Equal("Automatic Timeout", moderation.BanMethod);
|
||||
Assert.Equal("You have received a timeout due to a high number of reports for Trolling.", moderation.Message);
|
||||
Assert.True(moderation.CreatedAt <= DateTime.UtcNow);
|
||||
Assert.Equal(6, (await db.Reputations.SingleAsync(x => x.AccountId == 42)).ReportCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SelfAndUnauthenticatedReportsDoNotCountTowardAutomaticTimeouts()
|
||||
{
|
||||
using var db = NewDb();
|
||||
db.Reputations.Add(new Reputation { AccountId = 42, ReportCount = 5 });
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
AssertReportSucceeded(await NewApi(db, 42).CreateReport(new CreateReportRequest
|
||||
{
|
||||
PlayerIdReported = 42,
|
||||
ReportCategory = ReportCategory.CoC_Trolling
|
||||
}));
|
||||
Assert.Empty(await db.Moderation.ToListAsync());
|
||||
Assert.Equal(5, (await db.Reputations.SingleAsync(x => x.AccountId == 42)).ReportCount);
|
||||
|
||||
AssertReportSucceeded(await NewApi(db, null).CreateReport(new CreateReportRequest
|
||||
{
|
||||
PlayerIdReported = 42,
|
||||
ReportCategory = ReportCategory.CoC_Trolling
|
||||
}));
|
||||
Assert.Empty(await db.Moderation.ToListAsync());
|
||||
Assert.Equal(5, (await db.Reputations.SingleAsync(x => x.AccountId == 42)).ReportCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ModeratorReportCreatesDirectTimeoutWithoutAlsoUsingPublicReportEscalation()
|
||||
{
|
||||
using var db = NewDb();
|
||||
await AddReporterAsync(db, 6, "moderator");
|
||||
db.Reputations.Add(new Reputation { AccountId = 42, ReportCount = 0 });
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
AssertReportSucceeded(await NewApi(db, 6).CreateReport(new CreateReportRequest
|
||||
{
|
||||
PlayerIdReported = 42,
|
||||
ReportCategory = ReportCategory.CoC_Trolling,
|
||||
Details = "Moderator observed trolling"
|
||||
}));
|
||||
|
||||
var moderation = await db.Moderation.SingleAsync();
|
||||
Assert.Equal("Moderator Report", moderation.BanMethod);
|
||||
Assert.Equal("Moderator observed trolling", moderation.Message);
|
||||
Assert.Equal(0, (await db.Reputations.SingleAsync(x => x.AccountId == 42)).ReportCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvalidReportCategoryIsRejectedBeforeItCounts()
|
||||
{
|
||||
using var db = NewDb();
|
||||
await AddReporterAsync(db, 6);
|
||||
|
||||
var result = await NewApi(db, 6).CreateReport(new CreateReportRequest
|
||||
{
|
||||
PlayerIdReported = 42,
|
||||
ReportCategory = (ReportCategory)9999
|
||||
});
|
||||
|
||||
Assert.IsType<BadRequestObjectResult>(result.Result);
|
||||
Assert.Empty(await db.Reputations.ToListAsync());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(ReportCategory.CoC_Trolling, "Trolling")]
|
||||
[InlineData(ReportCategory.CoC_Sexual, "Sexual behavior")]
|
||||
public void AutomaticTimeoutReasonUsesTheReportCategory(ReportCategory category, string expected)
|
||||
{
|
||||
Assert.Equal(expected, PlayerReportingAPI.GetAutomaticTimeoutReason(category));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task VoiceModerationBlockDetailsCarryStartTimeButNotModeratorOnlyNote()
|
||||
{
|
||||
using var db = NewDb();
|
||||
var startedAt = DateTime.UtcNow;
|
||||
db.Moderation.Add(new ModerationDB
|
||||
{
|
||||
PlayerId = 42,
|
||||
IsBan = true,
|
||||
Message = "Sexually explicit behavior or photos",
|
||||
ModeratorNote = "Sexual harassment in the Rec Center",
|
||||
BanMethod = "Voice Moderation",
|
||||
Category = ReportCategory.CoC_Sexual,
|
||||
CreatedAt = startedAt,
|
||||
ExpireDuration = startedAt.AddDays(1),
|
||||
AppealCode = "ABC12345"
|
||||
});
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
var api = NewApi(db, 42);
|
||||
api.ControllerContext.HttpContext.Request.Headers["X-Forwarded-For"] = "192.0.2.42";
|
||||
var result = Assert.IsType<OkObjectResult>(await api.GetBlockDetails());
|
||||
var details = Assert.IsType<BlockDetails>(result.Value);
|
||||
|
||||
Assert.Equal(startedAt, details.TimeoutStartedAt);
|
||||
Assert.Equal("VoiceModeration", details.BanType);
|
||||
Assert.Equal("Sexually explicit behavior or photos", details.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Automatic Timeout", "You have received a timeout due to a high number of reports for Trolling", "You have received a timeout due to a high number of reports for Trolling.")]
|
||||
[InlineData("Moderator Report", "You were reported by a moderator", "You have received a timeout. You were reported by a moderator.")]
|
||||
[InlineData("Moderator Report", "You were reported by a moderator.", "You have received a timeout. a moderator report.")]
|
||||
[InlineData("Timeout", "Trolling", "You have received a timeout due to a high number of reports for Trolling.")]
|
||||
[InlineData("Automatic Timeout", "You have received a timeout due to a high number of reports for Trolling.", "You have received a timeout due to a high number of reports for Trolling.")]
|
||||
public async Task PersistedTimeoutBanHasClientFacingTimeoutCopy(string banMethod, string storedReason, string expectedMessage)
|
||||
{
|
||||
using var db = NewDb();
|
||||
var startedAt = DateTime.UtcNow;
|
||||
db.Moderation.Add(new ModerationDB
|
||||
{
|
||||
PlayerId = 42,
|
||||
IsBan = true,
|
||||
Message = storedReason,
|
||||
BanMethod = banMethod,
|
||||
Category = ReportCategory.CoC_Trolling,
|
||||
CreatedAt = startedAt,
|
||||
ExpireDuration = startedAt.AddHours(1),
|
||||
AppealCode = "ABC12345"
|
||||
});
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
var api = NewApi(db, 42);
|
||||
api.ControllerContext.HttpContext.Request.Headers["X-Forwarded-For"] = "192.0.2.42";
|
||||
var result = Assert.IsType<OkObjectResult>(await api.GetBlockDetails());
|
||||
var details = Assert.IsType<BlockDetails>(result.Value);
|
||||
|
||||
Assert.Equal("Timeout", details.BanType);
|
||||
Assert.Equal(startedAt, details.TimeoutStartedAt);
|
||||
Assert.Equal(expectedMessage, details.DisplayReason);
|
||||
Assert.Equal(expectedMessage, details.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HardwareBanShowsTheOriginalRelatedAccountOnItsOwnLine()
|
||||
{
|
||||
using var db = NewDb();
|
||||
var startedAt = DateTime.UtcNow;
|
||||
db.Players.Add(new PlayerData { AccountId = 42, DeviceId = "shared-device" });
|
||||
db.Profiles.Add(new Profile
|
||||
{
|
||||
accountId = 12,
|
||||
username = "HealthyMoose640",
|
||||
displayName = "HealthyMoose640",
|
||||
profileImage = DBConfig.DefaultProfileImage
|
||||
});
|
||||
db.HardwareBans.Add(new HardwareBan
|
||||
{
|
||||
DeviceId = "shared-device",
|
||||
BannedAccountId = 12,
|
||||
Reason = "Moderator. Account ban",
|
||||
CreatedAt = startedAt,
|
||||
ExpiresAt = startedAt.AddDays(1)
|
||||
});
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
var api = NewApi(db, 42);
|
||||
api.ControllerContext.HttpContext.Request.Headers["X-Forwarded-For"] = "192.0.2.42";
|
||||
var result = Assert.IsType<OkObjectResult>(await api.GetBlockDetails());
|
||||
var details = Assert.IsType<BlockDetails>(result.Value);
|
||||
|
||||
Assert.Contains("\nRelated account: @HealthyMoose640", details.Message);
|
||||
Assert.Equal(startedAt, details.TimeoutStartedAt);
|
||||
}
|
||||
|
||||
/* Every ban the client is shown has to carry the moment it started, because
|
||||
that is the "Banned since" line. Kicks must not: they are not bans and the
|
||||
screen has nothing to date. */
|
||||
[Fact]
|
||||
public void BanBlockDetailsCarryBannedSinceWhileKicksDoNot()
|
||||
{
|
||||
var startedAt = DateTime.UtcNow.AddDays(-3);
|
||||
|
||||
var ban = PlayerUtils.BuildBlockDetails(true, ReportCategory.Misc, "reason", startedAt.AddDays(5), startedAtUtc: startedAt);
|
||||
Assert.Equal(startedAt, ban.TimeoutStartedAt);
|
||||
|
||||
var kick = PlayerUtils.BuildBlockDetails(true, ReportCategory.Misc, "kicked", DateTime.UtcNow.AddMinutes(15));
|
||||
Assert.Null(kick.TimeoutStartedAt);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user