コード例 #1
0
        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();
        }
コード例 #2
0
        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"]));
            }
        }
コード例 #3
0
        /// <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));
        }
コード例 #4
0
        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
            });
        }
コード例 #5
0
        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()
            });
        }
コード例 #6
0
        /// <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());
        }
コード例 #7
0
        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);
            }
        }
コード例 #8
0
        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;
            }
        }
コード例 #9
0
        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);
        }
コード例 #10
0
ファイル: HitCalculator.cs プロジェクト: xerxes-at/IW4M-Admin
        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>());
        }
コード例 #11
0
        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();
                }
            }
        }
コード例 #12
0
 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());
     }
 }
コード例 #13
0
        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);
        }
コード例 #14
0
        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);
        }
コード例 #15
0
        /// <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);
        }
コード例 #16
0
ファイル: StatsTests.cs プロジェクト: xerxes-at/IW4M-Admin
        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();
        }
コード例 #17
0
        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();
        }
コード例 #18
0
        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
                    }
                }));
            }
        }
コード例 #19
0
        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;
            }
        }
コード例 #20
0
        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);
            }
        }
コード例 #21
0
        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;
            }
        }
コード例 #22
0
        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
            });
        }
コード例 #23
0
        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));
                }
            }
        }
コード例 #24
0
        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));
        }
コード例 #25
0
        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);
        }
コード例 #26
0
        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"]);
            }
        }
コード例 #27
0
        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
            });
        }
コード例 #28
0
        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 }
            });
        }
コード例 #29
0
        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);
            }
        }
コード例 #30
0
        /// <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);
        }