public async Task AddPersistentMeta(string metaKey, string metaValue, EFClient client) { // this seems to happen if the client disconnects before they've had time to authenticate and be added if (client.ClientId < 1) { return; } using var ctx = _contextFactory.CreateContext(); var existingMeta = await ctx.EFMeta .Where(_meta => _meta.Key == metaKey) .Where(_meta => _meta.ClientId == client.ClientId) .FirstOrDefaultAsync(); 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 <IEnumerable <string> > GetMostKills(long?serverId, StatsConfiguration config, IDatabaseContextFactory contextFactory, ITranslationLookup translationLookup) { using (var ctx = contextFactory.CreateContext(enableTracking: false)) { var dayInPast = DateTime.UtcNow.AddDays(-config.MostKillsMaxInactivityDays); var iqStats = (from stats in ctx.Set <EFClientStatistics>() join client in ctx.Clients on stats.ClientId equals client.ClientId join alias in ctx.Aliases on client.CurrentAliasId equals alias.AliasId where stats.ServerId == serverId where client.Level != EFClient.Permission.Banned where client.LastConnection >= dayInPast orderby stats.Kills descending select new { alias.Name, stats.Kills }) .Take(config.MostKillsClientLimit); var iqList = await iqStats.ToListAsync(); return(iqList.Select((stats, index) => translationLookup["PLUGINS_STATS_COMMANDS_MOSTKILLS_FORMAT"].FormatExt(index + 1, stats.Name, stats.Kills)) .Prepend(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_MOSTKILLS_HEADER"])); } }
/// <summary> /// retrieves all permanent bans ordered by ban date /// if request is authorized, it will include the client's ip address. /// </summary> /// <returns></returns> public async Task <IActionResult> PublicAsync() { IList <PenaltyInfo> penalties; await using var ctx = _contextFactory.CreateContext(false); var iqPenalties = ctx.Penalties .AsNoTracking() .Where(p => p.Type == EFPenalty.PenaltyType.Ban && p.Active) .OrderByDescending(_penalty => _penalty.When) .Select(p => new PenaltyInfo() { Id = p.PenaltyId, OffenderId = p.OffenderId, OffenderName = p.Offender.CurrentAlias.Name, OffenderNetworkId = (ulong)p.Offender.NetworkId, OffenderIPAddress = Authorized ? p.Offender.CurrentAlias.IPAddress.ConvertIPtoString() : null, Offense = p.Offense, PunisherId = p.PunisherId, PunisherNetworkId = (ulong)p.Punisher.NetworkId, PunisherName = p.Punisher.CurrentAlias.Name, PunisherIPAddress = Authorized ? p.Punisher.CurrentAlias.IPAddress.ConvertIPtoString() : null, TimePunished = p.When, AutomatedOffense = Authorized ? p.AutomatedOffense : null, }); penalties = await iqPenalties.ToListAsync(); return(Json(penalties)); }
public async Task <ResourceQueryHelperResult <ConnectionHistoryResponse> > QueryResource( ClientPaginationRequest query) { _logger.LogDebug("{Class} {@Request}", nameof(ConnectionsResourceQueryHelper), query); await using var context = _contextFactory.CreateContext(enableTracking: false); var iqConnections = context.ConnectionHistory.AsNoTracking() .Where(history => query.ClientId == history.ClientId) .Where(history => history.CreatedDateTime < query.Before) .OrderByDescending(history => history.CreatedDateTime); var connections = await iqConnections.Select(history => new ConnectionHistoryResponse { MetaId = history.ClientConnectionId, ClientId = history.ClientId, Type = MetaType.ConnectionHistory, ShouldDisplay = true, When = history.CreatedDateTime, ServerName = history.Server.HostName, ConnectionType = history.ConnectionType }) .ToListAsync(); _logger.LogDebug("{Class} retrieved {Number} items", nameof(ConnectionsResourceQueryHelper), connections.Count); return(new ResourceQueryHelperResult <ConnectionHistoryResponse> { Results = connections }); }
public async Task <ResourceQueryHelperResult <UpdatedAliasResponse> > QueryResource(ClientPaginationRequest query) { await using var ctx = _contextFactory.CreateContext(enableTracking: false); int linkId = ctx.Clients.First(_client => _client.ClientId == query.ClientId).AliasLinkId; var iqAliasUpdates = ctx.Aliases .Where(_alias => _alias.LinkId == linkId) .Where(_alias => _alias.DateAdded < query.Before) .Where(_alias => _alias.IPAddress != null) .OrderByDescending(_alias => _alias.DateAdded) .Select(_alias => new UpdatedAliasResponse { MetaId = _alias.AliasId, Name = _alias.Name, IPAddress = _alias.IPAddress.ConvertIPtoString(), When = _alias.DateAdded, Type = MetaType.AliasUpdate, IsSensitive = true }); var result = (await iqAliasUpdates .Take(query.Count) .ToListAsync()) .Distinct(); return(new ResourceQueryHelperResult <UpdatedAliasResponse> { Results = result, // we can potentially have duplicates RetrievedResultCount = result.Count() }); }
/// <inheritdoc/> public async Task <IList <AuditInfo> > ListAuditInformation(PaginationRequest paginationInfo) { await using var ctx = _contextFactory.CreateContext(enableTracking: false); var iqItems = (from change in ctx.EFChangeHistory where change.TypeOfChange != Data.Models.EFChangeHistory.ChangeType.Ban orderby change.TimeChanged descending join originClient in ctx.Clients on(change.ImpersonationEntityId ?? change.OriginEntityId) equals originClient.ClientId join targetClient in ctx.Clients on change.TargetEntityId equals targetClient.ClientId into targetChange from targetClient in targetChange.DefaultIfEmpty() select new AuditInfo() { Action = change.TypeOfChange.ToString(), OriginName = originClient.CurrentAlias.Name, OriginId = originClient.ClientId, TargetName = targetClient == null ? "" : targetClient.CurrentAlias.Name, TargetId = targetClient == null ? new int?() : targetClient.ClientId, When = change.TimeChanged, Data = change.Comment, OldValue = change.PreviousValue, NewValue = change.CurrentValue }) .Skip(paginationInfo.Offset) .Take(paginationInfo.Count); return(await iqItems.ToListAsync()); }
public static async Task Seed(IDatabaseContextFactory contextFactory, CancellationToken token) { await using var context = contextFactory.CreateContext(); var strategy = context.Database.CreateExecutionStrategy(); await strategy.ExecuteAsync(async() => { await context.Database.MigrateAsync(token); }); if (!await context.AliasLinks.AnyAsync(token)) { var link = new EFAliasLink(); context.Clients.Add(new EFClient() { Active = false, Connections = 0, FirstConnection = DateTime.UtcNow, LastConnection = DateTime.UtcNow, Level = EFClient.Permission.Console, Masked = true, NetworkId = 0, AliasLink = link, CurrentAlias = new EFAlias() { Link = link, Active = true, DateAdded = DateTime.UtcNow, Name = "IW4MAdmin", }, }); await context.SaveChangesAsync(token); } }
public override async Task ExecuteAsync(GameEvent gameEvent) { try { var clientDetection = gameEvent.Target.GetAdditionalProperty <Detection>(IW4MAdmin.Plugins.Stats.Helpers.StatManager .CLIENT_DETECTIONS_KEY); var clientStats = gameEvent.Target.GetAdditionalProperty <EFClientStatistics>(IW4MAdmin.Plugins.Stats.Helpers .StatManager.CLIENT_STATS_KEY); if (clientStats != null) { clientStats.MaxStrain = 0; clientStats.AverageSnapValue = 0; clientStats.SnapHitCount = 0; clientStats.HitLocations.Clear(); } clientDetection?.TrackedHits.Clear(); await using var context = _contextFactory.CreateContext(); var hitLocationCounts = await context.Set <EFHitLocationCount>() .Where(loc => loc.EFClientStatisticsClientId == gameEvent.Target.ClientId) .Select(loc => new EFHitLocationCount() { HitLocationCountId = loc.HitLocationCountId }) .ToListAsync(); context.RemoveRange(hitLocationCounts); await context.SaveChangesAsync(); var stats = await context.Set <EFClientStatistics>() .Where(stat => stat.ClientId == gameEvent.Target.ClientId) .ToListAsync(); foreach (var stat in stats) { stat.MaxStrain = 0; stat.AverageSnapValue = 0; stat.SnapHitCount = 0; } context.UpdateRange(stats); await context.SaveChangesAsync(); gameEvent.Origin.Tell(_translationLookup["PLUGINS_STATS_COMMANDS_RESETAC_SUCCESS"]); } catch (Exception ex) { _logger.LogError(ex, "Could not reset anticheat metrics for {Target}", gameEvent.Target); throw; } }
public static async Task RemoveOldRatings(IDatabaseContextFactory contextFactory, CancellationToken token) { await using var context = contextFactory.CreateContext(); var dbSet = context.Set <EFRating>(); var itemsToDelete = dbSet.Where(rating => rating.When <= CutoffDate); dbSet.RemoveRange(itemsToDelete); await context.SaveChangesAsync(token); }
private async Task <List <EFClientHitStatistic> > GetHitsForClient(int clientId) { try { await using var context = _contextFactory.CreateContext(); var hitLocations = await context.Set <EFClientHitStatistic>() .Where(stat => stat.ClientId == clientId) .ToListAsync(); return(!hitLocations.Any() ? new List <EFClientHitStatistic>() : hitLocations); } catch (Exception ex) { _logger.LogError(ex, "Could not retrieve {hitName} for client with id {id}", nameof(EFClientHitStatistic), clientId); } return(new List <EFClientHitStatistic>()); }
public async Task <T> AddAsync(T item) { await _onOperation.WaitAsync(); T existingItem = null; if (_cachedItems.ContainsKey(item.Id)) { existingItem = _cachedItems[item.Id]; } if (existingItem != null) { _logger.LogDebug("Cached item already added for {type} {id} {value}", typeof(T).Name, item.Id, item.Value); _onOperation.Release(); return(existingItem); } try { _logger.LogDebug("Adding new {type} with {id} {value}", typeof(T).Name, item.Id, item.Value); await using var context = _contextFactory.CreateContext(); context.Set <T>().Add(item); await context.SaveChangesAsync(); _cachedItems.Add(item.Id, item); return(item); } catch (Exception ex) { _logger.LogError(ex, "Could not add item to cache for {type}", typeof(T).Name); throw new Exception("Could not add item to cache"); } finally { if (_onOperation.CurrentCount == 0) { _onOperation.Release(); } } }
private async Task LoadServers() { if (_serverIds.Count == 0) { await using var context = _contextFactory.CreateContext(false); _serverIds.AddRange(await context.Servers .Where(s => s.EndPoint != null && s.HostName != null) .Select(s => s.ServerId) .ToListAsync()); } }
private async Task <int> GetOrCreateMap(string mapName, Reference.Game game, CancellationToken token) { await using var context = _contextFactory.CreateContext(); var existingMap = await context.Maps.FirstOrDefaultAsync(map => map.Name == mapName && map.Game == game, token); if (existingMap != null) { return(existingMap.MapId); } var newMap = new EFMap { Name = mapName, Game = game }; context.Maps.Add(newMap); await context.SaveChangesAsync(token); return(newMap.MapId); }
public virtual async Task <EFPenalty> Create(EFPenalty newEntity) { await using var context = _contextFactory.CreateContext(); var penalty = new EFPenalty() { Active = true, OffenderId = newEntity.Offender.ClientId, PunisherId = newEntity.Punisher.ClientId, LinkId = newEntity.Link.AliasLinkId, Type = newEntity.Type, Expires = newEntity.Expires, Offense = newEntity.Offense, When = DateTime.UtcNow, AutomatedOffense = newEntity.AutomatedOffense ?? newEntity.Punisher.AdministeredPenalties?.FirstOrDefault()?.AutomatedOffense, IsEvadedOffense = newEntity.IsEvadedOffense }; context.Penalties.Add(penalty); await context.SaveChangesAsync(); return(newEntity); }
/// <inheritdoc/> public async Task <ResourceQueryHelperResult <StatsInfoResult> > QueryResource(StatsInfoRequest query) { var result = new ResourceQueryHelperResult <StatsInfoResult>(); using var context = _contextFactory.CreateContext(enableTracking: false); // we need to get the ratings separately because there's not explicit FK var ratings = await context.Set <EFClientRatingHistory>() .Where(_ratingHistory => _ratingHistory.ClientId == query.ClientId) .SelectMany(_ratingHistory => _ratingHistory.Ratings.Where(_rating => _rating.ServerId != null && _rating.Newest) .Select(_rating => new { _rating.ServerId, _rating.Ranking, _rating.When })) .ToListAsync(); var iqStats = context.Set <EFClientStatistics>() .Where(_stats => _stats.ClientId == query.ClientId) .Select(_stats => new StatsInfoResult { Name = _stats.Client.CurrentAlias.Name, ServerId = _stats.ServerId, Kills = _stats.Kills, Deaths = _stats.Deaths, Performance = Math.Round((_stats.EloRating + _stats.Skill) / 2.0, 2), ScorePerMinute = _stats.SPM, LastPlayed = _stats.Client.LastConnection, TotalSecondsPlayed = _stats.TimePlayed, ServerGame = _stats.Server.GameName.ToString(), ServerName = _stats.Server.HostName, }); var queryResults = await iqStats.ToListAsync(); // add the rating query's results to the full query foreach (var eachResult in queryResults) { var rating = ratings.FirstOrDefault(_rating => _rating.ServerId == eachResult.ServerId); eachResult.Ranking = rating?.Ranking ?? 0; eachResult.LastPlayed = rating?.When ?? eachResult.LastPlayed; } result.Results = queryResults; result.RetrievedResultCount = queryResults.Count; result.TotalResultCount = result.RetrievedResultCount; return(result); }
public async Task Test_StatsQueryHelper_Get() { var queryHelper = serviceProvider.GetRequiredService <StatsResourceQueryHelper>(); await using var context = contextFactory.CreateContext(); var server = new EFServer() { ServerId = 1 }; var stats = new EFClientStatistics() { Client = ClientGenerators.CreateBasicClient(null), SPM = 100, Server = server }; var ratingHistory = new EFClientRatingHistory() { Client = stats.Client, Ratings = new[] { new EFRating() { Ranking = 100, Server = server, Newest = true } } }; context.Set <EFClientStatistics>().Add(stats); context.Set <EFClientRatingHistory>().Add(ratingHistory); await context.SaveChangesAsync(); var query = new StatsInfoRequest() { ClientId = stats.Client.ClientId }; var result = await queryHelper.QueryResource(query); Assert.IsNotEmpty(result.Results); Assert.AreEqual(stats.SPM, result.Results.First().ScorePerMinute); Assert.AreEqual(ratingHistory.Ratings.First().Ranking, result.Results.First().Ranking); context.Set <EFClientStatistics>().Remove(stats); context.Set <EFClientRatingHistory>().Remove(ratingHistory); context.Set <EFServer>().Remove(server); await context.SaveChangesAsync(); }
public async Task Test_QueryClientResource_Xuid() { var client = ClientGenerators.CreateBasicClient(null); client.NetworkId = -1; var query = new FindClientRequest() { Xuid = client.NetworkId.ToString("X") }; using var context = contextFactory.CreateContext(); context.Clients.Add(client); await context.SaveChangesAsync(); var result = await clientService.QueryResource(query); Assert.IsNotEmpty(result.Results); Assert.AreEqual(query.Xuid, result.Results.First().Xuid); context.Clients.Remove(client); await context.SaveChangesAsync(); }
public async Task <IActionResult> GetAutomatedPenaltyInfoAsync(int penaltyId) { await using var context = _contextFactory.CreateContext(false); var penalty = await context.Penalties .Select(_penalty => new { _penalty.OffenderId, _penalty.PenaltyId, _penalty.When, _penalty.AutomatedOffense }) .FirstOrDefaultAsync(_penalty => _penalty.PenaltyId == penaltyId); if (penalty == null) { return(NotFound()); } // todo: this can be optimized var iqSnapshotInfo = context.ACSnapshots .Where(s => s.ClientId == penalty.OffenderId) .Include(s => s.LastStrainAngle) .Include(s => s.HitOrigin) .Include(s => s.HitDestination) .Include(s => s.CurrentViewAngle) .Include(s => s.Server) .Include(s => s.PredictedViewAngles) .ThenInclude(_angles => _angles.Vector) .OrderBy(s => s.When) .ThenBy(s => s.Hits); var penaltyInfo = await iqSnapshotInfo.ToListAsync(); if (penaltyInfo.Count > 0) { return(View("~/Views/Client/_PenaltyInfo.cshtml", penaltyInfo)); } // we want to show anything related to the automated offense else { return(View("~/Views/Client/_MessageContext.cshtml", new List <MessageResponse> { new MessageResponse() { ClientId = penalty.OffenderId, Message = penalty.AutomatedOffense, When = penalty.When } })); } }
public override async Task ExecuteAsync(GameEvent gameEvent) { try { await using var context = _contextFactory.CreateContext(); var inboxItems = await context.InboxMessages .Include(message => message.SourceClient) .ThenInclude(client => client.CurrentAlias) .Where(message => message.DestinationClientId == gameEvent.Origin.ClientId) .Where(message => !message.IsDelivered) .ToListAsync(); if (!inboxItems.Any()) { gameEvent.Origin.Tell(_translationLookup["COMMANDS_READ_MESSAGE_NONE"]); return; } var index = 1; foreach (var inboxItem in inboxItems) { await gameEvent.Origin.Tell(_translationLookup["COMMANDS_READ_MESSAGE_SUCCESS"] .FormatExt($"{index}/{inboxItems.Count}", inboxItem.SourceClient.CurrentAlias.Name)) .WaitAsync(); foreach (var messageFragment in inboxItem.Message.FragmentMessageForDisplay()) { await gameEvent.Origin.Tell(messageFragment).WaitAsync(); } index++; } inboxItems.ForEach(item => { item.IsDelivered = true; }); context.UpdateRange(inboxItems); await context.SaveChangesAsync(); } catch (Exception ex) { logger.LogError(ex, "Could not retrieve offline messages for {Client}", gameEvent.Origin.ToString()); throw; } }
private async Task RunCacheUpdate(CacheState <TReturnType> state, CancellationToken token) { try { _logger.LogDebug("Running update for {ClassName} {@State}", GetType().Name, state); await using var context = _contextFactory.CreateContext(false); var set = context.Set <TEntityType>(); var value = await state.Getter(set, token); state.Value = value; state.IsSet = true; state.LastRetrieval = DateTime.Now; } catch (Exception ex) { _logger.LogError(ex, "Could not get cached value for {Key}", state.Key); } }
public override async Task ExecuteAsync(GameEvent gameEvent) { if (gameEvent.Data.Length > MaxLength) { gameEvent.Origin.Tell(_translationLookup["COMMANDS_OFFLINE_MESSAGE_TOO_LONG"].FormatExt(MaxLength)); return; } if (gameEvent.Target.ClientId == gameEvent.Origin.ClientId) { gameEvent.Origin.Tell(_translationLookup["COMMANDS_OFFLINE_MESSAGE_SELF"].FormatExt(MaxLength)); return; } if (gameEvent.Target.IsIngame) { gameEvent.Origin.Tell(_translationLookup["COMMANDS_OFFLINE_MESSAGE_INGAME"].FormatExt(gameEvent.Target.Name)); return; } await using var context = _contextFactory.CreateContext(enableTracking: false); var server = await context.Servers.FirstAsync(srv => srv.EndPoint == gameEvent.Owner.ToString()); var newMessage = new EFInboxMessage() { SourceClientId = gameEvent.Origin.ClientId, DestinationClientId = gameEvent.Target.ClientId, ServerId = server.Id, Message = gameEvent.Data, }; try { context.Set <EFInboxMessage>().Add(newMessage); await context.SaveChangesAsync(); gameEvent.Origin.Tell(_translationLookup["COMMANDS_OFFLINE_MESSAGE_SUCCESS"]); } catch (Exception ex) { _logger.LogError(ex, "Could not save offline message {@Message}", newMessage); throw; } }
public async Task <ResourceQueryHelperResult <ReceivedPenaltyResponse> > QueryResource(ClientPaginationRequest query) { var linkedPenaltyType = Utilities.LinkedPenaltyTypes(); using var ctx = _contextFactory.CreateContext(enableTracking: false); var linkId = await ctx.Clients.AsNoTracking() .Where(_client => _client.ClientId == query.ClientId) .Select(_client => _client.AliasLinkId) .FirstOrDefaultAsync(); var iqPenalties = ctx.Penalties.AsNoTracking() .Where(_penalty => _penalty.OffenderId == query.ClientId || (linkedPenaltyType.Contains(_penalty.Type) && _penalty.LinkId == linkId)) .Where(_penalty => _penalty.When < query.Before) .OrderByDescending(_penalty => _penalty.When); var penalties = await iqPenalties .Take(query.Count) .Select(_penalty => new ReceivedPenaltyResponse() { PenaltyId = _penalty.PenaltyId, ClientId = query.ClientId, Offense = _penalty.Offense, AutomatedOffense = _penalty.AutomatedOffense, OffenderClientId = _penalty.OffenderId, OffenderName = _penalty.Offender.CurrentAlias.Name, PunisherClientId = _penalty.PunisherId, PunisherName = _penalty.Punisher.CurrentAlias.Name, PenaltyType = _penalty.Type, When = _penalty.When, ExpirationDate = _penalty.Expires, IsLinked = _penalty.OffenderId != query.ClientId, IsSensitive = _penalty.Type == EFPenalty.PenaltyType.Flag }) .ToListAsync(); return(new ResourceQueryHelperResult <ReceivedPenaltyResponse> { // todo: maybe actually count RetrievedResultCount = penalties.Count, Results = penalties }); }
public async Task OnEventAsync(GameEvent gameEvent, Server server) { if (gameEvent.Type == GameEvent.EventType.Join) { var newPlayer = gameEvent.Origin; if (newPlayer.Level >= Permission.Trusted && !gameEvent.Origin.Masked || !string.IsNullOrEmpty(newPlayer.GetAdditionalProperty <string>("ClientTag")) && newPlayer.Level != Permission.Flagged && newPlayer.Level != Permission.Banned && !newPlayer.Masked) { gameEvent.Owner.Broadcast( await ProcessAnnouncement(_configHandler.Configuration().PrivilegedAnnouncementMessage, newPlayer)); } newPlayer.Tell(await ProcessAnnouncement(_configHandler.Configuration().UserWelcomeMessage, newPlayer)); if (newPlayer.Level == Permission.Flagged) { string penaltyReason; await using var context = _contextFactory.CreateContext(false); { penaltyReason = await context.Penalties .Where(p => p.OffenderId == newPlayer.ClientId && p.Type == EFPenalty.PenaltyType.Flag) .OrderByDescending(p => p.When) .Select(p => p.AutomatedOffense ?? p.Offense) .FirstOrDefaultAsync(); } gameEvent.Owner.ToAdmins(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_WELCOME_FLAG_MESSAGE"] .FormatExt(newPlayer.Name, penaltyReason)); } else { gameEvent.Owner.Broadcast(await ProcessAnnouncement(_configHandler.Configuration().UserAnnouncementMessage, newPlayer)); } } }
public override async Task ExecuteAsync(GameEvent E) { int inactiveDays = 30; try { if (E.Data.Length > 0) { inactiveDays = int.Parse(E.Data); if (inactiveDays < 1) { throw new FormatException(); } } } catch (FormatException) { E.Origin.Tell(_translationLookup["COMMANDS_PRUNE_FAIL"]); return; } List <EFClient> inactiveUsers = null; // todo: make an event for this // update user roles await using var context = _contextFactory.CreateContext(); var lastActive = DateTime.UtcNow.AddDays(-inactiveDays); inactiveUsers = await context.Clients .Where(c => c.Level > Permission.Flagged && c.Level <= Permission.Moderator) .Where(c => c.LastConnection < lastActive) .Select(c => c.ToPartialClient()) .ToListAsync(); inactiveUsers.ForEach(c => c.SetLevel(Permission.User, E.Origin)); await context.SaveChangesAsync(); E.Origin.Tell(_translationLookup["COMMANDS_PRUNE_SUCCESS"].FormatExt(inactiveUsers.Count)); }
public static async Task <List <string> > GetMostPlayed(Server s, ITranslationLookup translationLookup, IDatabaseContextFactory contextFactory) { var serverId = StatManager.GetIdForServer(s); var mostPlayed = new List <string> { $"(Color::Accent)--{translationLookup["PLUGINS_STATS_COMMANDS_MOSTPLAYED_TEXT"]}--" }; await using var context = contextFactory.CreateContext(false); var thirtyDaysAgo = DateTime.UtcNow.AddMonths(-1); var iqStats = (from stats in context.Set <EFClientStatistics>() join client in context.Clients on stats.ClientId equals client.ClientId join alias in context.Aliases on client.CurrentAliasId equals alias.AliasId where stats.ServerId == serverId where client.Level != EFClient.Permission.Banned where client.LastConnection >= thirtyDaysAgo orderby stats.TimePlayed descending select new { alias.Name, stats.TimePlayed, stats.Kills }) .Take(5); var iqList = await iqStats.ToListAsync(); mostPlayed.AddRange(iqList.Select((stats, index) => $"#{index + 1} " + translationLookup["COMMANDS_MOST_PLAYED_FORMAT_V2"].FormatExt(stats.Name, stats.Kills, (DateTime.UtcNow - DateTime.UtcNow.AddSeconds(-stats.TimePlayed)) .HumanizeForCurrentCulture()))); return(mostPlayed); }
public override async Task ExecuteAsync(GameEvent gameEvent) { if (gameEvent.Origin.ClientNumber >= 0) { var serverId = Helpers.StatManager.GetIdForServer(gameEvent.Owner); await using var context = _contextFactory.CreateContext(); var clientStats = await context.Set <EFClientStatistics>() .Where(s => s.ClientId == gameEvent.Origin.ClientId) .Where(s => s.ServerId == serverId) .FirstOrDefaultAsync(); // want to prevent resetting stats before they've gotten any kills if (clientStats != null) { clientStats.Deaths = 0; clientStats.Kills = 0; clientStats.SPM = 0.0; clientStats.Skill = 0.0; clientStats.TimePlayed = 0; // todo: make this more dynamic clientStats.EloRating = 200.0; await context.SaveChangesAsync(); } // reset the cached version Plugin.Manager.ResetStats(gameEvent.Origin); gameEvent.Origin.Tell(_translationLookup["PLUGINS_STATS_COMMANDS_RESET_SUCCESS"]); } else { gameEvent.Origin.Tell(_translationLookup["PLUGINS_STATS_COMMANDS_RESET_FAIL"]); } }
public async Task <ResourceQueryHelperResult <AdministeredPenaltyResponse> > QueryResource(ClientPaginationRequest query) { using var ctx = _contextFactory.CreateContext(enableTracking: false); var iqPenalties = ctx.Penalties.AsNoTracking() .Where(_penalty => query.ClientId == _penalty.PunisherId) .Where(_penalty => _penalty.When < query.Before) .OrderByDescending(_penalty => _penalty.When); var penalties = await iqPenalties .Take(query.Count) .Select(_penalty => new AdministeredPenaltyResponse() { PenaltyId = _penalty.PenaltyId, Offense = _penalty.Offense, AutomatedOffense = _penalty.AutomatedOffense, ClientId = _penalty.OffenderId, OffenderName = _penalty.Offender.CurrentAlias.Name, OffenderClientId = _penalty.Offender.ClientId, PunisherClientId = _penalty.PunisherId, PunisherName = _penalty.Punisher.CurrentAlias.Name, PenaltyType = _penalty.Type, When = _penalty.When, ExpirationDate = _penalty.Expires, IsLinked = _penalty.OffenderId != query.ClientId, IsSensitive = _penalty.Type == EFPenalty.PenaltyType.Flag }) .ToListAsync(); return(new ResourceQueryHelperResult <AdministeredPenaltyResponse> { // todo: might need to do count at some point RetrievedResultCount = penalties.Count, Results = penalties }); }
public async Task <ResourceQueryHelperResult <AdvancedStatsInfo> > QueryResource(StatsInfoRequest query) { await using var context = _contextFactory.CreateContext(enableTracking: false); long?serverId = null; if (!string.IsNullOrEmpty(query.ServerEndpoint)) { serverId = (await context.Servers .Select(server => new { server.EndPoint, server.Id }) .FirstOrDefaultAsync(server => server.EndPoint == query.ServerEndpoint)) ?.Id; } var clientInfo = await context.Clients.Select(client => new { client.ClientId, client.CurrentAlias.Name, client.Level }).FirstOrDefaultAsync(client => client.ClientId == query.ClientId); if (clientInfo == null) { return(null); } // gets all the hit stats for the client var hitStats = await context.Set <EFClientHitStatistic>() .Include(stat => stat.HitLocation) .Include(stat => stat.MeansOfDeath) .Include(stat => stat.Weapon) .Include(stat => stat.WeaponAttachmentCombo) .ThenInclude(attachment => attachment.Attachment1) .Include(stat => stat.WeaponAttachmentCombo) .ThenInclude(attachment => attachment.Attachment2) .Include(stat => stat.WeaponAttachmentCombo) .ThenInclude(attachment => attachment.Attachment3) .Where(stat => stat.ClientId == query.ClientId) .Where(stat => stat.ServerId == serverId) .ToListAsync(); var ratings = await context.Set <EFClientRankingHistory>() .Where(r => r.ClientId == clientInfo.ClientId) .Where(r => r.ServerId == serverId) .Where(r => r.Ranking != null) .OrderByDescending(r => r.UpdatedDateTime) .ToListAsync(); var mostRecentRanking = ratings.FirstOrDefault(ranking => ranking.Newest); var ranking = mostRecentRanking?.Ranking + 1; // get stat for server, or all if no serverId var legacyStats = await context.Set <EFClientStatistics>() .Where(stat => stat.ClientId == query.ClientId) .Where(stat => serverId == null || stat.ServerId == serverId) .ToListAsync(); if (mostRecentRanking != null && mostRecentRanking.CreatedDateTime < Extensions.FifteenDaysAgo()) { ranking = 0; } if (clientInfo.Level == EFClient.Permission.Banned) { ranking = null; } var hitInfo = new AdvancedStatsInfo() { ServerId = serverId, Performance = mostRecentRanking?.PerformanceMetric, ZScore = mostRecentRanking?.ZScore, ServerEndpoint = query.ServerEndpoint, ClientName = clientInfo.Name, ClientId = clientInfo.ClientId, Level = clientInfo.Level, Rating = mostRecentRanking?.PerformanceMetric, All = hitStats, Servers = _manager.GetServers() .Select(server => new ServerInfo() { Name = server.Hostname, IPAddress = server.IP, Port = server.Port }) .ToList(), Aggregate = hitStats.FirstOrDefault(hit => hit.HitLocationId == null && hit.ServerId == serverId && hit.WeaponId == null && hit.MeansOfDeathId == null), ByHitLocation = hitStats .Where(hit => hit.HitLocationId != null) .Where(hit => hit.WeaponId == null) .Where(hit => hit.WeaponAttachmentComboId == null) .ToList(), ByWeapon = hitStats .Where(hit => hit.HitLocationId == null) .Where(hit => hit.WeaponId != null) .ToList(), ByAttachmentCombo = hitStats .Where(hit => hit.HitLocationId == null) .Where(hit => hit.WeaponId != null) .Where(hit => hit.WeaponAttachmentComboId != null) .ToList(), Ratings = ratings, LegacyStats = legacyStats, Ranking = ranking, }; // todo: when nothign found return(new ResourceQueryHelperResult <AdvancedStatsInfo>() { Results = new[] { hitInfo } }); }
public async Task Add(GameEvent e) { EFChangeHistory change = null; switch (e.Type) { case GameEvent.EventType.Ban: change = new EFChangeHistory() { OriginEntityId = e.Origin.ClientId, TargetEntityId = e.Target.ClientId, ImpersonationEntityId = e.ImpersonationOrigin?.ClientId, TypeOfChange = EFChangeHistory.ChangeType.Ban, Comment = e.Data }; break; case GameEvent.EventType.Command: // this prevents passwords/tokens being logged into the database in plain text if (e.Extra is Command cmd) { if (cmd.Name == "login" || cmd.Name == "setpassword") { e.Message = string.Join(' ', e.Message.Split(" ").Select((arg, index) => index > 0 ? "*****" : arg)); } } change = new EFChangeHistory() { OriginEntityId = e.Origin.ClientId, TargetEntityId = e.Target?.ClientId ?? 0, ImpersonationEntityId = e.ImpersonationOrigin?.ClientId, Comment = "Executed command", CurrentValue = e.Message, TypeOfChange = EFChangeHistory.ChangeType.Command }; break; case GameEvent.EventType.ChangePermission: change = new EFChangeHistory() { OriginEntityId = e.Origin.ClientId, TargetEntityId = e.Target.ClientId, ImpersonationEntityId = e.ImpersonationOrigin?.ClientId, Comment = "Changed permission level", TypeOfChange = EFChangeHistory.ChangeType.Permission, CurrentValue = ((EFClient.Permission)e.Extra).ToString() }; break; case GameEvent.EventType.Login: change = new EFChangeHistory() { OriginEntityId = e.Origin.ClientId, Comment = "Logged In To Webfront", TypeOfChange = EFChangeHistory.ChangeType.Command, CurrentValue = e.Data }; break; case GameEvent.EventType.Logout: change = new EFChangeHistory() { OriginEntityId = e.Origin.ClientId, Comment = "Logged Out of Webfront", TypeOfChange = EFChangeHistory.ChangeType.Command, CurrentValue = e.Data }; break; } if (change == null) { return; } await using var context = _contextFactory.CreateContext(false); context.EFChangeHistory.Add(change); try { await context.SaveChangesAsync(); } catch (Exception ex) { _logger.LogError(ex, "Could not persist change @{change}", change); } }
/// <inheritdoc/> public async Task <ResourceQueryHelperResult <MessageResponse> > QueryResource(ChatSearchQuery query) { if (query == null) { throw new ArgumentException("Query must be specified"); } var result = new ResourceQueryHelperResult <MessageResponse>(); await using var context = _contextFactory.CreateContext(enableTracking: false); if (serverCache == null) { serverCache = await context.Set <EFServer>().ToListAsync(); } if (int.TryParse(query.ServerId, out int serverId)) { query.ServerId = serverCache.FirstOrDefault(_server => _server.ServerId == serverId)?.EndPoint ?? query.ServerId; } var iqMessages = context.Set <EFClientMessage>() .Where(_message => _message.TimeSent >= query.SentAfter) .Where(_message => _message.TimeSent < query.SentBefore); if (query.ClientId != null) { iqMessages = iqMessages.Where(_message => _message.ClientId == query.ClientId.Value); } if (query.ServerId != null) { iqMessages = iqMessages.Where(_message => _message.Server.EndPoint == query.ServerId); } if (!string.IsNullOrEmpty(query.MessageContains)) { iqMessages = iqMessages.Where(_message => EF.Functions.Like(_message.Message.ToLower(), $"%{query.MessageContains.ToLower()}%")); } var iqResponse = iqMessages .Select(_message => new MessageResponse { ClientId = _message.ClientId, ClientName = query.IsProfileMeta ? "" : _message.Client.CurrentAlias.Name, ServerId = _message.ServerId, When = _message.TimeSent, Message = _message.Message, ServerName = query.IsProfileMeta ? "" : _message.Server.HostName, GameName = _message.Server.GameName == null ? Server.Game.IW4 : (Server.Game)_message.Server.GameName.Value, SentIngame = _message.SentIngame }); if (query.Direction == SharedLibraryCore.Dtos.SortDirection.Descending) { iqResponse = iqResponse.OrderByDescending(_message => _message.When); } else { iqResponse = iqResponse.OrderBy(_message => _message.When); } var resultList = await iqResponse .Skip(query.Offset) .Take(query.Count) .ToListAsync(); foreach (var message in resultList) { message.IsHidden = serverCache.Any(server => server.ServerId == message.ServerId && server.IsPasswordProtected); if (!message.Message.IsQuickMessage()) { continue; } try { var quickMessages = _defaultSettings .QuickMessages .First(_qm => _qm.Game == message.GameName); message.Message = quickMessages.Messages[message.Message.Substring(1)]; message.IsQuickMessage = true; } catch { message.Message = message.Message.Substring(1); } } result.TotalResultCount = await iqResponse.CountAsync(); result.Results = resultList; result.RetrievedResultCount = resultList.Count; return(result); }