From aaf9eb09b6a7871dc78f4fa045d96aa40782f89d Mon Sep 17 00:00:00 2001 From: RaidMax Date: Wed, 2 Jan 2019 18:32:39 -0600 Subject: [PATCH] more alias changes :( fix flag penalty coming from wrong user --- Application/Application.csproj | 8 +- Application/IW4MServer.cs | 2 +- SharedLibraryCore/Database/DatabaseContext.cs | 7 + SharedLibraryCore/Objects/EFClient.cs | 3 +- SharedLibraryCore/Server.cs | 2 +- SharedLibraryCore/Services/ClientService.cs | 283 ++++++++---------- SharedLibraryCore/Services/PenaltyService.cs | 6 +- 7 files changed, 144 insertions(+), 167 deletions(-) diff --git a/Application/Application.csproj b/Application/Application.csproj index 2870f0985..e328741d7 100644 --- a/Application/Application.csproj +++ b/Application/Application.csproj @@ -6,12 +6,12 @@ 2.1.5 false RaidMax.IW4MAdmin.Application - 2.2.3.0 + 2.2.3.1 RaidMax Forever None IW4MAdmin IW4MAdmin is a complete server administration tool for IW4x and most Call of Duty® dedicated server - 2018 + 2019 https://github.com/RaidMax/IW4M-Admin/blob/master/LICENSE https://raidmax.org/IW4MAdmin https://github.com/RaidMax/IW4M-Admin @@ -31,8 +31,8 @@ true true - 2.2.3.0 - 2.2.3.0 + 2.2.3.1 + 2.2.3.1 diff --git a/Application/IW4MServer.cs b/Application/IW4MServer.cs index ca5e5285e..e03046b16 100644 --- a/Application/IW4MServer.cs +++ b/Application/IW4MServer.cs @@ -843,7 +843,7 @@ namespace IW4MAdmin Type = Penalty.PenaltyType.Warning, Expires = DateTime.UtcNow, Offender = Target, - Punisher = Utilities.IW4MAdminClient(this), + Punisher = Origin, Offense = Reason, Link = Target.AliasLink }; diff --git a/SharedLibraryCore/Database/DatabaseContext.cs b/SharedLibraryCore/Database/DatabaseContext.cs index 8844f7d21..98de184bf 100644 --- a/SharedLibraryCore/Database/DatabaseContext.cs +++ b/SharedLibraryCore/Database/DatabaseContext.cs @@ -36,6 +36,13 @@ namespace SharedLibraryCore.Database this.ChangeTracker.LazyLoadingEnabled = false; this.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; } + + else + { + this.ChangeTracker.AutoDetectChangesEnabled = true; + this.ChangeTracker.LazyLoadingEnabled = true; + this.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.TrackAll; + } } public DatabaseContext(string connStr, string provider) diff --git a/SharedLibraryCore/Objects/EFClient.cs b/SharedLibraryCore/Objects/EFClient.cs index f72be830b..2aaea48fc 100644 --- a/SharedLibraryCore/Objects/EFClient.cs +++ b/SharedLibraryCore/Objects/EFClient.cs @@ -454,7 +454,7 @@ namespace SharedLibraryCore.Database.Models public async Task OnJoin(int? ipAddress) { CurrentServer.Logger.WriteDebug($"Start join for {this}::{ipAddress}::{Level.ToString()}"); - + IPAddress = ipAddress; var loc = Utilities.CurrentLocalization.LocalizationIndex; var autoKickClient = Utilities.IW4MAdminClient(CurrentServer); @@ -465,6 +465,7 @@ namespace SharedLibraryCore.Database.Models } OnConnect(); + await CurrentServer.Manager.GetClientService().Update(this); CurrentServer.Logger.WriteDebug($"OnConnect finished for {this}"); diff --git a/SharedLibraryCore/Server.cs b/SharedLibraryCore/Server.cs index 967ea57de..36254afd7 100644 --- a/SharedLibraryCore/Server.cs +++ b/SharedLibraryCore/Server.cs @@ -66,7 +66,7 @@ namespace SharedLibraryCore //Returns list of all current players public List GetClientsAsList() { - return Clients.FindAll(x => x != null); + return Clients.FindAll(x => x != null && x.NetworkId != 0); } /// diff --git a/SharedLibraryCore/Services/ClientService.cs b/SharedLibraryCore/Services/ClientService.cs index af9726bb1..67214d0bf 100644 --- a/SharedLibraryCore/Services/ClientService.cs +++ b/SharedLibraryCore/Services/ClientService.cs @@ -50,8 +50,9 @@ namespace SharedLibraryCore.Services } } - public async Task UpdateAlias(EFClient entity) + private async Task UpdateAlias(string name, int? ip, EFClient entity, DatabaseContext context) { + // entity is the tracked db context item // todo: move this out #if DEBUG == false if (entity.IsBot) @@ -59,100 +60,93 @@ namespace SharedLibraryCore.Services return; } #endif - using (var context = new DatabaseContext()) - { - string name = entity.Name; - int? ip = entity.IPAddress; - - // indicates if someone appears to have played before - bool hasExistingAlias = false; - - // get all aliases by IP address and LinkId - var iqAliases = context.Aliases - .Include(a => a.Link) - //.Where(a => a.Link.Active) - .Where(a => (a.IPAddress == ip) || - a.LinkId == entity.AliasLinkId); + // get all aliases by IP address and LinkId + var iqAliases = context.Aliases + .Include(a => a.Link) + .Where(a => (a.IPAddress == ip) || + a.LinkId == entity.AliasLinkId); #if DEBUG == true - var aliasSql = iqAliases.ToSql(); + var aliasSql = iqAliases.ToSql(); #endif - var aliases = await iqAliases.ToListAsync(); + var aliases = await iqAliases.ToListAsync(); - // see if they have a matching IP + Name but new NetworkId - var existingAlias = aliases.FirstOrDefault(a => a.Name == name && a.IPAddress == ip); - bool exactAliasMatch = existingAlias != null; - // if existing alias matches link them - EFAliasLink aliasLink = existingAlias?.Link; - // if no exact matches find the first IP that matches - aliasLink = aliasLink ?? aliases.FirstOrDefault()?.Link; - // if no matches are found, create new link - aliasLink = aliasLink ?? new EFAliasLink(); + // see if they have a matching IP + Name but new NetworkId + var existingExactAlias = aliases.FirstOrDefault(a => a.Name == name && a.IPAddress == ip); + bool exactAliasMatch = existingExactAlias != null; - hasExistingAlias = aliases.Count > 0; + // if existing alias matches link them + EFAliasLink aliasLink = existingExactAlias?.Link; + // if no exact matches find the first IP that matches + aliasLink = aliasLink ?? aliases.FirstOrDefault()?.Link; + // if no matches are found, use our current one + aliasLink = aliasLink ?? entity.AliasLink; - // the existing alias matches ip and name, so we can just ignore the temporary one - if (exactAliasMatch) + bool hasExistingAlias = aliases.Count > 0; + + // this happens when an alias exists but the current link is a temporary one + if ((exactAliasMatch || hasExistingAlias) && + (!entity.AliasLink.Active && entity.AliasLinkId != aliasLink.AliasLinkId)) + { + entity.AliasLinkId = aliasLink.AliasLinkId; + entity.AliasLink = aliasLink; + + //entity.CurrentServer.Logger.WriteDebug($"Updating alias link for {entity}"); + await context.SaveChangesAsync(); + + foreach (var alias in aliases.Union(new List() { entity.CurrentAlias }) + .Where(_alias => !_alias.Active || + _alias.LinkId != aliasLink.AliasLinkId)) { - entity.CurrentServer.Logger.WriteDebug($"{entity} has exact alias match"); - // they're using the same alias as before, so we need to make sure the current aliases is set to it - if (entity.CurrentAliasId != existingAlias.AliasId) - { - context.Update(entity); + entity.CurrentServer.Logger.WriteDebug($"{entity} updating alias-link id is {alias.LinkId}"); + alias.Active = true; + alias.LinkId = aliasLink.AliasLinkId; + } - if (existingAlias.AliasId > 0) - { - entity.CurrentAliasId = existingAlias.AliasId; - } - else - { - entity.CurrentServer.Logger.WriteDebug($"Updating alias for {entity} failed"); - } - } + //entity.CurrentServer.Logger.WriteDebug($"Saving updated aliases for {entity}"); + await context.SaveChangesAsync(); - if (!entity.CurrentAlias.Active) - { - existingAlias.Active = true; - } + // todo: fix this + /*context.AliasLinks.Remove(entity.AliasLink); + entity.AliasLink = null; - entity.CurrentAlias = existingAlias; + //entity.CurrentServer.Logger.WriteDebug($"Removing temporary link for {entity}"); + + try + { + await context.SaveChangesAsync(); + } + catch + { + // entity.CurrentServer.Logger.WriteDebug($"Failed to remove link for {entity}"); + }*/ + } + + // the existing alias matches ip and name, so we can just ignore the temporary one + if (exactAliasMatch) + { + entity.CurrentServer.Logger.WriteDebug($"{entity} has exact alias match"); + entity.CurrentAliasId = existingExactAlias.AliasId; + entity.CurrentAlias = existingExactAlias; + await context.SaveChangesAsync(); + } + + // theres no exact match, but they've played before with the GUID or IP + else if (hasExistingAlias) + { + //entity.CurrentServer.Logger.WriteDebug($"Connecting player is using a new alias {entity}"); + + // this happens when a temporary alias gets updated + if (entity.CurrentAlias.Name == name && entity.CurrentAlias.IPAddress == null) + { + entity.CurrentAlias.IPAddress = ip; + entity.CurrentAlias.Active = true; + //entity.CurrentServer.Logger.WriteDebug($"Updating temporary alias for {entity}"); await context.SaveChangesAsync(); } - // theres no exact match, but they've played before with the GUID or IP - else if (hasExistingAlias) + else { - // the current link is temporary so we need to update - if (!entity.AliasLink.Active) - { - entity.CurrentServer.Logger.WriteDebug($"{entity} has temporary alias so we are deleting"); - - foreach (var alias in aliases.Where(_alias => !_alias.Active)) - { - context.Update(alias); - - if (alias.IPAddress == null && alias.Name == name) - { - context.Entry(alias).State = EntityState.Deleted; - } - - else - { - alias.Active = true; - alias.LinkId = aliasLink.AliasLinkId; - } - } - - // we want to delete the temporary alias link - context.Entry(entity.AliasLink).State = EntityState.Deleted; - } - - context.Update(entity); - entity.AliasLink = aliasLink; - entity.AliasLinkId = aliasLink.AliasLinkId; - - entity.CurrentServer.Logger.WriteDebug($"Connecting player is using a new alias {entity}"); - var newAlias = new EFAlias() { DateAdded = DateTime.UtcNow, @@ -162,65 +156,43 @@ namespace SharedLibraryCore.Services Active = true, }; - context.Aliases.Add(newAlias); entity.CurrentAlias = newAlias; - + //entity.CurrentServer.Logger.WriteDebug($"Saving new alias for {entity}"); await context.SaveChangesAsync(); } + } - // no record of them playing - else + // no record of them playing + else + { + //entity.CurrentServer.Logger.WriteDebug($"{entity} has not be seen before"); + + entity.AliasLink.Active = true; + entity.CurrentAlias.Active = true; + entity.CurrentAlias.IPAddress = ip; + entity.CurrentAlias.Name = name; + + //entity.CurrentServer.Logger.WriteDebug($"updating new alias for {entity}"); + await context.SaveChangesAsync(); + } + + var linkIds = aliases.Select(a => a.LinkId); + + if (linkIds.Count() > 0 && + aliases.Count(_alias => _alias.Name == name && _alias.IPAddress == ip) > 0) + { + var highestLevel = await context.Clients + .Where(c => linkIds.Contains(c.AliasLinkId)) + .MaxAsync(c => c.Level); + + if (entity.Level != highestLevel) { - entity.CurrentServer.Logger.WriteDebug($"{entity} has not be seen before"); - - if (name != entity.CurrentAlias.Name) - { - var newAlias = new EFAlias() - { - DateAdded = DateTime.UtcNow, - IPAddress = ip, - LinkId = entity.AliasLink.AliasLinkId, - Name = name, - Active = true - }; - - context.Update(entity); - context.Aliases.Add(newAlias); - entity.CurrentAlias = newAlias; - } - - else - { - context.Update(entity.CurrentAlias); - entity.CurrentAlias.Active = true; - entity.CurrentAlias.IPAddress = ip; - entity.CurrentAlias.Link = entity.AliasLink; - } - - context.Update(entity.AliasLink); - entity.AliasLink.Active = true; - + entity.CurrentServer.Logger.WriteDebug($"{entity} updating user level"); + // todo: log level changes here + context.Update(entity); + entity.Level = highestLevel; await context.SaveChangesAsync(); } - - var linkIds = aliases.Select(a => a.LinkId); - - if (linkIds.Count() > 0 && - aliases.Count(_alias => _alias.Name == name && _alias.IPAddress == ip) > 0) - { - var highestLevel = await context.Clients - .Where(c => linkIds.Contains(c.AliasLinkId)) - .MaxAsync(c => c.Level); - - if (entity.Level != highestLevel) - { - // todo: log level changes here - context.Update(entity); - entity.Level = highestLevel; - await context.SaveChangesAsync(); - } - } - } } @@ -310,16 +282,36 @@ namespace SharedLibraryCore.Services } } + public async Task UpdateAlias(EFClient entity) + { + using (var context = new DatabaseContext()) + { + var client = context.Clients + .Include(c => c.AliasLink) + .Include(c => c.CurrentAlias) + .First(e => e.ClientId == entity.ClientId); + + client.CurrentServer = entity.CurrentServer; + + await UpdateAlias(entity.Name, entity.IPAddress, client, context); + + entity.CurrentAlias = client.CurrentAlias; + entity.CurrentAliasId = client.CurrentAliasId; + entity.AliasLink = client.AliasLink; + entity.AliasLinkId = client.AliasLinkId; + } + } + public async Task Update(EFClient entity) { using (var context = new DatabaseContext()) { // grab the context version of the entity var client = context.Clients - .Include(c => c.AliasLink) - .Include(c => c.CurrentAlias) .First(e => e.ClientId == entity.ClientId); + client.CurrentServer = entity.CurrentServer; + // if their level has been changed if (entity.Level != client.Level) { @@ -332,30 +324,11 @@ namespace SharedLibraryCore.Services // update all related clients level await matchingClients.ForEachAsync(c => { + // todo: log that it has changed here c.Level = entity.Level; }); } - // their alias has been updated and not yet saved - if (entity.CurrentAlias.AliasId == 0) - { - client.CurrentAlias = new EFAlias() - { - Active = entity.CurrentAlias.IPAddress.HasValue ? true : false, - DateAdded = DateTime.UtcNow, - IPAddress = entity.CurrentAlias.IPAddress, - Name = entity.CurrentAlias.Name, - Link = client.AliasLink - }; - } - - else - { - client.CurrentAliasId = entity.CurrentAliasId; - client.IPAddress = entity.IPAddress; - client.Name = entity.Name; - } - // set remaining non-navigation properties that may have been updated client.Level = entity.Level; client.LastConnection = entity.LastConnection; diff --git a/SharedLibraryCore/Services/PenaltyService.cs b/SharedLibraryCore/Services/PenaltyService.cs index 12f5b6d04..556d046d1 100644 --- a/SharedLibraryCore/Services/PenaltyService.cs +++ b/SharedLibraryCore/Services/PenaltyService.cs @@ -18,10 +18,6 @@ namespace SharedLibraryCore.Services { using (var context = new DatabaseContext()) { - context.ChangeTracker.AutoDetectChangesEnabled = true; - context.ChangeTracker.LazyLoadingEnabled = true; - context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.TrackAll; - // make bans propogate to all aliases if (newEntity.Type == Penalty.PenaltyType.Ban) { @@ -95,7 +91,7 @@ namespace SharedLibraryCore.Services IsEvadedOffense = newEntity.IsEvadedOffense }; - newEntity.Offender.ReceivedPenalties.Add(penalty); + newEntity.Offender.ReceivedPenalties?.Add(penalty); context.Penalties.Add(penalty); }