From 4b1f44cc2a8d9b0b3d2290192a2572de2a16dae1 Mon Sep 17 00:00:00 2001 From: RaidMax Date: Fri, 22 Feb 2019 19:06:51 -0600 Subject: [PATCH] re-enable login to webfront with password update cookie to last 3 months add configuration option to limit # of rss feed items prevent database tracking of bots if ignore bots requested add last map and last server played to profile --- Application/Application.csproj | 6 +- Application/ApplicationManager.cs | 42 ++ Application/IW4MServer.cs | 13 + Plugins/AutomessageFeed/Configuration.cs | 7 +- Plugins/AutomessageFeed/Plugin.cs | 2 +- Plugins/Stats/Plugin.cs | 6 +- Plugins/Tests/Tests.csproj | 8 +- SharedLibraryCore/Database/DatabaseContext.cs | 9 +- ...ddIndexToEFMeta-KeyAndClientId.Designer.cs | 696 ++++++++++++++++++ ...2234742_AddIndexToEFMeta-KeyAndClientId.cs | 22 + .../DatabaseContextModelSnapshot.cs | 4 +- SharedLibraryCore/Services/MetaService.cs | 59 +- SharedLibraryCore/SharedLibraryCore.csproj | 1 + WebfrontCore/Controllers/AccountController.cs | 14 +- WebfrontCore/Controllers/ClientController.cs | 2 +- 15 files changed, 864 insertions(+), 27 deletions(-) create mode 100644 SharedLibraryCore/Migrations/20190222234742_AddIndexToEFMeta-KeyAndClientId.Designer.cs create mode 100644 SharedLibraryCore/Migrations/20190222234742_AddIndexToEFMeta-KeyAndClientId.cs diff --git a/Application/Application.csproj b/Application/Application.csproj index 96ae5c360..53334a694 100644 --- a/Application/Application.csproj +++ b/Application/Application.csproj @@ -6,7 +6,7 @@ 2.2.2 false RaidMax.IW4MAdmin.Application - 2.2.5.4 + 2.2.5.5 RaidMax Forever None IW4MAdmin @@ -31,8 +31,8 @@ true true - 2.2.5.4 - 2.2.5.4 + 2.2.5.5 + 2.2.5.5 diff --git a/Application/ApplicationManager.cs b/Application/ApplicationManager.cs index 68e245baa..f81ae7b85 100644 --- a/Application/ApplicationManager.cs +++ b/Application/ApplicationManager.cs @@ -7,6 +7,7 @@ using SharedLibraryCore.Commands; using SharedLibraryCore.Configuration; using SharedLibraryCore.Database; using SharedLibraryCore.Database.Models; +using SharedLibraryCore.Dtos; using SharedLibraryCore.Events; using SharedLibraryCore.Exceptions; using SharedLibraryCore.Helpers; @@ -58,6 +59,7 @@ namespace IW4MAdmin.Application readonly SemaphoreSlim ProcessingEvent = new SemaphoreSlim(1, 1); readonly Dictionary Loggers = new Dictionary(); readonly ITokenAuthentication _authenticator; + private readonly MetaService _metaService; private ApplicationManager() { @@ -77,6 +79,7 @@ namespace IW4MAdmin.Application OnServerEvent += OnGameEvent; OnServerEvent += EventApi.OnGameEvent; _authenticator = new TokenAuthentication(); + _metaService = new MetaService(); } private async void OnGameEvent(object sender, GameEventArgs args) @@ -384,6 +387,45 @@ namespace IW4MAdmin.Application } #endregion + #region META + async Task> getLastMap(int clientId) + { + var meta = await _metaService.GetPersistentMeta("LastMapPlayed", new EFClient() { ClientId = clientId }); + + return meta == null ? new List() : new List() + { + new ProfileMeta() + { + Id = meta.MetaId, + Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_LAST_MAP"], + Value = meta.Value, + Show = true + } + + }; + } + + async Task> getLastServer(int clientId) + { + var meta = await _metaService.GetPersistentMeta("LastServerPlayed", new EFClient() { ClientId = clientId }); + + return meta == null ? new List() : new List() + { + new ProfileMeta() + { + Id = meta.MetaId, + Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_LAST_SERVER"], + Value = meta.Value, + Show = true + } + + }; + } + + MetaService.AddRuntimeMeta(getLastMap); + MetaService.AddRuntimeMeta(getLastServer); + #endregion + #region INIT async Task Init(ServerConfiguration Conf) { diff --git a/Application/IW4MServer.cs b/Application/IW4MServer.cs index b2afb6acb..916b11423 100644 --- a/Application/IW4MServer.cs +++ b/Application/IW4MServer.cs @@ -9,6 +9,7 @@ using SharedLibraryCore.Exceptions; using SharedLibraryCore.Interfaces; using SharedLibraryCore.Localization; using SharedLibraryCore.Objects; +using SharedLibraryCore.Services; using System; using System.Collections.Generic; using System.IO; @@ -199,6 +200,12 @@ namespace IW4MAdmin else if (E.Type == GameEvent.EventType.PreConnect) { + // we don't want to track bots in the database at all if ignore bots is requested + if (E.Origin.IsBot && Manager.GetApplicationSettings().Configuration().IgnoreBots) + { + return false; + } + if (Clients[E.Origin.ClientNumber] == null) { #if DEBUG == true @@ -306,6 +313,12 @@ namespace IW4MAdmin } } + else if (E.Type == GameEvent.EventType.Disconnect) + { + await new MetaService().AddPersistentMeta("LastMapPlayed", CurrentMap.Alias, E.Origin); + await new MetaService().AddPersistentMeta("LastServerPlayed", E.Owner.Hostname, E.Origin); + } + else if (E.Type == GameEvent.EventType.PreDisconnect) { if ((DateTime.UtcNow - SessionStart).TotalSeconds < 30) diff --git a/Plugins/AutomessageFeed/Configuration.cs b/Plugins/AutomessageFeed/Configuration.cs index 50719b2c3..0b8052bac 100644 --- a/Plugins/AutomessageFeed/Configuration.cs +++ b/Plugins/AutomessageFeed/Configuration.cs @@ -1,8 +1,5 @@ using SharedLibraryCore; using SharedLibraryCore.Interfaces; -using System; -using System.Collections.Generic; -using System.Text; namespace AutomessageFeed { @@ -10,6 +7,7 @@ namespace AutomessageFeed { public bool EnableFeed { get; set; } public string FeedUrl { get; set; } + public int MaxFeedItems { get; set; } public IBaseConfiguration Generate() { @@ -18,6 +16,9 @@ namespace AutomessageFeed if (EnableFeed) { FeedUrl = Utilities.PromptString(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_AUTOMESSAGEFEED_URL"]); + MaxFeedItems = Utilities.PromptInt(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_AUTOMESSAGEFEED_PROMPT_MAXITEMS"], + Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_AUTOMESSAGEFEED_PROMPT_MAXITEMS_DESC"], + 0, int.MaxValue, 0); } return this; diff --git a/Plugins/AutomessageFeed/Plugin.cs b/Plugins/AutomessageFeed/Plugin.cs index e5835b731..56abd3d22 100644 --- a/Plugins/AutomessageFeed/Plugin.cs +++ b/Plugins/AutomessageFeed/Plugin.cs @@ -43,7 +43,7 @@ namespace AutomessageFeed } } - if (_currentFeedItem < items.Count) + if (_currentFeedItem < items.Count && (_configuration.MaxFeedItems == 0 || _currentFeedItem < _configuration.MaxFeedItems)) { _currentFeedItem++; return items[_currentFeedItem - 1]; diff --git a/Plugins/Stats/Plugin.cs b/Plugins/Stats/Plugin.cs index c9bf5727a..c93ecc53d 100644 --- a/Plugins/Stats/Plugin.cs +++ b/Plugins/Stats/Plugin.cs @@ -282,14 +282,14 @@ namespace IW4MAdmin.Plugins.Stats return messageMeta; } - MetaService.AddMeta(getStats); + MetaService.AddRuntimeMeta(getStats); if (Config.Configuration().EnableAntiCheat) { - MetaService.AddMeta(getAnticheatInfo); + MetaService.AddRuntimeMeta(getAnticheatInfo); } - MetaService.AddMeta(getMessages); + MetaService.AddRuntimeMeta(getMessages); async Task totalKills(Server server) { diff --git a/Plugins/Tests/Tests.csproj b/Plugins/Tests/Tests.csproj index 84255c5de..03e7bb2d2 100644 --- a/Plugins/Tests/Tests.csproj +++ b/Plugins/Tests/Tests.csproj @@ -13,8 +13,12 @@ - - + + + + all + runtime; build; native; contentfiles; analyzers + diff --git a/SharedLibraryCore/Database/DatabaseContext.cs b/SharedLibraryCore/Database/DatabaseContext.cs index 98de184bf..e60bbd806 100644 --- a/SharedLibraryCore/Database/DatabaseContext.cs +++ b/SharedLibraryCore/Database/DatabaseContext.cs @@ -4,6 +4,7 @@ using SharedLibraryCore.Database.Models; using SharedLibraryCore.Interfaces; using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; @@ -22,7 +23,7 @@ namespace SharedLibraryCore.Database static string _ConnectionString; static string _provider; - private static readonly string _migrationPluginDirectory = @"X:\IW4MAdmin\BUILD\Plugins\"; + private static readonly string _migrationPluginDirectory = @"X:\IW4MAdmin\BUILD\Plugins"; public DatabaseContext(DbContextOptions opt) : base(opt) { } @@ -123,6 +124,11 @@ namespace SharedLibraryCore.Database ent.HasIndex(a => a.Name); }); + modelBuilder.Entity(ent => + { + ent.HasIndex(_meta => _meta.Key); + }); + // force full name for database conversion modelBuilder.Entity().ToTable("EFClients"); modelBuilder.Entity().ToTable("EFAlias"); @@ -138,7 +144,6 @@ namespace SharedLibraryCore.Database #endif IEnumerable directoryFiles = Directory.GetFiles(pluginDir).Where(f => f.EndsWith(".dll")); - foreach (string dllPath in directoryFiles) { Assembly library; diff --git a/SharedLibraryCore/Migrations/20190222234742_AddIndexToEFMeta-KeyAndClientId.Designer.cs b/SharedLibraryCore/Migrations/20190222234742_AddIndexToEFMeta-KeyAndClientId.Designer.cs new file mode 100644 index 000000000..284f81338 --- /dev/null +++ b/SharedLibraryCore/Migrations/20190222234742_AddIndexToEFMeta-KeyAndClientId.Designer.cs @@ -0,0 +1,696 @@ +// +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("20190222234742_AddIndexToEFMeta-KeyAndClientId")] + partial class AddIndexToEFMetaKeyAndClientId + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.2-servicing-10034"); + + 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("EndPoint"); + + 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.HasIndex("Key"); + + 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("IsEvadedOffense"); + + 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/20190222234742_AddIndexToEFMeta-KeyAndClientId.cs b/SharedLibraryCore/Migrations/20190222234742_AddIndexToEFMeta-KeyAndClientId.cs new file mode 100644 index 000000000..2b726c9e0 --- /dev/null +++ b/SharedLibraryCore/Migrations/20190222234742_AddIndexToEFMeta-KeyAndClientId.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace SharedLibraryCore.Migrations +{ + public partial class AddIndexToEFMetaKeyAndClientId : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateIndex( + name: "IX_EFMeta_Key", + table: "EFMeta", + column: "Key"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_EFMeta_Key", + table: "EFMeta"); + } + } +} diff --git a/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs b/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs index 19225ca16..2ecfd4260 100644 --- a/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs +++ b/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs @@ -14,7 +14,7 @@ namespace SharedLibraryCore.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.1.4-rtm-31024"); + .HasAnnotation("ProductVersion", "2.2.2-servicing-10034"); modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b => { @@ -443,6 +443,8 @@ namespace SharedLibraryCore.Migrations b.HasIndex("ClientId"); + b.HasIndex("Key"); + b.ToTable("EFMeta"); }); diff --git a/SharedLibraryCore/Services/MetaService.cs b/SharedLibraryCore/Services/MetaService.cs index e78793f78..2f540185a 100644 --- a/SharedLibraryCore/Services/MetaService.cs +++ b/SharedLibraryCore/Services/MetaService.cs @@ -1,24 +1,71 @@ -using SharedLibraryCore.Dtos; +using Microsoft.EntityFrameworkCore; +using SharedLibraryCore.Database; +using SharedLibraryCore.Database.Models; +using SharedLibraryCore.Dtos; +using SharedLibraryCore.Interfaces; using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; namespace SharedLibraryCore.Services { public class MetaService { - private static List>>> MetaActions = new List>>>(); + private static List>>> _metaActions = new List>>>(); - public static void AddMeta(Func>> metaAction) + public async Task AddPersistentMeta(string metaKey, string metaValue, EFClient client) { - MetaActions.Add(metaAction); + using (var ctx = new DatabaseContext()) + { + var existingMeta = await ctx.EFMeta.FirstOrDefaultAsync(_meta => _meta.ClientId == client.ClientId && _meta.Key == metaKey); + + if (existingMeta != null) + { + existingMeta.Value = metaValue; + existingMeta.Updated = DateTime.UtcNow; + } + + else + { + ctx.EFMeta.Add(new EFMeta() + { + ClientId = client.ClientId, + Created = DateTime.UtcNow, + Key = metaKey, + Value = metaValue + }); + } + + await ctx.SaveChangesAsync(); + } } - public static async Task> GetMeta(int clientId) + public Task GetPersistentMeta(string metaKey, EFClient client) + { + using (var ctx = new DatabaseContext(disableTracking:true)) + { + return ctx.EFMeta + .Where(_meta => _meta.Key == metaKey) + .Where(_meta => _meta.ClientId == client.ClientId) + .FirstOrDefaultAsync(); + } + } + + public static void AddRuntimeMeta(Func>> metaAction) + { + _metaActions.Add(metaAction); + } + + public static async Task> GetRuntimeMeta(int clientId) { var meta = new List(); - foreach (var action in MetaActions) + + foreach (var action in _metaActions) + { meta.AddRange(await action(clientId)); + } + return meta; } } diff --git a/SharedLibraryCore/SharedLibraryCore.csproj b/SharedLibraryCore/SharedLibraryCore.csproj index 9fb48da62..c4ca779ad 100644 --- a/SharedLibraryCore/SharedLibraryCore.csproj +++ b/SharedLibraryCore/SharedLibraryCore.csproj @@ -17,6 +17,7 @@ + diff --git a/WebfrontCore/Controllers/AccountController.cs b/WebfrontCore/Controllers/AccountController.cs index 5cfdb3c85..4052070f4 100644 --- a/WebfrontCore/Controllers/AccountController.cs +++ b/WebfrontCore/Controllers/AccountController.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System; using System.Security.Claims; @@ -10,6 +9,11 @@ namespace WebfrontCore.Controllers { public class AccountController : BaseController { + /// + /// life span in months + /// + private const int COOKIE_LIFESPAN = 3; + [HttpGet] public async Task LoginAsync(int clientId, string password) { @@ -22,10 +26,10 @@ namespace WebfrontCore.Controllers { var client = Manager.GetPrivilegedClients()[clientId]; - // string[] hashedPassword = await Task.FromResult(SharedLibraryCore.Helpers.Hashing.Hash(password, client.PasswordSalt)); - //if (hashedPassword[0] == client.Password) + bool loginSuccess = Manager.TokenAuthenticator.AuthorizeToken(client.NetworkId, password) || + (await Task.FromResult(SharedLibraryCore.Helpers.Hashing.Hash(password, client.PasswordSalt)))[0] == client.Password; - if (Manager.TokenAuthenticator.AuthorizeToken(client.NetworkId, password)) + if (loginSuccess) { var claims = new[] { @@ -40,7 +44,7 @@ namespace WebfrontCore.Controllers await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrinciple, new AuthenticationProperties() { AllowRefresh = true, - ExpiresUtc = DateTime.UtcNow.AddDays(30), + ExpiresUtc = DateTime.UtcNow.AddMonths(COOKIE_LIFESPAN), IsPersistent = true, IssuedUtc = DateTime.UtcNow }); diff --git a/WebfrontCore/Controllers/ClientController.cs b/WebfrontCore/Controllers/ClientController.cs index 8f9365e6c..d012735fe 100644 --- a/WebfrontCore/Controllers/ClientController.cs +++ b/WebfrontCore/Controllers/ClientController.cs @@ -59,7 +59,7 @@ namespace WebfrontCore.Controllers LinkedAccounts = client.LinkedAccounts }; - var meta = await MetaService.GetMeta(client.ClientId); + var meta = await MetaService.GetRuntimeMeta(client.ClientId); var penaltyMeta = await Manager.GetPenaltyService() .ReadGetClientPenaltiesAsync(client.ClientId); var administeredPenaltiesMeta = await Manager.GetPenaltyService()