diff --git a/IW4MAdmin.sln b/IW4MAdmin.sln index 42c29352..bee433cf 100644 --- a/IW4MAdmin.sln +++ b/IW4MAdmin.sln @@ -53,6 +53,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ScriptPlugins", "ScriptPlug Plugins\ScriptPlugins\GameInterface.js = Plugins\ScriptPlugins\GameInterface.js Plugins\ScriptPlugins\SubnetBan.js = Plugins\ScriptPlugins\SubnetBan.js Plugins\ScriptPlugins\BanBroadcasting.js = Plugins\ScriptPlugins\BanBroadcasting.js + Plugins\ScriptPlugins\ParserH1MOD.js = Plugins\ScriptPlugins\ParserH1MOD.js EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutomessageFeed", "Plugins\AutomessageFeed\AutomessageFeed.csproj", "{F5815359-CFC7-44B4-9A3B-C04BACAD5836}" diff --git a/SharedLibraryCore/Dtos/PaginationRequest.cs b/SharedLibraryCore/Dtos/PaginationRequest.cs index bb6c7b39..d9a7312a 100644 --- a/SharedLibraryCore/Dtos/PaginationRequest.cs +++ b/SharedLibraryCore/Dtos/PaginationRequest.cs @@ -13,7 +13,7 @@ namespace SharedLibraryCore.Dtos public int Offset { get; set; } /// - /// how many itesm to take + /// how many items to take /// public int Count { get; set; } = 100; @@ -35,4 +35,4 @@ namespace SharedLibraryCore.Dtos Ascending, Descending } -} \ No newline at end of file +} diff --git a/WebfrontCore/Controllers/API/PenaltyController.cs b/WebfrontCore/Controllers/API/PenaltyController.cs new file mode 100644 index 00000000..56e01ef5 --- /dev/null +++ b/WebfrontCore/Controllers/API/PenaltyController.cs @@ -0,0 +1,25 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using SharedLibraryCore; +using SharedLibraryCore.Interfaces; +using WebfrontCore.QueryHelpers.Models; + +namespace WebfrontCore.Controllers.API; + +[Route("api/[controller]")] +public class PenaltyController : BaseController +{ + private readonly IResourceQueryHelper _banInfoQueryHelper; + + public PenaltyController(IManager manager, IResourceQueryHelper banInfoQueryHelper) : base(manager) + { + _banInfoQueryHelper = banInfoQueryHelper; + } + + [HttpGet("BanInfo/{clientName}")] + public async Task BanInfo(BanInfoRequest request) + { + var result = await _banInfoQueryHelper.QueryResource(request); + return Json(result); + } +} diff --git a/WebfrontCore/QueryHelpers/BanInfoResourceQueryHelper.cs b/WebfrontCore/QueryHelpers/BanInfoResourceQueryHelper.cs new file mode 100644 index 00000000..69ceeab0 --- /dev/null +++ b/WebfrontCore/QueryHelpers/BanInfoResourceQueryHelper.cs @@ -0,0 +1,96 @@ +using System.Linq; +using System.Threading.Tasks; +using Data.Abstractions; +using Data.Models.Client; +using Microsoft.EntityFrameworkCore; +using SharedLibraryCore; +using SharedLibraryCore.Helpers; +using SharedLibraryCore.Interfaces; +using WebfrontCore.QueryHelpers.Models; + +namespace WebfrontCore.QueryHelpers; + +public class BanInfoResourceQueryHelper : IResourceQueryHelper +{ + private readonly IDatabaseContextFactory _contextFactory; + + public BanInfoResourceQueryHelper(IDatabaseContextFactory contextFactory) + { + _contextFactory = contextFactory; + } + + public async Task> QueryResource(BanInfoRequest query) + { + if (query.Count > 30) + { + query.Count = 30; + } + + await using var context = _contextFactory.CreateContext(false); + + var matchingClients = await context.Clients.Where(client => + EF.Functions.ILike(client.CurrentAlias.SearchableName ?? client.CurrentAlias.Name, $"%{query.ClientName.Trim()}%")) + .Where(client => client.Level == EFClient.Permission.Banned) + .OrderByDescending(client => client.LastConnection) + .Skip(query.Offset) + .Take(query.Count) + .Select(client => new + { + client.CurrentAlias.Name, + client.NetworkId, + client.AliasLinkId, + client.ClientId + }).ToListAsync(); + + var usedIps = await context.Aliases + .Where(alias => matchingClients.Select(client => client.AliasLinkId).Contains(alias.LinkId)) + .Where(alias => alias.IPAddress != null) + .Select(alias => new { alias.IPAddress, alias.LinkId }) + .ToListAsync(); + + var usedIpsGrouped = usedIps + .GroupBy(alias => alias.LinkId) + .ToDictionary(key => key.Key, value => value.Select(alias => alias.IPAddress).Distinct()); + + var searchingNetworkIds = matchingClients.Select(client => client.NetworkId); + var searchingIps = usedIpsGrouped.SelectMany(group => group.Value); + + var matchedPenalties = await context.PenaltyIdentifiers.Where(identifier => + searchingNetworkIds.Contains(identifier.NetworkId) || + searchingIps.Contains(identifier.IPv4Address)) + .Select(penalty => new + { + penalty.CreatedDateTime, + PunisherName = penalty.Penalty.Punisher.CurrentAlias.Name, + Offense = string.IsNullOrEmpty(penalty.Penalty.AutomatedOffense) ? penalty.Penalty.Offense : "Anticheat Detection", + LinkId = penalty.Penalty.Offender.AliasLinkId, + penalty.Penalty.PunisherId + }) + .ToListAsync(); + + var groupedPenalties = matchedPenalties.GroupBy(penalty => penalty.LinkId) + .ToDictionary(key => key.Key, value => value.FirstOrDefault()); + + var results = matchingClients.Select(client => + { + var matchedPenalty = + groupedPenalties.ContainsKey(client.AliasLinkId) ? groupedPenalties[client.AliasLinkId] : null; + return new BanInfo + { + DateTime = matchedPenalty?.CreatedDateTime, + OffenderName = client.Name.StripColors(), + OffenderId = client.ClientId, + PunisherName = matchedPenalty?.PunisherName.StripColors(), + PunisherId = matchedPenalty?.PunisherId, + Offense = matchedPenalty?.Offense + }; + }).ToList(); + + return new ResourceQueryHelperResult + { + RetrievedResultCount = results.Count, + TotalResultCount = results.Count, + Results = results + }; + } +} diff --git a/WebfrontCore/QueryHelpers/Models/BanInfo.cs b/WebfrontCore/QueryHelpers/Models/BanInfo.cs new file mode 100644 index 00000000..8fdd1adc --- /dev/null +++ b/WebfrontCore/QueryHelpers/Models/BanInfo.cs @@ -0,0 +1,12 @@ +using System; + +public class BanInfo +{ + public string OffenderName { get; set; } + public int OffenderId { get; set; } + public string PunisherName { get; set; } + public int? PunisherId { get; set; } + public string Offense { get; set; } + public DateTime? DateTime { get; set; } + public long? TimeStamp => DateTime.HasValue ? new DateTimeOffset(DateTime.Value, TimeSpan.Zero).ToUnixTimeSeconds() : null; +} diff --git a/WebfrontCore/QueryHelpers/Models/BanInfoRequest.cs b/WebfrontCore/QueryHelpers/Models/BanInfoRequest.cs new file mode 100644 index 00000000..c9236305 --- /dev/null +++ b/WebfrontCore/QueryHelpers/Models/BanInfoRequest.cs @@ -0,0 +1,8 @@ +using SharedLibraryCore.Dtos; + +namespace WebfrontCore.QueryHelpers.Models; + +public class BanInfoRequest : PaginationRequest +{ + public string ClientName { get; set; } +} diff --git a/WebfrontCore/Startup.cs b/WebfrontCore/Startup.cs index 723945c9..c88fcb55 100644 --- a/WebfrontCore/Startup.cs +++ b/WebfrontCore/Startup.cs @@ -24,11 +24,12 @@ using System.Reflection; using System.Threading.Tasks; using Data.Abstractions; using Data.Helpers; -using IW4MAdmin.Plugins.Stats.Config; using Stats.Client.Abstractions; using Stats.Config; using WebfrontCore.Controllers.API.Validation; using WebfrontCore.Middleware; +using WebfrontCore.QueryHelpers; +using WebfrontCore.QueryHelpers.Models; namespace WebfrontCore { @@ -127,6 +128,7 @@ namespace WebfrontCore services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService()); services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService()); services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService()); + services.AddSingleton, BanInfoResourceQueryHelper>(); services.AddSingleton( Program.ApplicationServiceProvider.GetRequiredService()); services.AddSingleton(Program.ApplicationServiceProvider diff --git a/WebfrontCore/WebfrontCore.csproj b/WebfrontCore/WebfrontCore.csproj index 11dafe0c..203832c5 100644 --- a/WebfrontCore/WebfrontCore.csproj +++ b/WebfrontCore/WebfrontCore.csproj @@ -56,7 +56,6 @@ -