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 @@
-