diff --git a/Application/Server.cs b/Application/Server.cs index facabb9c5..02e76f6e0 100644 --- a/Application/Server.cs +++ b/Application/Server.cs @@ -197,7 +197,8 @@ namespace IW4MAdmin Players[player.ClientNumber] = player; var activePenalties = await Manager.GetPenaltyService().GetActivePenaltiesAsync(player.AliasLinkId, player.IPAddress); - var currentBan = activePenalties.FirstOrDefault(b => b.Expires > DateTime.UtcNow); + var currentBan = activePenalties.FirstOrDefault(p => p.Type == Penalty.PenaltyType.Ban || p.Type == Penalty.PenaltyType.TempBan); + var currentAutoFlag = activePenalties.Where(p => p.Type == Penalty.PenaltyType.Flag && p.PunisherId == 1) .Where(p => p.Active) .OrderByDescending(p => p.When) @@ -232,7 +233,7 @@ namespace IW4MAdmin string formattedKick = String.Format( RconParser.GetCommandPrefixes().Kick, polledPlayer.ClientNumber, - $"{loc["SERVER_TB_REMAIN"]} ({(currentBan.Expires - DateTime.UtcNow).TimeSpanText()} {loc["WEBFRONT_PENALTY_TEMPLATE_REMAINING"]})"); + $"{loc["SERVER_TB_REMAIN"]} ({(currentBan.Expires.Value - DateTime.UtcNow).TimeSpanText()} {loc["WEBFRONT_PENALTY_TEMPLATE_REMAINING"]})"); await this.ExecuteCommandAsync(formattedKick); } @@ -1060,7 +1061,7 @@ namespace IW4MAdmin Penalty newPenalty = new Penalty() { Type = Penalty.PenaltyType.Ban, - Expires = DateTime.MaxValue, + Expires = null, Offender = Target, Offense = Message, Punisher = Origin, @@ -1080,7 +1081,7 @@ namespace IW4MAdmin var unbanPenalty = new Penalty() { Type = Penalty.PenaltyType.Unban, - Expires = DateTime.UtcNow, + Expires = null, Offender = Target, Offense = reason, Punisher = Origin, diff --git a/Plugins/IW4ScriptCommands/Commands/Balance.cs b/Plugins/IW4ScriptCommands/Commands/Balance.cs index e24492ded..3547a5ff9 100644 --- a/Plugins/IW4ScriptCommands/Commands/Balance.cs +++ b/Plugins/IW4ScriptCommands/Commands/Balance.cs @@ -1,197 +1,193 @@ -//using SharedLibraryCore; -//using SharedLibraryCore.Objects; -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using System.Text; -//using System.Threading.Tasks; +using SharedLibraryCore; +using SharedLibraryCore.Objects; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; -//namespace IW4ScriptCommands.Commands -//{ -// class Balance : Command -// { -// private class TeamAssignment -// { -// public IW4MAdmin.Plugins.Stats.IW4Info.Team CurrentTeam { get; set; } -// public int Num { get; set; } -// public IW4MAdmin.Plugins.Stats.Models.EFClientStatistics Stats { get; set; } -// } -// public Balance() : base("balance", "balance teams", "bal", Player.Permission.Trusted, false, null) -// { -// } +namespace IW4ScriptCommands.Commands +{ + class Balance + { + private class TeamAssignment + { + public IW4MAdmin.Plugins.Stats.IW4Info.Team CurrentTeam { get; set; } + public int Num { get; set; } + public IW4MAdmin.Plugins.Stats.Models.EFClientStatistics Stats { get; set; } + } -// public override async Task ExecuteAsync(GameEvent E) -// { -// string teamsString = (await E.Owner.GetDvarAsync("sv_iw4madmin_teams")).Value; + public static string GetTeamAssignments(Player client, string teamsString = "") + { + var scriptClientTeams = teamsString.Split(';', StringSplitOptions.RemoveEmptyEntries) + .Select(c => c.Split(',')) + .Select(c => new TeamAssignment() + { + CurrentTeam = (IW4MAdmin.Plugins.Stats.IW4Info.Team)Enum.Parse(typeof(IW4MAdmin.Plugins.Stats.IW4Info.Team), c[1]), + Num = client.CurrentServer.GetPlayersAsList().FirstOrDefault(p => p.ClientNumber== Int32.Parse(c[0]))?.ClientNumber ?? -1, + Stats = IW4MAdmin.Plugins.Stats.Plugin.Manager.GetClientStats(client.CurrentServer.Players.FirstOrDefault(p => p.ClientNumber == Int32.Parse(c[0])).ClientId, client.CurrentServer.GetHashCode()) + }) + .ToList(); -// var scriptClientTeams = teamsString.Split(';', StringSplitOptions.RemoveEmptyEntries) -// .Select(c => c.Split(',')) -// .Select(c => new TeamAssignment() -// { -// CurrentTeam = (IW4MAdmin.Plugins.Stats.IW4Info.Team)Enum.Parse(typeof(IW4MAdmin.Plugins.Stats.IW4Info.Team), c[1]), -// Num = E.Owner.Players.FirstOrDefault(p => p?.NetworkId == c[0].ConvertLong())?.ClientNumber ?? -1, -// Stats = IW4MAdmin.Plugins.Stats.Plugin.Manager.GetClientStats(E.Owner.Players.FirstOrDefault(p => p?.NetworkId == c[0].ConvertLong()).ClientId, E.Owner.GetHashCode()) -// }) -// .ToList(); + // at least one team is full so we can't balance + if (scriptClientTeams.Count(ct => ct.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Axis) >= Math.Floor(client.CurrentServer.MaxClients / 2.0) + || scriptClientTeams.Count(ct => ct.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Allies) >= Math.Floor(client.CurrentServer.MaxClients / 2.0)) + { + // E.Origin?.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_BALANCE_FAIL"]); + return string.Empty; + } -// // at least one team is full so we can't balance -// if (scriptClientTeams.Count(ct => ct.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Axis) >= Math.Floor(E.Owner.MaxClients / 2.0) -// || scriptClientTeams.Count(ct => ct.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Allies) >= Math.Floor(E.Owner.MaxClients / 2.0)) -// { -// await E.Origin?.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_BALANCE_FAIL"]); -// return; -// } + List teamAssignments = new List(); -// List teamAssignments = new List(); + var activeClients = client.CurrentServer.GetPlayersAsList().Select(c => new TeamAssignment() + { + Num = c.ClientNumber, + Stats = IW4MAdmin.Plugins.Stats.Plugin.Manager.GetClientStats(c.ClientId, client.CurrentServer.GetHashCode()), + CurrentTeam = IW4MAdmin.Plugins.Stats.Plugin.Manager.GetClientStats(c.ClientId, client.CurrentServer.GetHashCode()).Team + }) + .Where(c => scriptClientTeams.FirstOrDefault(sc => sc.Num == c.Num)?.CurrentTeam != IW4MAdmin.Plugins.Stats.IW4Info.Team.Spectator) + .Where(c => c.CurrentTeam != scriptClientTeams.FirstOrDefault(p => p.Num == c.Num)?.CurrentTeam) + .OrderByDescending(c => c.Stats.Performance) + .ToList(); -// var activeClients = E.Owner.GetPlayersAsList().Select(c => new TeamAssignment() -// { -// Num = c.ClientNumber, -// Stats = IW4MAdmin.Plugins.Stats.Plugin.Manager.GetClientStats(c.ClientId, E.Owner.GetHashCode()), -// CurrentTeam = IW4MAdmin.Plugins.Stats.Plugin.Manager.GetClientStats(c.ClientId, E.Owner.GetHashCode()).Team -// }) -// .Where(c => scriptClientTeams.FirstOrDefault(sc => sc.Num == c.Num)?.CurrentTeam != IW4MAdmin.Plugins.Stats.IW4Info.Team.Spectator) -// .Where(c => c.CurrentTeam != scriptClientTeams.FirstOrDefault(p => p.Num == c.Num)?.CurrentTeam) -// .OrderByDescending(c => c.Stats.Performance) -// .ToList(); + var alliesTeam = scriptClientTeams + .Where(c => c.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Allies) + .Where(c => activeClients.Count(t => t.Num == c.Num) == 0) + .ToList(); -// var alliesTeam = scriptClientTeams -// .Where(c => c.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Allies) -// .Where(c => activeClients.Count(t => t.Num == c.Num) == 0) -// .ToList(); + var axisTeam = scriptClientTeams + .Where(c => c.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Axis) + .Where(c => activeClients.Count(t => t.Num == c.Num) == 0) + .ToList(); -// var axisTeam = scriptClientTeams -// .Where(c => c.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Axis) -// .Where(c => activeClients.Count(t => t.Num == c.Num) == 0) -// .ToList(); + while (activeClients.Count() > 0) + { + int teamSizeDifference = alliesTeam.Count - axisTeam.Count; + double performanceDisparity = alliesTeam.Count > 0 ? alliesTeam.Average(t => t.Stats.Performance) : 0 - + axisTeam.Count > 0 ? axisTeam.Average(t => t.Stats.Performance) : 0; -// while (activeClients.Count() > 0) -// { -// int teamSizeDifference = alliesTeam.Count - axisTeam.Count; -// double performanceDisparity = alliesTeam.Count > 0 ? alliesTeam.Average(t => t.Stats.Performance) : 0 - -// axisTeam.Count > 0 ? axisTeam.Average(t => t.Stats.Performance) : 0; + if (teamSizeDifference == 0) + { + if (performanceDisparity == 0) + { + alliesTeam.Add(activeClients.First()); + activeClients.RemoveAt(0); + } + else + { + if (performanceDisparity > 0) + { + axisTeam.Add(activeClients.First()); + activeClients.RemoveAt(0); + } + else + { + alliesTeam.Add(activeClients.First()); + activeClients.RemoveAt(0); + } + } + } + else if (teamSizeDifference > 0) + { + if (performanceDisparity > 0) + { + axisTeam.Add(activeClients.First()); + activeClients.RemoveAt(0); + } -// if (teamSizeDifference == 0) -// { -// if (performanceDisparity == 0) -// { -// alliesTeam.Add(activeClients.First()); -// activeClients.RemoveAt(0); -// } -// else -// { -// if (performanceDisparity > 0) -// { -// axisTeam.Add(activeClients.First()); -// activeClients.RemoveAt(0); -// } -// else -// { -// alliesTeam.Add(activeClients.First()); -// activeClients.RemoveAt(0); -// } -// } -// } -// else if (teamSizeDifference > 0) -// { -// if (performanceDisparity > 0) -// { -// axisTeam.Add(activeClients.First()); -// activeClients.RemoveAt(0); -// } + else + { + axisTeam.Add(activeClients.Last()); + activeClients.RemoveAt(activeClients.Count - 1); + } + } + else + { + if (performanceDisparity > 0) + { + alliesTeam.Add(activeClients.First()); + activeClients.RemoveAt(0); + } -// else -// { -// axisTeam.Add(activeClients.Last()); -// activeClients.RemoveAt(activeClients.Count - 1); -// } -// } -// else -// { -// if (performanceDisparity > 0) -// { -// alliesTeam.Add(activeClients.First()); -// activeClients.RemoveAt(0); -// } + else + { + alliesTeam.Add(activeClients.Last()); + activeClients.RemoveAt(activeClients.Count - 1); + } + } + } -// else -// { -// alliesTeam.Add(activeClients.Last()); -// activeClients.RemoveAt(activeClients.Count - 1); -// } -// } -// } + alliesTeam = alliesTeam.OrderByDescending(t => t.Stats.Performance) + .ToList(); -// alliesTeam = alliesTeam.OrderByDescending(t => t.Stats.Performance) -// .ToList(); + axisTeam = axisTeam.OrderByDescending(t => t.Stats.Performance) + .ToList(); -// axisTeam = axisTeam.OrderByDescending(t => t.Stats.Performance) -// .ToList(); + while (Math.Abs(alliesTeam.Count - axisTeam.Count) > 1) + { + int teamSizeDifference = alliesTeam.Count - axisTeam.Count; + double performanceDisparity = alliesTeam.Count > 0 ? alliesTeam.Average(t => t.Stats.Performance) : 0 - + axisTeam.Count > 0 ? axisTeam.Average(t => t.Stats.Performance) : 0; -// while (Math.Abs(alliesTeam.Count - axisTeam.Count) > 1) -// { -// int teamSizeDifference = alliesTeam.Count - axisTeam.Count; -// double performanceDisparity = alliesTeam.Count > 0 ? alliesTeam.Average(t => t.Stats.Performance) : 0 - -// axisTeam.Count > 0 ? axisTeam.Average(t => t.Stats.Performance) : 0; + if (teamSizeDifference > 0) + { + if (performanceDisparity > 0) + { + axisTeam.Add(alliesTeam.First()); + alliesTeam.RemoveAt(0); + } -// if (teamSizeDifference > 0) -// { -// if (performanceDisparity > 0) -// { -// axisTeam.Add(alliesTeam.First()); -// alliesTeam.RemoveAt(0); -// } + else + { + axisTeam.Add(alliesTeam.Last()); + alliesTeam.RemoveAt(axisTeam.Count - 1); + } + } -// else -// { -// axisTeam.Add(alliesTeam.Last()); -// alliesTeam.RemoveAt(axisTeam.Count - 1); -// } -// } + else + { + if (performanceDisparity > 0) + { + alliesTeam.Add(axisTeam.Last()); + axisTeam.RemoveAt(axisTeam.Count - 1); + } -// else -// { -// if (performanceDisparity > 0) -// { -// alliesTeam.Add(axisTeam.Last()); -// axisTeam.RemoveAt(axisTeam.Count - 1); -// } + else + { + alliesTeam.Add(axisTeam.First()); + axisTeam.RemoveAt(0); + } + } + } -// else -// { -// alliesTeam.Add(axisTeam.First()); -// axisTeam.RemoveAt(0); -// } -// } -// } + foreach (var assignment in alliesTeam) + { + teamAssignments.Add($"{assignment.Num},2"); + assignment.Stats.Team = IW4MAdmin.Plugins.Stats.IW4Info.Team.Allies; + } -// foreach (var assignment in alliesTeam) -// { -// teamAssignments.Add($"{assignment.Num},2"); -// assignment.Stats.Team = IW4MAdmin.Plugins.Stats.IW4Info.Team.Allies; -// } -// foreach (var assignment in axisTeam) -// { -// teamAssignments.Add($"{assignment.Num},3"); -// assignment.Stats.Team = IW4MAdmin.Plugins.Stats.IW4Info.Team.Axis; -// } + foreach (var assignment in axisTeam) + { + teamAssignments.Add($"{assignment.Num},3"); + assignment.Stats.Team = IW4MAdmin.Plugins.Stats.IW4Info.Team.Axis; + } -// if (alliesTeam.Count(ac => scriptClientTeams.First(sc => sc.Num == ac.Num).CurrentTeam != ac.CurrentTeam) == 0 && -// axisTeam.Count(ac => scriptClientTeams.First(sc => sc.Num == ac.Num).CurrentTeam != ac.CurrentTeam) == 0) -// { -// await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_BALANCE_FAIL_BALANCED"]); -// return; -// } + //if (alliesTeam.Count(ac => scriptClientTeams.First(sc => sc.Num == ac.Num).CurrentTeam != ac.CurrentTeam) == 0 && + // axisTeam.Count(ac => scriptClientTeams.First(sc => sc.Num == ac.Num).CurrentTeam != ac.CurrentTeam) == 0) + //{ + // //E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_BALANCE_FAIL_BALANCED"]); + // return string.Empty; + //} -// if (E.Origin?.Level > Player.Permission.Administrator) -// { -// await E.Origin.Tell($"Allies Elo: {(alliesTeam.Count > 0 ? alliesTeam.Average(t => t.Stats.Performance) : 0)}"); -// await E.Origin.Tell($"Axis Elo: {(axisTeam.Count > 0 ? axisTeam.Average(t => t.Stats.Performance) : 0)}"); -// } + //if (E.Origin?.Level > Player.Permission.Administrator) + //{ + // E.Origin.Tell($"Allies Elo: {(alliesTeam.Count > 0 ? alliesTeam.Average(t => t.Stats.Performance) : 0)}"); + // E.Origin.Tell($"Axis Elo: {(axisTeam.Count > 0 ? axisTeam.Average(t => t.Stats.Performance) : 0)}"); + //} -// string args = string.Join(",", teamAssignments); -// await E.Owner.ExecuteCommandAsync($"sv_iw4madmin_command \"balance:{args}\""); -// await E.Origin.Tell("Balance command sent"); -// } -// } -//} + //E.Origin.Tell("Balance command sent"); + string args = string.Join(",", teamAssignments); + return args; + } + } +} diff --git a/WebfrontCore/Controllers/API/GscApiController.cs b/Plugins/IW4ScriptCommands/GscApiController.cs similarity index 70% rename from WebfrontCore/Controllers/API/GscApiController.cs rename to Plugins/IW4ScriptCommands/GscApiController.cs index e5fd07b7a..d4121ad13 100644 --- a/WebfrontCore/Controllers/API/GscApiController.cs +++ b/Plugins/IW4ScriptCommands/GscApiController.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Mvc; +using IW4ScriptCommands.Commands; +using Microsoft.AspNetCore.Mvc; using SharedLibraryCore; using SharedLibraryCore.Objects; using System; @@ -32,5 +33,18 @@ namespace WebfrontCore.Controllers.API return Content(""); } + + [HttpGet("{networkId}")] + public IActionResult GetTeamAssignments(string networkId, string teams = "") + { + var client = Manager.GetActiveClients() + .First(c => c.NetworkId == networkId.ConvertLong()); + + teams = teams ?? string.Empty; + + string assignments = Balance.GetTeamAssignments(client, teams); + + return Content(assignments); + } } } diff --git a/Plugins/Stats/Commands/TopStats.cs b/Plugins/Stats/Commands/TopStats.cs index 23edf63a0..b33488855 100644 --- a/Plugins/Stats/Commands/TopStats.cs +++ b/Plugins/Stats/Commands/TopStats.cs @@ -14,7 +14,6 @@ namespace IW4MAdmin.Plugins.Stats.Commands { class TopStats : Command { - public static async Task> GetTopStats(Server s) { int serverId = s.GetHashCode(); diff --git a/Plugins/Stats/Commands/ViewStats.cs b/Plugins/Stats/Commands/ViewStats.cs index eb71c0927..dc786ae94 100644 --- a/Plugins/Stats/Commands/ViewStats.cs +++ b/Plugins/Stats/Commands/ViewStats.cs @@ -9,6 +9,7 @@ using System.Text; using System.Threading.Tasks; using SharedLibraryCore.Database; using Microsoft.EntityFrameworkCore; +using IW4MAdmin.Plugins.Stats.Helpers; namespace IW4MAdmin.Plugins.Stats.Commands { @@ -47,14 +48,20 @@ namespace IW4MAdmin.Plugins.Stats.Commands { if (E.Target != null) { + int performanceRanking = await StatManager.GetClientOverallRanking(E.Target.ClientId); + string performanceRankingString = performanceRanking == 0 ? loc["WEBFRONT_STATS_INDEX_UNRANKED"] : $"{loc["WEBFRONT_STATS_INDEX_RANKED"]} #{performanceRanking}"; + pStats = (await ctx.Set().FirstAsync(c => c.ServerId == serverId && c.ClientId == E.Target.ClientId)); - statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()}"; + statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()} | {performanceRankingString}"; } else { + int performanceRanking = await StatManager.GetClientOverallRanking(E.Origin.ClientId); + string performanceRankingString = performanceRanking == 0 ? loc["WEBFRONT_STATS_INDEX_UNRANKED"] : $"{loc["WEBFRONT_STATS_INDEX_RANKED"]} #{performanceRanking}"; + pStats = (await ctx.Set().FirstAsync((c => c.ServerId == serverId && c.ClientId == E.Origin.ClientId))); - statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()}"; + statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()} | {performanceRankingString}"; } } diff --git a/Plugins/Stats/Helpers/StatManager.cs b/Plugins/Stats/Helpers/StatManager.cs index 5d8adf5f5..76af7239d 100644 --- a/Plugins/Stats/Helpers/StatManager.cs +++ b/Plugins/Stats/Helpers/StatManager.cs @@ -57,7 +57,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers /// /// client id of the player /// - public async Task GetClientOverallRanking(int clientId) + public static async Task GetClientOverallRanking(int clientId) { using (var context = new DatabaseContext(true)) { diff --git a/Plugins/Stats/Plugin.cs b/Plugins/Stats/Plugin.cs index 929904e45..3a144f5b0 100644 --- a/Plugins/Stats/Plugin.cs +++ b/Plugins/Stats/Plugin.cs @@ -143,7 +143,7 @@ namespace IW4MAdmin.Plugins.Stats new ProfileMeta() { Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_RANKING"], - Value = "#" + await Manager.GetClientOverallRanking(clientId), + Value = "#" + await StatManager.GetClientOverallRanking(clientId), }, new ProfileMeta() { diff --git a/README.md b/README.md index 209533437..ad44d218b 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,9 @@ If you wish to further customize your experience of **IW4MAdmin**, the following * Specifies the database provider **IW4MAdmin** should use * Possible values — `sqlite`, `mysql`, `postgresql` * Default — `sqlite` + +`Ignore Bots` +* Disables bots from being registered by **IW4MAdmin** `RConPollRate` * Specifies (in milliseconds) how often to poll each server for updates diff --git a/SharedLibraryCore/Commands/NativeCommands.cs b/SharedLibraryCore/Commands/NativeCommands.cs index b3b81ff0a..e2ef5745c 100644 --- a/SharedLibraryCore/Commands/NativeCommands.cs +++ b/SharedLibraryCore/Commands/NativeCommands.cs @@ -183,9 +183,17 @@ namespace SharedLibraryCore.Commands string tempbanReason = match.Groups[2].ToString(); var length = match.Groups[1].ToString().ParseTimespan(); - var _ = !(await E.Target.TempBan(tempbanReason, length, E.Origin).WaitAsync()).Failed ? - E.Origin.Tell($"^5{E.Target} ^7{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_TEMPBAN_SUCCESS"]} ^5{length.TimeSpanText()}") : - E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_TEMPBAN_FAIL"]} {E.Target.Name}"); + if (length > E.Owner.Manager.GetApplicationSettings().Configuration().MaximumTempBanTime) + { + E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_TEMPBAN_FAIL_TOOLONG"]); + } + + else + { + var _ = !(await E.Target.TempBan(tempbanReason, length, E.Origin).WaitAsync()).Failed ? + E.Origin.Tell($"^5{E.Target} ^7{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_TEMPBAN_SUCCESS"]} ^5{length.TimeSpanText()}") : + E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_TEMPBAN_FAIL"]} {E.Target.Name}"); + } } } } @@ -468,7 +476,11 @@ namespace SharedLibraryCore.Commands { ActiveClient.Level = newPerm; await E.Owner.Manager.GetClientService().Update(ActiveClient); - ActiveClient.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_SUCCESS_TARGET"]} {newPerm}"); + + if (newPerm > oldPerm) + { + ActiveClient.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_SUCCESS_TARGET"]} {newPerm}"); + } } else @@ -503,7 +515,9 @@ namespace SharedLibraryCore.Commands E.Owner.Manager.GetEventHandler().AddEvent(e); - E.Origin.Tell($"{E.Target.Name} {Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_SUCCESS"]}"); + var _ = newPerm < oldPerm ? + E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_DEMOTE_SUCCESS"]} {E.Target.Name}") : + E.Origin.Tell($"{E.Target.Name} {Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_SUCCESS"]}"); } else @@ -625,7 +639,7 @@ namespace SharedLibraryCore.Commands } IList db_players = (await (E.Owner.Manager.GetClientService() as ClientService) - .GetClientByName(E.Data)) + .FindClientsByIdentifier(E.Data)) .OrderByDescending(p => p.LastConnection) .ToList(); @@ -935,7 +949,8 @@ namespace SharedLibraryCore.Commands { var B = await E.Owner.Manager.GetPenaltyService().GetClientPenaltiesAsync(E.Target.ClientId); - var penalty = B.FirstOrDefault(b => b.Type > Penalty.PenaltyType.Kick && b.Expires > DateTime.UtcNow); + var penalty = B.FirstOrDefault(b => b.Type > Penalty.PenaltyType.Kick && + (b.Expires == null || b.Expires > DateTime.UtcNow)); if (penalty == null) { @@ -943,7 +958,7 @@ namespace SharedLibraryCore.Commands return; } - string timeRemaining = penalty.Type == Penalty.PenaltyType.TempBan ? $"({(penalty.Expires - DateTime.UtcNow).TimeSpanText()} remaining)" : ""; + string timeRemaining = penalty.Type == Penalty.PenaltyType.TempBan ? $"({(penalty.Expires.Value - DateTime.UtcNow).TimeSpanText()} remaining)" : ""; string success = Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_BANINFO_SUCCESS"]; E.Origin.Tell($"^1{E.Target.Name} ^7{string.Format(success, penalty.Punisher.Name)} {penalty.Punisher.Name} {timeRemaining}"); diff --git a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs index 94b655660..a9187abab 100644 --- a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs +++ b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs @@ -22,6 +22,7 @@ namespace SharedLibraryCore.Configuration public string ConnectionString { get; set; } public int RConPollRate { get; set; } = 5000; public bool IgnoreBots { get; set; } + public TimeSpan MaximumTempBanTime { get; set; } = new TimeSpan(24 * 30, 0, 0); public string Id { get; set; } public List Servers { get; set; } public int AutoMessagePeriod { get; set; } diff --git a/SharedLibraryCore/Database/DatabaseContext.cs b/SharedLibraryCore/Database/DatabaseContext.cs index 010a76281..690feb5ae 100644 --- a/SharedLibraryCore/Database/DatabaseContext.cs +++ b/SharedLibraryCore/Database/DatabaseContext.cs @@ -98,6 +98,9 @@ namespace SharedLibraryCore.Database .WithMany(p => p.AdministeredPenalties) .HasForeignKey(c => c.PunisherId) .OnDelete(DeleteBehavior.Restrict); + + entity.Property(p => p.Expires) + .IsRequired(false); }); modelBuilder.Entity(entity => diff --git a/SharedLibraryCore/Database/Models/EFPenalty.cs b/SharedLibraryCore/Database/Models/EFPenalty.cs index fdcb365d5..4ca04af9e 100644 --- a/SharedLibraryCore/Database/Models/EFPenalty.cs +++ b/SharedLibraryCore/Database/Models/EFPenalty.cs @@ -27,7 +27,7 @@ namespace SharedLibraryCore.Database.Models [Required] public DateTime When { get; set; } [Required] - public DateTime Expires { get; set; } + public DateTime? Expires { get; set; } [Required] public string Offense { get; set; } public string AutomatedOffense { get; set; } diff --git a/SharedLibraryCore/Migrations/20181014171848_MakePenaltyExpirationNullable.Designer.cs b/SharedLibraryCore/Migrations/20181014171848_MakePenaltyExpirationNullable.Designer.cs new file mode 100644 index 000000000..034f5a20d --- /dev/null +++ b/SharedLibraryCore/Migrations/20181014171848_MakePenaltyExpirationNullable.Designer.cs @@ -0,0 +1,690 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using SharedLibraryCore.Database; + +namespace SharedLibraryCore.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20181014171848_MakePenaltyExpirationNullable")] + partial class MakePenaltyExpirationNullable + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.1.4-rtm-31024"); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b => + { + b.Property("SnapshotId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("ClientId"); + + b.Property("CurrentSessionLength"); + + b.Property("CurrentStrain"); + + b.Property("CurrentViewAngleId"); + + b.Property("Deaths"); + + b.Property("Distance"); + + b.Property("EloRating"); + + b.Property("HitDestinationId"); + + b.Property("HitLocation"); + + b.Property("HitOriginId"); + + b.Property("HitType"); + + b.Property("Hits"); + + b.Property("Kills"); + + b.Property("LastStrainAngleId"); + + b.Property("SessionAngleOffset"); + + b.Property("SessionSPM"); + + b.Property("SessionScore"); + + b.Property("StrainAngleBetween"); + + b.Property("TimeSinceLastEvent"); + + b.Property("WeaponId"); + + b.Property("When"); + + b.HasKey("SnapshotId"); + + b.HasIndex("ClientId"); + + b.HasIndex("CurrentViewAngleId"); + + b.HasIndex("HitDestinationId"); + + b.HasIndex("HitOriginId"); + + b.HasIndex("LastStrainAngleId"); + + b.ToTable("EFACSnapshot"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b => + { + b.Property("KillId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("AttackerId"); + + b.Property("Damage"); + + b.Property("DeathOriginVector3Id"); + + b.Property("DeathType"); + + b.Property("Fraction"); + + b.Property("HitLoc"); + + b.Property("IsKill"); + + b.Property("KillOriginVector3Id"); + + b.Property("Map"); + + b.Property("ServerId"); + + b.Property("VictimId"); + + b.Property("ViewAnglesVector3Id"); + + b.Property("VisibilityPercentage"); + + b.Property("Weapon"); + + b.Property("When"); + + b.HasKey("KillId"); + + b.HasIndex("AttackerId"); + + b.HasIndex("DeathOriginVector3Id"); + + b.HasIndex("KillOriginVector3Id"); + + b.HasIndex("ServerId"); + + b.HasIndex("VictimId"); + + b.HasIndex("ViewAnglesVector3Id"); + + b.ToTable("EFClientKills"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b => + { + b.Property("MessageId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("ClientId"); + + b.Property("Message"); + + b.Property("ServerId"); + + b.Property("TimeSent"); + + b.HasKey("MessageId"); + + b.HasIndex("ClientId"); + + b.HasIndex("ServerId"); + + b.HasIndex("TimeSent"); + + b.ToTable("EFClientMessages"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b => + { + b.Property("RatingHistoryId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("ClientId"); + + b.HasKey("RatingHistoryId"); + + b.HasIndex("ClientId"); + + b.ToTable("EFClientRatingHistory"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b => + { + b.Property("ClientId"); + + b.Property("ServerId"); + + b.Property("Active"); + + b.Property("Deaths"); + + b.Property("EloRating"); + + b.Property("Kills"); + + b.Property("MaxStrain"); + + b.Property("RollingWeightedKDR"); + + b.Property("SPM"); + + b.Property("Skill"); + + b.Property("TimePlayed"); + + b.Property("VisionAverage"); + + b.HasKey("ClientId", "ServerId"); + + b.HasIndex("ServerId"); + + b.ToTable("EFClientStatistics"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b => + { + b.Property("HitLocationCountId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("ClientId") + .HasColumnName("EFClientStatistics_ClientId"); + + b.Property("HitCount"); + + b.Property("HitOffsetAverage"); + + b.Property("Location"); + + b.Property("MaxAngleDistance"); + + b.Property("ServerId") + .HasColumnName("EFClientStatistics_ServerId"); + + b.HasKey("HitLocationCountId"); + + b.HasIndex("ServerId"); + + b.HasIndex("ClientId", "ServerId"); + + b.ToTable("EFHitLocationCounts"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b => + { + b.Property("RatingId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("ActivityAmount"); + + b.Property("Newest"); + + b.Property("Performance"); + + b.Property("Ranking"); + + b.Property("RatingHistoryId"); + + b.Property("ServerId"); + + b.Property("When"); + + b.HasKey("RatingId"); + + b.HasIndex("Performance"); + + b.HasIndex("Ranking"); + + b.HasIndex("RatingHistoryId"); + + b.HasIndex("ServerId"); + + b.HasIndex("When"); + + b.ToTable("EFRating"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b => + { + b.Property("ServerId"); + + b.Property("Active"); + + b.Property("Port"); + + b.HasKey("ServerId"); + + b.ToTable("EFServers"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b => + { + b.Property("StatisticId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("ServerId"); + + b.Property("TotalKills"); + + b.Property("TotalPlayTime"); + + b.HasKey("StatisticId"); + + b.HasIndex("ServerId"); + + b.ToTable("EFServerStatistics"); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b => + { + b.Property("AliasId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("DateAdded"); + + b.Property("IPAddress"); + + b.Property("LinkId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(24); + + b.HasKey("AliasId"); + + b.HasIndex("IPAddress"); + + b.HasIndex("LinkId"); + + b.HasIndex("Name"); + + b.ToTable("EFAlias"); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAliasLink", b => + { + b.Property("AliasLinkId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.HasKey("AliasLinkId"); + + b.ToTable("EFAliasLinks"); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFChangeHistory", b => + { + b.Property("ChangeHistoryId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("Comment") + .HasMaxLength(128); + + b.Property("CurrentValue"); + + b.Property("OriginEntityId"); + + b.Property("PreviousValue"); + + b.Property("TargetEntityId"); + + b.Property("TimeChanged"); + + b.Property("TypeOfChange"); + + b.HasKey("ChangeHistoryId"); + + b.ToTable("EFChangeHistory"); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b => + { + b.Property("ClientId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("AliasLinkId"); + + b.Property("Connections"); + + b.Property("CurrentAliasId"); + + b.Property("FirstConnection"); + + b.Property("LastConnection"); + + b.Property("Level"); + + b.Property("Masked"); + + b.Property("NetworkId"); + + b.Property("Password"); + + b.Property("PasswordSalt"); + + b.Property("TotalConnectionTime"); + + b.HasKey("ClientId"); + + b.HasIndex("AliasLinkId"); + + b.HasIndex("CurrentAliasId"); + + b.HasIndex("NetworkId") + .IsUnique(); + + b.ToTable("EFClients"); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b => + { + b.Property("MetaId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("ClientId"); + + b.Property("Created"); + + b.Property("Extra"); + + b.Property("Key") + .IsRequired(); + + b.Property("Updated"); + + b.Property("Value") + .IsRequired(); + + b.HasKey("MetaId"); + + b.HasIndex("ClientId"); + + b.ToTable("EFMeta"); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b => + { + b.Property("PenaltyId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("AutomatedOffense"); + + b.Property("Expires"); + + b.Property("LinkId"); + + b.Property("OffenderId"); + + b.Property("Offense") + .IsRequired(); + + b.Property("PunisherId"); + + b.Property("Type"); + + b.Property("When"); + + b.HasKey("PenaltyId"); + + b.HasIndex("LinkId"); + + b.HasIndex("OffenderId"); + + b.HasIndex("PunisherId"); + + b.ToTable("EFPenalties"); + }); + + modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b => + { + b.Property("Vector3Id") + .ValueGeneratedOnAdd(); + + b.Property("EFACSnapshotSnapshotId"); + + b.Property("X"); + + b.Property("Y"); + + b.Property("Z"); + + b.HasKey("Vector3Id"); + + b.HasIndex("EFACSnapshotSnapshotId"); + + b.ToTable("Vector3"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") + .WithMany() + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "CurrentViewAngle") + .WithMany() + .HasForeignKey("CurrentViewAngleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitDestination") + .WithMany() + .HasForeignKey("HitDestinationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitOrigin") + .WithMany() + .HasForeignKey("HitOriginId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "LastStrainAngle") + .WithMany() + .HasForeignKey("LastStrainAngleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker") + .WithMany() + .HasForeignKey("AttackerId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "DeathOrigin") + .WithMany() + .HasForeignKey("DeathOriginVector3Id"); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "KillOrigin") + .WithMany() + .HasForeignKey("KillOriginVector3Id"); + + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Victim") + .WithMany() + .HasForeignKey("VictimId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "ViewAngles") + .WithMany() + .HasForeignKey("ViewAnglesVector3Id"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") + .WithMany() + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") + .WithMany() + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") + .WithMany() + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") + .WithMany() + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics") + .WithMany("HitLocations") + .HasForeignKey("ClientId", "ServerId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b => + { + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", "RatingHistory") + .WithMany("Ratings") + .HasForeignKey("RatingHistoryId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("ServerId"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b => + { + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link") + .WithMany("Children") + .HasForeignKey("LinkId") + .OnDelete(DeleteBehavior.Restrict); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "AliasLink") + .WithMany() + .HasForeignKey("AliasLinkId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("SharedLibraryCore.Database.Models.EFAlias", "CurrentAlias") + .WithMany() + .HasForeignKey("CurrentAliasId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") + .WithMany("Meta") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link") + .WithMany("ReceivedPenalties") + .HasForeignKey("LinkId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Offender") + .WithMany("ReceivedPenalties") + .HasForeignKey("OffenderId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Punisher") + .WithMany("AdministeredPenalties") + .HasForeignKey("PunisherId") + .OnDelete(DeleteBehavior.Restrict); + }); + + modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b => + { + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot") + .WithMany("PredictedViewAngles") + .HasForeignKey("EFACSnapshotSnapshotId"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/SharedLibraryCore/Migrations/20181014171848_MakePenaltyExpirationNullable.cs b/SharedLibraryCore/Migrations/20181014171848_MakePenaltyExpirationNullable.cs new file mode 100644 index 000000000..a9ec9b9c9 --- /dev/null +++ b/SharedLibraryCore/Migrations/20181014171848_MakePenaltyExpirationNullable.cs @@ -0,0 +1,105 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace SharedLibraryCore.Migrations +{ + public partial class MakePenaltyExpirationNullable : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + if (migrationBuilder.ActiveProvider == "Microsoft.EntityFrameworkCore.Sqlite") + { + migrationBuilder.Sql(@"PRAGMA foreign_keys = 0; + +CREATE TABLE sqlitestudio_temp_table AS SELECT * + FROM EFPenalties; + +DROP TABLE EFPenalties; + +CREATE TABLE EFPenalties ( + PenaltyId INTEGER NOT NULL + CONSTRAINT PK_EFPenalties PRIMARY KEY AUTOINCREMENT, + Active INTEGER NOT NULL, + Expires TEXT, + LinkId INTEGER NOT NULL, + OffenderId INTEGER NOT NULL, + Offense TEXT NOT NULL, + PunisherId INTEGER NOT NULL, + Type INTEGER NOT NULL, + [When] TEXT NOT NULL, + AutomatedOffense TEXT, + CONSTRAINT FK_EFPenalties_EFAliasLinks_LinkId FOREIGN KEY ( + LinkId + ) + REFERENCES EFAliasLinks (AliasLinkId) ON DELETE CASCADE, + CONSTRAINT FK_EFPenalties_EFClients_OffenderId FOREIGN KEY ( + OffenderId + ) + REFERENCES EFClients (ClientId) ON DELETE RESTRICT, + CONSTRAINT FK_EFPenalties_EFClients_PunisherId FOREIGN KEY ( + PunisherId + ) + REFERENCES EFClients (ClientId) ON DELETE RESTRICT +); + +INSERT INTO EFPenalties ( + PenaltyId, + Active, + Expires, + LinkId, + OffenderId, + Offense, + PunisherId, + Type, + [When], + AutomatedOffense + ) + SELECT PenaltyId, + Active, + Expires, + LinkId, + OffenderId, + Offense, + PunisherId, + Type, + ""When"", + AutomatedOffense + FROM sqlitestudio_temp_table; + + DROP TABLE sqlitestudio_temp_table; + + CREATE INDEX IX_EFPenalties_LinkId ON EFPenalties( + ""LinkId"" + ); + + CREATE INDEX IX_EFPenalties_OffenderId ON EFPenalties( + ""OffenderId"" + ); + + CREATE INDEX IX_EFPenalties_PunisherId ON EFPenalties( + ""PunisherId"" + ); + + PRAGMA foreign_keys = 1; "); + } + else + { + migrationBuilder.AlterColumn( + name: "Expires", + table: "EFPenalties", + nullable: true, + oldClrType: typeof(DateTime)); + } + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Expires", + table: "EFPenalties", + nullable: false, + oldClrType: typeof(DateTime), + oldNullable: true); + } + } +} diff --git a/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs b/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs index acce2cb5e..e2cedabab 100644 --- a/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs +++ b/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs @@ -3,7 +3,6 @@ using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using SharedLibraryCore.Database; namespace SharedLibraryCore.Migrations @@ -15,9 +14,7 @@ namespace SharedLibraryCore.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) - .HasAnnotation("ProductVersion", "2.1.3-rtm-32065") - .HasAnnotation("Relational:MaxIdentifierLength", 63); + .HasAnnotation("ProductVersion", "2.1.4-rtm-31024"); modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b => { @@ -456,7 +453,7 @@ namespace SharedLibraryCore.Migrations b.Property("AutomatedOffense"); - b.Property("Expires"); + b.Property("Expires"); b.Property("LinkId"); diff --git a/SharedLibraryCore/Services/ClientService.cs b/SharedLibraryCore/Services/ClientService.cs index c3c27587a..282019be4 100644 --- a/SharedLibraryCore/Services/ClientService.cs +++ b/SharedLibraryCore/Services/ClientService.cs @@ -255,27 +255,30 @@ namespace SharedLibraryCore.Services } } - public async Task> GetClientByName(string name) + public async Task> FindClientsByIdentifier(string identifier) { - if (name.Length < 3) + if (identifier.Length < 3) + { return new List(); + } - name = name.ToLower(); + identifier = identifier.ToLower(); using (var context = new DatabaseContext(disableTracking: true)) { - int asIP = name.ConvertToIP(); - // hack: so IW4MAdmin and bots don't show up in search results - asIP = asIP == 0 ? int.MaxValue : asIP; + long networkId = identifier.ConvertLong(); + int ipAddress = identifier.ConvertToIP(); var iqLinkIds = (from alias in context.Aliases - where asIP != int.MaxValue ? alias.IPAddress == asIP : alias.Name.ToLower().Contains(name) - select alias.LinkId); + where alias.IPAddress == ipAddress || + alias.Name.ToLower().Contains(identifier) + select alias.LinkId).Distinct(); var linkIds = iqLinkIds.ToList(); var iqClients = context.Clients - .Where(c => linkIds.Contains(c.AliasLinkId)) + .Where(c => linkIds.Contains(c.AliasLinkId) || + networkId == c.NetworkId) .Include(c => c.CurrentAlias) .Include(c => c.AliasLink.Children); diff --git a/SharedLibraryCore/Services/PenaltyService.cs b/SharedLibraryCore/Services/PenaltyService.cs index 85eafe294..7745d4b88 100644 --- a/SharedLibraryCore/Services/PenaltyService.cs +++ b/SharedLibraryCore/Services/PenaltyService.cs @@ -30,9 +30,6 @@ namespace SharedLibraryCore.Services AutomatedOffense = newEntity.AutomatedOffense }; - if (addedEntity.Expires == DateTime.MaxValue) - addedEntity.Expires = DateTime.Parse(System.Data.SqlTypes.SqlDateTime.MaxValue.ToString()); - // make bans propogate to all aliases if (addedEntity.Type == Objects.Penalty.PenaltyType.Ban) { @@ -225,7 +222,7 @@ namespace SharedLibraryCore.Services .Where(p => p.LinkId == linkId || p.Link.Children.Any(a => a.IPAddress == ip)) .Where(p => p.Active) - .Where(p => p.Expires > now); + .Where(p => p.Expires == null || p.Expires > now); #if DEBUG == true @@ -246,7 +243,7 @@ namespace SharedLibraryCore.Services var penalties = await context.Penalties .Include(p => p.Link.Children) .Where(p => p.LinkId == aliasLinkId) - .Where(p => p.Expires > now) + .Where(p => p.Expires > now || p.Expires == null) .ToListAsync(); penalties.ForEach(async p => diff --git a/SharedLibraryCore/Utilities.cs b/SharedLibraryCore/Utilities.cs index a99b0b2fc..152a6602a 100644 --- a/SharedLibraryCore/Utilities.cs +++ b/SharedLibraryCore/Utilities.cs @@ -248,14 +248,14 @@ namespace SharedLibraryCore if (!string.IsNullOrEmpty(bot)) // should set their GUID to the negation of their 1 based index (-1 - -18) return -(Convert.ToInt64(bot.Substring(3)) + 1); - return 0; + return long.MinValue; } public static int ConvertToIP(this string str) { System.Net.IPAddress.TryParse(str, out System.Net.IPAddress ip); - return ip == null ? 0 : BitConverter.ToInt32(ip.GetAddressBytes(), 0); + return ip == null ? int.MaxValue : BitConverter.ToInt32(ip.GetAddressBytes(), 0); } public static string ConvertIPtoString(this int ip) diff --git a/WebfrontCore/Controllers/ClientController.cs b/WebfrontCore/Controllers/ClientController.cs index fe57d0a08..995b909fa 100644 --- a/WebfrontCore/Controllers/ClientController.cs +++ b/WebfrontCore/Controllers/ClientController.cs @@ -146,7 +146,7 @@ namespace WebfrontCore.Controllers public async Task FindAsync(string clientName) { - var clients = (await Manager.GetClientService().GetClientByName(clientName)) + var clients = (await Manager.GetClientService().FindClientsByIdentifier(clientName)) .OrderByDescending(c => c.LastConnection); var clientsDto = clients.Select(c => new PlayerInfo() diff --git a/WebfrontCore/ViewComponents/PenaltyListViewComponent.cs b/WebfrontCore/ViewComponents/PenaltyListViewComponent.cs index 6fb6d06ab..bc1839cbe 100644 --- a/WebfrontCore/ViewComponents/PenaltyListViewComponent.cs +++ b/WebfrontCore/ViewComponents/PenaltyListViewComponent.cs @@ -30,7 +30,7 @@ namespace WebfrontCore.ViewComponents Type = p.Type.ToString(), TimePunished = Utilities.GetTimePassed(p.When, false), // show time passed if ban - TimeRemaining = DateTime.UtcNow > p.Expires ? "" : $"{(p.Expires.Year == DateTime.MaxValue.Year ? Utilities.GetTimePassed(p.When, true) : Utilities.TimeSpanText(p.Expires - DateTime.UtcNow))}", + TimeRemaining = DateTime.UtcNow > p.Expires ? "" : $"{(p.Expires.Value.Year == DateTime.MaxValue.Year ? Utilities.GetTimePassed(p.When, true) : Utilities.TimeSpanText(p.Expires.Value - DateTime.UtcNow))}", Sensitive = p.Type == Penalty.PenaltyType.Flag, AutomatedOffense = p.AutomatedOffense }); diff --git a/version.txt b/version.txt index a13a5388d..4c778f740 100644 --- a/version.txt +++ b/version.txt @@ -1,3 +1,6 @@ +Version 2.3: +-added configuration option to ignore bots + Version 2.2: -upgraded projects to .NET 2.1 -added top player stats page