IW4M-Admin/WebfrontCore/QueryHelpers/BanInfoResourceQueryHelper.cs
2022-07-05 12:02:43 -05:00

234 lines
8.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Data.Abstractions;
using Data.Models;
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<BanInfoRequest, BanInfo>
{
private readonly IDatabaseContextFactory _contextFactory;
public BanInfoResourceQueryHelper(IDatabaseContextFactory contextFactory)
{
_contextFactory = contextFactory;
}
public async Task<ResourceQueryHelperResult<BanInfo>> QueryResource(BanInfoRequest query)
{
if (query.Count > 10)
{
query.Count = 10;
}
await using var context = _contextFactory.CreateContext(false);
var iqMatchingClients = context.Clients.Where(client => client.Level == EFClient.Permission.Banned);
iqMatchingClients = SetupSearchArgs(query, iqMatchingClients);
if (string.IsNullOrEmpty(query.ClientName) && string.IsNullOrEmpty(query.ClientGuid) &&
query.ClientId is null && string.IsNullOrEmpty(query.ClientIP))
{
return new ResourceQueryHelperResult<BanInfo>
{
Results = Enumerable.Empty<BanInfo>()
};
}
var matchingClients = await iqMatchingClients
.OrderByDescending(client => client.LastConnection)
.Skip(query.Offset)
.Take(query.Count)
.Select(client => new
{
client.CurrentAlias.Name,
client.NetworkId,
client.AliasLinkId,
client.ClientId,
client.CurrentAlias.IPAddress,
client.GameName
}).ToListAsync();
var results = new List<BanInfo>();
var matchedClientIds = new List<int?>();
var lateDateTime = DateTime.Now.AddYears(100);
// would prefer not to loop this, but unfortunately due to the data design
// we can't properly group on ip and alias link
foreach (var matchingClient in matchingClients)
{
var usedIps = await context.Aliases
.Where(alias => matchingClient.AliasLinkId == alias.LinkId)
.Where(alias => alias.IPAddress != null)
.Select(alias => new { alias.IPAddress, alias.LinkId })
.ToListAsync();
var searchingNetworkId = matchingClient.NetworkId;
var searchingIps = usedIps.Select(ip => ip.IPAddress).Distinct();
var matchedPenalties = await context.PenaltyIdentifiers.Where(identifier =>
identifier.NetworkId == searchingNetworkId ||
searchingIps.Contains(identifier.IPv4Address))
.Where(identifier => identifier.Penalty.Expires == null || identifier.Penalty.Expires > lateDateTime)
.Select(penalty => new
{
penalty.CreatedDateTime,
PunisherName = penalty.Penalty.Punisher.CurrentAlias.Name,
OffenderName = penalty.Penalty.Offender.CurrentAlias.Name,
Offense = string.IsNullOrEmpty(penalty.Penalty.AutomatedOffense)
? penalty.Penalty.Offense
: Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_BAN_INFO_AC_DETECTION"],
LinkId = penalty.Penalty.Offender.AliasLinkId,
penalty.Penalty.OffenderId,
penalty.Penalty.PunisherId,
penalty.IPv4Address,
penalty.Penalty.Offender.NetworkId
})
.ToListAsync();
if (!matchedPenalties.Any())
{
var linkIds = (await context.Aliases
.Where(alias => alias.IPAddress != null && searchingIps.Contains(alias.IPAddress))
.Select(alias => alias.LinkId)
.ToListAsync()).Distinct();
matchedPenalties = await context.Penalties.Where(penalty => penalty.Type == EFPenalty.PenaltyType.Ban)
.Where(penalty => penalty.Expires == null || penalty.Expires > lateDateTime)
.Where(penalty => penalty.LinkId != null && linkIds.Contains(penalty.LinkId.Value))
.OrderByDescending(penalty => penalty.When)
.Select(penalty => new
{
CreatedDateTime = penalty.When,
PunisherName = penalty.Punisher.CurrentAlias.Name,
OffenderName = penalty.Offender.CurrentAlias.Name,
Offense = string.IsNullOrEmpty(penalty.AutomatedOffense)
? penalty.Offense
: Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_BAN_INFO_AC_DETECTION"],
LinkId = penalty.Offender.AliasLinkId,
penalty.OffenderId,
penalty.PunisherId,
IPv4Address = penalty.Offender.CurrentAlias.IPAddress,
penalty.Offender.NetworkId
}).ToListAsync();
}
var allPenalties = matchedPenalties.Select(penalty => new PenaltyInfo
{
DateTime = penalty.CreatedDateTime,
Offense = penalty.Offense,
PunisherInfo = new RelatedClientInfo
{
ClientName = penalty.PunisherName.StripColors(),
ClientId = penalty.PunisherId,
},
OffenderInfo = new RelatedClientInfo
{
ClientName = penalty.OffenderName.StripColors(),
ClientId = penalty.OffenderId,
IPAddress = penalty.IPv4Address,
NetworkId = penalty.NetworkId
}
}).ToList();
if (matchedClientIds.Contains(matchingClient.ClientId))
{
continue;
}
matchedClientIds.Add(matchingClient.ClientId);
var relatedEntities =
allPenalties.Where(penalty => penalty.OffenderInfo.ClientId != matchingClient.ClientId);
matchedClientIds.AddRange(relatedEntities.Select(client => client.OffenderInfo.ClientId));
results.Add(new BanInfo
{
ClientName = matchingClient.Name.StripColors(),
ClientId = matchingClient.ClientId,
NetworkId = matchingClient.NetworkId,
IPAddress = matchingClient.IPAddress,
Game = matchingClient.GameName,
AssociatedPenalties = relatedEntities,
AttachedPenalty = allPenalties.FirstOrDefault(penalty =>
penalty.OffenderInfo.ClientId == matchingClient.ClientId)
});
}
return new ResourceQueryHelperResult<BanInfo>
{
RetrievedResultCount = results.Count,
TotalResultCount = results.Count,
Results = results
};
}
private IQueryable<EFClient> SetupSearchArgs(BanInfoRequest query, IQueryable<EFClient> source)
{
if (!string.IsNullOrEmpty(query.ClientName))
{
var nameToSearch = query.ClientName.Trim().ToLower();
source = source.Where(client =>
EF.Functions.Like(client.CurrentAlias.SearchableName ?? client.CurrentAlias.Name.ToLower(),
$"%{nameToSearch}%"));
}
if (!string.IsNullOrEmpty(query.ClientGuid))
{
long? parsedGuid = null;
if (!long.TryParse(query.ClientGuid, NumberStyles.HexNumber, null, out var guid))
{
if (!long.TryParse(query.ClientGuid, out var guid2))
{
}
else
{
parsedGuid = guid2;
}
}
else
{
parsedGuid = guid;
}
if (parsedGuid is not null)
{
source = source.Where(client => client.NetworkId == parsedGuid);
}
}
if (query.ClientId is not null)
{
source = source.Where(client => client.ClientId == query.ClientId);
}
if (string.IsNullOrEmpty(query.ClientIP))
{
return source;
}
var parsedIp = query.ClientIP.ConvertToIP();
if (parsedIp is not null)
{
source = source.Where(client => client.CurrentAlias.IPAddress == parsedIp);
}
else
{
query.ClientIP = null;
}
return source;
}
}