diff --git a/Application/Application.csproj b/Application/Application.csproj index 9d9c84940..d06635524 100644 --- a/Application/Application.csproj +++ b/Application/Application.csproj @@ -5,7 +5,7 @@ netcoreapp2.1 false RaidMax.IW4MAdmin.Application - 2.1.8 + 2.1.9 RaidMax Forever None IW4MAdmin @@ -80,15 +80,17 @@ - + - + + + + - + - diff --git a/Application/BuildScripts/PostBuild.bat b/Application/BuildScripts/PostBuild.bat index 98932ef91..db0ed34ae 100644 --- a/Application/BuildScripts/PostBuild.bat +++ b/Application/BuildScripts/PostBuild.bat @@ -2,6 +2,9 @@ set SolutionDir=%1 set ProjectDir=%2 set TargetDir=%3 set OutDir=%4 +set Version=%5 + +echo %Version% > "%SolutionDir%DEPLOY\version.txt" echo Copying dependency configs copy "%SolutionDir%WebfrontCore\%OutDir%*.deps.json" "%TargetDir%" diff --git a/Application/GameEventHandler.cs b/Application/GameEventHandler.cs index 0a4c00ec3..dceb1b326 100644 --- a/Application/GameEventHandler.cs +++ b/Application/GameEventHandler.cs @@ -18,20 +18,23 @@ namespace IW4MAdmin.Application { Manager = mgr; OutOfOrderEvents = new SortedList(); - IsProcessingEvent = new SemaphoreSlim(0); - IsProcessingEvent.Release(); + IsProcessingEvent = new SemaphoreSlim(2, 2); } public void AddEvent(GameEvent gameEvent) { + IsProcessingEvent.Wait(); ((Manager as ApplicationManager).OnServerEvent)(this, new GameEventArgs(null, false, gameEvent)); if (gameEvent.Type == GameEvent.EventType.Connect) { + IsProcessingEvent.Wait(); if (!gameEvent.OnProcessed.Wait(30 * 1000)) { Manager.GetLogger().WriteError($"{Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_COMMAND_TIMEOUT"]} [{gameEvent.Id}, {gameEvent.Type}]"); } + IsProcessingEvent.Release(1); } + IsProcessingEvent.Release(1); return; #if DEBUG diff --git a/Application/Properties/PublishProfiles/Stable-Windows.pubxml b/Application/Properties/PublishProfiles/Stable-Windows.pubxml deleted file mode 100644 index 49599c2f4..000000000 --- a/Application/Properties/PublishProfiles/Stable-Windows.pubxml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - FileSystem - Release - netcoreapp2.0 - C:\Projects\IW4M-Admin\Publish\Windows - - \ No newline at end of file diff --git a/Application/Server.cs b/Application/Server.cs index 0fb40c348..905e88740 100644 --- a/Application/Server.cs +++ b/Application/Server.cs @@ -231,7 +231,14 @@ namespace IW4MAdmin // reban the "evading" guid if (player.Level != Player.Permission.Banned && currentBan.Type == Penalty.PenaltyType.Ban) + { + // hack: re apply the automated offense to the reban + if (currentBan.AutomatedOffense != null) + { + autoKickClient.AdministeredPenalties.Add(new EFPenalty() { AutomatedOffense = currentBan.AutomatedOffense }); + } await player.Ban($"{currentBan.Offense}", autoKickClient); + } // they didn't fully connect so empty their slot Players[player.ClientNumber] = null; diff --git a/DiscordWebhook/DiscordWebhook.pyproj b/DiscordWebhook/DiscordWebhook.pyproj index f8020fba8..c3ed35f4f 100644 --- a/DiscordWebhook/DiscordWebhook.pyproj +++ b/DiscordWebhook/DiscordWebhook.pyproj @@ -10,6 +10,7 @@ . . DiscordWebhook + true DiscordWebhook MSBuild|env|$(MSBuildProjectFullPath) False @@ -49,7 +50,7 @@ True - + @@ -58,4 +59,37 @@ + + + + + True + True + http://localhost + False + + + + + + + CurrentPage + True + False + False + False + + + + + + + + + False + False + + + + \ No newline at end of file diff --git a/IW4MAdmin.sln b/IW4MAdmin.sln index 319250726..efe8e8387 100644 --- a/IW4MAdmin.sln +++ b/IW4MAdmin.sln @@ -10,6 +10,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution _commands.gsc = _commands.gsc _customcallbacks.gsc = _customcallbacks.gsc README.md = README.md + RunPublishPre.cmd = RunPublishPre.cmd version.txt = version.txt EndProjectSection EndProject diff --git a/RunPublishPre.cmd b/RunPublishPre.cmd new file mode 100644 index 000000000..b9954b86d --- /dev/null +++ b/RunPublishPre.cmd @@ -0,0 +1,8 @@ +dotnet publish WebfrontCore/WebfrontCore.csproj -c Prerelease -o C:\Projects\IW4M-Admin\Publish\WindowsPrerelease +dotnet publish Application/Application.csproj -c Prerelease -o C:\Projects\IW4M-Admin\Publish\WindowsPrerelease +dotnet publish GameLogServer/GameLogServer.pyproj -c Release -o C:\Projects\IW4M-Admin\Publish\WindowsPrerelease\GameLogServer +call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\Tools\VsDevCmd.bat" +msbuild GameLogServer/GameLogServer.pyproj /p:PublishProfile=FolderProfile /p:DeployOnBuild=true /p:PublishProfileRootFolder=C:\Projects\IW4M-Admin\GameLogServer\ +msbuild DiscordWebhook/DiscordWebhook.pyproj /p:PublishProfile=FolderProfile /p:DeployOnBuild=true /p:PublishProfileRootFolder=C:\Projects\IW4M-Admin\DiscordWebhook\ +cd "C:\Projects\IW4M-Admin\DEPLOY\" +PowerShell ".\upload_prerelease.ps1" \ No newline at end of file diff --git a/SharedLibraryCore/Commands/NativeCommands.cs b/SharedLibraryCore/Commands/NativeCommands.cs index 7951080c7..323c89531 100644 --- a/SharedLibraryCore/Commands/NativeCommands.cs +++ b/SharedLibraryCore/Commands/NativeCommands.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using SharedLibraryCore.Database; using SharedLibraryCore.Database.Models; +using SharedLibraryCore.Events; using SharedLibraryCore.Objects; using SharedLibraryCore.Services; using System; @@ -464,6 +465,7 @@ namespace SharedLibraryCore.Commands return; } + Player.Permission oldPerm = E.Target.Level; Player.Permission newPerm = Utilities.MatchPermission(E.Data); if (newPerm == Player.Permission.Owner && @@ -518,6 +520,21 @@ namespace SharedLibraryCore.Commands E.Owner.Manager.GetPrivilegedClients()[E.Target.ClientId] = E.Target; } + var e = new GameEvent() + { + Origin = E.Origin, + Target = E.Target, + Owner = E.Owner, + Type = GameEvent.EventType.ChangePermission, + Extra = new Change() + { + PreviousValue = oldPerm.ToString(), + NewValue = newPerm.ToString() + } + }; + + E.Owner.Manager.GetEventHandler().AddEvent(e); + await E.Origin.Tell($"{E.Target.Name} {Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_SUCCESS"]}"); } diff --git a/SharedLibraryCore/Database/Models/EFChangeHistory.cs b/SharedLibraryCore/Database/Models/EFChangeHistory.cs index 0fc9794ab..33be8cf50 100644 --- a/SharedLibraryCore/Database/Models/EFChangeHistory.cs +++ b/SharedLibraryCore/Database/Models/EFChangeHistory.cs @@ -12,7 +12,8 @@ namespace SharedLibraryCore.Database.Models { public enum ChangeType { - Permission + Permission, + Ban } [Key] @@ -23,5 +24,7 @@ namespace SharedLibraryCore.Database.Models public DateTime TimeChanged { get; set; } = DateTime.UtcNow; [MaxLength(128)] public string Comment { get; set; } + public string PreviousValue { get; set; } + public string CurrentValue { get; set; } } } diff --git a/SharedLibraryCore/Database/Models/SharedEntity.cs b/SharedLibraryCore/Database/Models/SharedEntity.cs index 7784cbcaf..269158546 100644 --- a/SharedLibraryCore/Database/Models/SharedEntity.cs +++ b/SharedLibraryCore/Database/Models/SharedEntity.cs @@ -8,6 +8,6 @@ namespace SharedLibraryCore.Database.Models { public class SharedEntity { - public bool Active { get; set; } + public bool Active { get; set; } = true; } } diff --git a/SharedLibraryCore/Events/Change.cs b/SharedLibraryCore/Events/Change.cs new file mode 100644 index 000000000..6e4eaea12 --- /dev/null +++ b/SharedLibraryCore/Events/Change.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace SharedLibraryCore.Events +{ + /// + /// represents change from one value to another + /// + class Change + { + /// + /// represents the previous value of the item + /// + public string PreviousValue { get; set; } + /// + /// represents the new/current value of the item + /// + public string NewValue { get; set; } + } +} diff --git a/SharedLibraryCore/Events/EventAPI.cs b/SharedLibraryCore/Events/EventAPI.cs index 4fc37e5e2..a8fbac192 100644 --- a/SharedLibraryCore/Events/EventAPI.cs +++ b/SharedLibraryCore/Events/EventAPI.cs @@ -1,5 +1,8 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; +using SharedLibraryCore.Database; +using SharedLibraryCore.Database.Models; using SharedLibraryCore.Dtos; namespace SharedLibraryCore.Events @@ -22,7 +25,92 @@ namespace SharedLibraryCore.Events return eventList; } - public static void OnGameEvent(object sender, GameEventArgs eventState) + private static async Task SaveChangeHistory(GameEvent e) + { + EFChangeHistory change = null; + + switch (e.Type) + { + case GameEvent.EventType.Unknown: + break; + case GameEvent.EventType.Start: + break; + case GameEvent.EventType.Stop: + break; + case GameEvent.EventType.Connect: + break; + case GameEvent.EventType.Join: + break; + case GameEvent.EventType.Quit: + break; + case GameEvent.EventType.Disconnect: + break; + case GameEvent.EventType.MapEnd: + break; + case GameEvent.EventType.MapChange: + break; + case GameEvent.EventType.Say: + break; + case GameEvent.EventType.Warn: + break; + case GameEvent.EventType.Report: + break; + case GameEvent.EventType.Flag: + break; + case GameEvent.EventType.Unflag: + break; + case GameEvent.EventType.Kick: + break; + case GameEvent.EventType.TempBan: + break; + case GameEvent.EventType.Ban: + change = new EFChangeHistory() + { + OriginEntityId = e.Origin.ClientId, + TargetEntityId = e.Target.ClientId, + TypeOfChange = EFChangeHistory.ChangeType.Ban, + Comment = e.Data + }; + break; + case GameEvent.EventType.Command: + break; + case GameEvent.EventType.ChangePermission: + change = new EFChangeHistory() + { + OriginEntityId = e.Origin.ClientId, + TargetEntityId = e.Target.ClientId, + TypeOfChange = EFChangeHistory.ChangeType.Permission, + PreviousValue = ((Change)e.Extra).PreviousValue, + CurrentValue = ((Change)e.Extra).NewValue + }; + break; + case GameEvent.EventType.Broadcast: + break; + case GameEvent.EventType.Tell: + break; + case GameEvent.EventType.ScriptDamage: + break; + case GameEvent.EventType.ScriptKill: + break; + case GameEvent.EventType.Damage: + break; + case GameEvent.EventType.Kill: + break; + case GameEvent.EventType.JoinTeam: + break; + } + + if (change != null) + { + using (var ctx = new DatabaseContext(true)) + { + ctx.EFChangeHistory.Add(change); + await ctx.SaveChangesAsync(); + } + } + } + + public static async void OnGameEvent(object sender, GameEventArgs eventState) { var E = eventState.Event; // don't want to clog up the api with unknown events @@ -62,6 +150,8 @@ namespace SharedLibraryCore.Events // add the new event to the list AddNewEvent(apiEvent); + + await SaveChangeHistory(E); } /// diff --git a/SharedLibraryCore/Events/GameEvent.cs b/SharedLibraryCore/Events/GameEvent.cs index 59be67b38..1bde1db78 100644 --- a/SharedLibraryCore/Events/GameEvent.cs +++ b/SharedLibraryCore/Events/GameEvent.cs @@ -9,41 +9,118 @@ namespace SharedLibraryCore { public enum EventType { + /// + /// the event wasn't parsed properly + /// Unknown, // events "generated" by the server + /// + /// a server started being monitored + /// Start, + /// + /// a server stopped being monitored + /// Stop, + /// + /// a client was detecting as connecting via RCon + /// Connect, + /// + /// a client was detecting joining via log + /// Join, + /// + /// a client was detected leaving via log + /// Quit, + /// + /// a client was detected leaving by RCon + /// Disconnect, + /// + /// the current map ended + /// MapEnd, + /// + /// the current map changed + /// MapChange, - // events "generated" by clients + // events "generated" by clients + /// + /// a client sent a message + /// Say, + /// + /// a client was warned + /// Warn, + /// + /// a client was reported + /// Report, + /// + /// a client was flagged + /// Flag, + /// + /// a client was unflagged + /// Unflag, + /// + /// a client was kicked + /// Kick, + /// + /// a client was tempbanned + /// TempBan, + /// + /// a client was banned + /// Ban, + /// + /// a client entered a command + /// Command, + /// + /// a client's permission was changed + /// + ChangePermission, // events "generated" by IW4MAdmin + /// + /// a message is sent to all clients + /// Broadcast, + /// + /// a message is sent to a specific client + /// Tell, // events "generated" by script/log + /// + /// AC Damage Log + /// ScriptDamage, + /// + /// AC Kill Log + /// ScriptKill, + /// + /// damage info printed out by game script + /// Damage, + /// + /// kill info printed out by game script + /// Kill, + /// + /// team info printed out by game script + /// JoinTeam, - - StatusUpdate } static long NextEventId; diff --git a/SharedLibraryCore/Migrations/20180911190823_AddEFAliasNameMaxLength24.cs b/SharedLibraryCore/Migrations/20180911190823_AddEFAliasNameMaxLength24.cs index c38024983..362b51317 100644 --- a/SharedLibraryCore/Migrations/20180911190823_AddEFAliasNameMaxLength24.cs +++ b/SharedLibraryCore/Migrations/20180911190823_AddEFAliasNameMaxLength24.cs @@ -6,7 +6,15 @@ namespace SharedLibraryCore.Migrations { protected override void Up(MigrationBuilder migrationBuilder) { - + // hack: we can't alter the column on SQLite, but we need max length limit for the Index in MySQL etc + if (migrationBuilder.ActiveProvider != "Microsoft.EntityFrameworkCore.Sqlite") + { + migrationBuilder.AlterColumn( + name: "Name", + table: "EFAlias", + maxLength: 24, + nullable: false); + } } protected override void Down(MigrationBuilder migrationBuilder) diff --git a/SharedLibraryCore/Migrations/20180912015012_AddPreviousCurrentValueToEFChangeHistory.Designer.cs b/SharedLibraryCore/Migrations/20180912015012_AddPreviousCurrentValueToEFChangeHistory.Designer.cs new file mode 100644 index 000000000..4db53a4f1 --- /dev/null +++ b/SharedLibraryCore/Migrations/20180912015012_AddPreviousCurrentValueToEFChangeHistory.Designer.cs @@ -0,0 +1,684 @@ +// +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("20180912015012_AddPreviousCurrentValueToEFChangeHistory")] + partial class AddPreviousCurrentValueToEFChangeHistory + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.1.2-rtm-30932"); + + 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("CurrentViewAngleVector3Id"); + + b.Property("Deaths"); + + b.Property("Distance"); + + b.Property("EloRating"); + + b.Property("HitDestinationVector3Id"); + + b.Property("HitLocation"); + + b.Property("HitOriginVector3Id"); + + b.Property("HitType"); + + b.Property("Hits"); + + b.Property("Kills"); + + b.Property("LastStrainAngleVector3Id"); + + 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("CurrentViewAngleVector3Id"); + + b.HasIndex("HitDestinationVector3Id"); + + b.HasIndex("HitOriginVector3Id"); + + b.HasIndex("LastStrainAngleVector3Id"); + + 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.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("CurrentViewAngleVector3Id"); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitDestination") + .WithMany() + .HasForeignKey("HitDestinationVector3Id"); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitOrigin") + .WithMany() + .HasForeignKey("HitOriginVector3Id"); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "LastStrainAngle") + .WithMany() + .HasForeignKey("LastStrainAngleVector3Id"); + }); + + 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/20180912015012_AddPreviousCurrentValueToEFChangeHistory.cs b/SharedLibraryCore/Migrations/20180912015012_AddPreviousCurrentValueToEFChangeHistory.cs new file mode 100644 index 000000000..2ccf0c2a9 --- /dev/null +++ b/SharedLibraryCore/Migrations/20180912015012_AddPreviousCurrentValueToEFChangeHistory.cs @@ -0,0 +1,31 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace SharedLibraryCore.Migrations +{ + public partial class AddPreviousCurrentValueToEFChangeHistory : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CurrentValue", + table: "EFChangeHistory", + nullable: true); + + migrationBuilder.AddColumn( + name: "PreviousValue", + table: "EFChangeHistory", + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "CurrentValue", + table: "EFChangeHistory"); + + migrationBuilder.DropColumn( + name: "PreviousValue", + table: "EFChangeHistory"); + } + } +} diff --git a/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs b/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs index d1f923a98..9e579405d 100644 --- a/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs +++ b/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs @@ -356,8 +356,12 @@ namespace SharedLibraryCore.Migrations b.Property("Comment") .HasMaxLength(128); + b.Property("CurrentValue"); + b.Property("OriginEntityId"); + b.Property("PreviousValue"); + b.Property("TargetEntityId"); b.Property("TimeChanged"); diff --git a/SharedLibraryCore/Services/PenaltyService.cs b/SharedLibraryCore/Services/PenaltyService.cs index 13a997242..2e0177ce0 100644 --- a/SharedLibraryCore/Services/PenaltyService.cs +++ b/SharedLibraryCore/Services/PenaltyService.cs @@ -101,9 +101,8 @@ namespace SharedLibraryCore.Services public async Task> GetRecentPenalties(int count, int offset, Penalty.PenaltyType showOnly = Penalty.PenaltyType.Any) { - using (var context = new DatabaseContext()) + using (var context = new DatabaseContext(true)) return await context.Penalties - .AsNoTracking() .Include(p => p.Offender.CurrentAlias) .Include(p => p.Punisher.CurrentAlias) .Where(p => showOnly == Penalty.PenaltyType.Any ? p.Type != Penalty.PenaltyType.Any : p.Type == showOnly) @@ -116,9 +115,8 @@ namespace SharedLibraryCore.Services public async Task> GetClientPenaltiesAsync(int clientId) { - using (var context = new DatabaseContext()) + using (var context = new DatabaseContext(true)) return await context.Penalties - .AsNoTracking() .Where(p => p.OffenderId == clientId) .Where(p => p.Active) .Include(p => p.Offender.CurrentAlias) @@ -134,10 +132,9 @@ namespace SharedLibraryCore.Services /// public async Task> ReadGetClientPenaltiesAsync(int clientId, bool victim = true) { - using (var context = new DatabaseContext()) + using (var context = new DatabaseContext(true)) { - context.ChangeTracker.AutoDetectChangesEnabled = false; - context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; + // todo: clean this up if (victim) { var now = DateTime.UtcNow; @@ -233,32 +230,26 @@ namespace SharedLibraryCore.Services } } - public async Task> GetActivePenaltiesAsync(int aliasId, int ip = 0) + public async Task> GetActivePenaltiesAsync(int linkId, int ip = 0) { var now = DateTime.UtcNow; - using (var context = new DatabaseContext()) + using (var context = new DatabaseContext(true)) { - var iqPenalties = await (from link in context.AliasLinks - where link.AliasLinkId == aliasId - join penalty in context.Penalties - on link.AliasLinkId equals penalty.LinkId - where penalty.Active - where penalty.Expires > now - orderby penalty.When descending - select penalty).ToListAsync(); - if (ip != 0) - { - iqPenalties.AddRange(await (from alias in context.Aliases - where alias.IPAddress == ip - join penalty in context.Penalties - on alias.LinkId equals penalty.LinkId - where penalty.Active - where penalty.Expires > now - orderby penalty.When descending - select penalty).ToListAsync()); - } - return iqPenalties; + var iqPenalties = context.Penalties + .Where(p => p.LinkId == linkId || + p.Link.Children.Any(a => a.IPAddress == ip)) + .Where(p => p.Active) + .Where(p => p.Expires > now); + + +#if DEBUG == true + var penaltiesSql = iqPenalties.ToSql(); +#endif + + var activePenalties = await iqPenalties.ToListAsync(); + // this is a bit more performant in memory (ordering) + return activePenalties.OrderByDescending(p =>p.When).ToList(); } } @@ -286,8 +277,6 @@ namespace SharedLibraryCore.Services .ForEachAsync(c => c.Level = Player.Permission.User); await internalContext.SaveChangesAsync(); } - - } }); diff --git a/SharedLibraryCore/SharedLibraryCore.csproj b/SharedLibraryCore/SharedLibraryCore.csproj index 04068ecf5..3522e9b87 100644 --- a/SharedLibraryCore/SharedLibraryCore.csproj +++ b/SharedLibraryCore/SharedLibraryCore.csproj @@ -36,7 +36,7 @@ - +