From c783a04a52651db008ccc595c7891a2594a7e273 Mon Sep 17 00:00:00 2001 From: RaidMax Date: Thu, 20 Aug 2020 10:38:11 -0500 Subject: [PATCH] hide chat for password protected servers for issue #162 --- Application/IW4MServer.cs | 10 +- Application/Main.cs | 4 +- .../AutomessageFeed/AutomessageFeed.csproj | 2 +- .../IW4ScriptCommands.csproj | 2 +- Plugins/LiveRadar/LiveRadar.csproj | 2 +- Plugins/Login/Login.csproj | 2 +- .../ProfanityDeterment.csproj | 2 +- .../Dtos/ChatSearchQuery.cs | 10 +- Plugins/Stats/Helpers/StatManager.cs | 4 + Plugins/Stats/Models/EFServer.cs | 1 + Plugins/Stats/Plugin.cs | 54 +- Plugins/Stats/Stats.csproj | 2 +- .../Web/StatsWeb/ChatResourceQueryHelper.cs | 68 +- .../StatsWeb/Controllers/StatsController.cs | 52 +- Plugins/Web/StatsWeb/Dtos/ChatSearchResult.cs | 32 - .../Extensions/SearchQueryExtensions.cs | 2 +- Plugins/Web/StatsWeb/StatsWeb.csproj | 2 +- .../StatsWeb/Views/Stats/Message/Find.cshtml | 3 +- .../StatsWeb/Views/Stats/Message/_Item.cshtml | 25 +- .../Views/Stats/_MessageContext.cshtml | 9 +- Plugins/Welcome/Welcome.csproj | 2 +- SharedLibraryCore/Dtos/ChatInfo.cs | 3 + .../Dtos/Meta/Responses/MessageResponse.cs | 27 +- SharedLibraryCore/Dtos/ServerInfo.cs | 1 + ...9_AddIsPasswordProtectedColumn.Designer.cs | 925 ++++++++++++++++++ ...0819224119_AddIsPasswordProtectedColumn.cs | 35 + .../DatabaseContextModelSnapshot.cs | 5 +- SharedLibraryCore/Server.cs | 1 + SharedLibraryCore/SharedLibraryCore.csproj | 6 +- SharedLibraryCore/Utilities.cs | 6 +- Tests/ApplicationTests/ApiTests.cs | 1 - .../Fixtures/ConfigurationGenerators.cs | 2 +- .../Fixtures/MessageGenerators.cs | 2 +- Tests/ApplicationTests/StatsWebTests.cs | 12 +- WebfrontCore/Controllers/ServerController.cs | 3 +- WebfrontCore/Startup.cs | 14 +- .../Profile/Meta/_MessageResponse.cshtml | 16 +- .../Views/Server/_ClientActivity.cshtml | 8 +- WebfrontCore/wwwroot/js/loader.js | 2 +- 39 files changed, 1171 insertions(+), 188 deletions(-) rename Plugins/{Web/StatsWeb => Stats}/Dtos/ChatSearchQuery.cs (80%) delete mode 100644 Plugins/Web/StatsWeb/Dtos/ChatSearchResult.cs create mode 100644 SharedLibraryCore/Migrations/20200819224119_AddIsPasswordProtectedColumn.Designer.cs create mode 100644 SharedLibraryCore/Migrations/20200819224119_AddIsPasswordProtectedColumn.cs diff --git a/Application/IW4MServer.cs b/Application/IW4MServer.cs index 4e80917c0..0fdc6d8b8 100644 --- a/Application/IW4MServer.cs +++ b/Application/IW4MServer.cs @@ -541,14 +541,18 @@ namespace IW4MAdmin .First(_qm => _qm.Game == GameName) .Messages[E.Data.Substring(1)]; } - catch { } + catch + { + message = E.Data.Substring(1); + } } ChatHistory.Add(new ChatInfo() { Name = E.Origin.Name, Message = message, - Time = DateTime.UtcNow + Time = DateTime.UtcNow, + IsHidden = !string.IsNullOrEmpty(GamePassword) }); } } @@ -982,6 +986,7 @@ namespace IW4MAdmin var logfile = await this.GetMappedDvarValueOrDefaultAsync("g_log"); var logsync = await this.GetMappedDvarValueOrDefaultAsync("g_logsync"); var ip = await this.GetMappedDvarValueOrDefaultAsync("net_ip"); + var gamePassword = await this.GetMappedDvarValueOrDefaultAsync("g_password", overrideDefault: ""); if (Manager.GetApplicationSettings().Configuration().EnableCustomSayName) { @@ -1015,6 +1020,7 @@ namespace IW4MAdmin this.FSGame = game.Value; this.Gametype = gametype; this.IP = ip.Value == "localhost" ? ServerConfig.IPAddress : ip.Value ?? ServerConfig.IPAddress; + this.GamePassword = gamePassword.Value; UpdateMap(mapname); if (RconParser.CanGenerateLogPath) diff --git a/Application/Main.cs b/Application/Main.cs index 9959440a2..cce9f2f0e 100644 --- a/Application/Main.cs +++ b/Application/Main.cs @@ -10,7 +10,6 @@ using RestEase; using SharedLibraryCore; using SharedLibraryCore.Configuration; using SharedLibraryCore.Database.Models; -using SharedLibraryCore.Dtos.Meta.Requests; using SharedLibraryCore.Dtos.Meta.Responses; using SharedLibraryCore.Exceptions; using SharedLibraryCore.Helpers; @@ -18,6 +17,8 @@ using SharedLibraryCore.Interfaces; using SharedLibraryCore.QueryHelper; using SharedLibraryCore.Repositories; using SharedLibraryCore.Services; +using Stats.Dtos; +using StatsWeb; using System; using System.Linq; using System.Text; @@ -251,6 +252,7 @@ namespace IW4MAdmin.Application .AddSingleton, ReceivedPenaltyResourceQueryHelper>() .AddSingleton, AdministeredPenaltyResourceQueryHelper>() .AddSingleton, UpdatedAliasResourceQueryHelper>() + .AddSingleton, ChatResourceQueryHelper>() .AddTransient() .AddSingleton(_serviceProvider => { diff --git a/Plugins/AutomessageFeed/AutomessageFeed.csproj b/Plugins/AutomessageFeed/AutomessageFeed.csproj index c38a710ac..2a894b5ca 100644 --- a/Plugins/AutomessageFeed/AutomessageFeed.csproj +++ b/Plugins/AutomessageFeed/AutomessageFeed.csproj @@ -10,7 +10,7 @@ - + diff --git a/Plugins/IW4ScriptCommands/IW4ScriptCommands.csproj b/Plugins/IW4ScriptCommands/IW4ScriptCommands.csproj index 4e3575ee1..8c371e527 100644 --- a/Plugins/IW4ScriptCommands/IW4ScriptCommands.csproj +++ b/Plugins/IW4ScriptCommands/IW4ScriptCommands.csproj @@ -10,7 +10,7 @@ - + diff --git a/Plugins/LiveRadar/LiveRadar.csproj b/Plugins/LiveRadar/LiveRadar.csproj index d4537b118..efd9d1d91 100644 --- a/Plugins/LiveRadar/LiveRadar.csproj +++ b/Plugins/LiveRadar/LiveRadar.csproj @@ -16,7 +16,7 @@ - + diff --git a/Plugins/Login/Login.csproj b/Plugins/Login/Login.csproj index 4c98542f8..c43bfe7df 100644 --- a/Plugins/Login/Login.csproj +++ b/Plugins/Login/Login.csproj @@ -23,7 +23,7 @@ - + diff --git a/Plugins/ProfanityDeterment/ProfanityDeterment.csproj b/Plugins/ProfanityDeterment/ProfanityDeterment.csproj index 28fd3c064..3b98cd452 100644 --- a/Plugins/ProfanityDeterment/ProfanityDeterment.csproj +++ b/Plugins/ProfanityDeterment/ProfanityDeterment.csproj @@ -16,7 +16,7 @@ - + diff --git a/Plugins/Web/StatsWeb/Dtos/ChatSearchQuery.cs b/Plugins/Stats/Dtos/ChatSearchQuery.cs similarity index 80% rename from Plugins/Web/StatsWeb/Dtos/ChatSearchQuery.cs rename to Plugins/Stats/Dtos/ChatSearchQuery.cs index fe4cc318b..302f55770 100644 --- a/Plugins/Web/StatsWeb/Dtos/ChatSearchQuery.cs +++ b/Plugins/Stats/Dtos/ChatSearchQuery.cs @@ -1,8 +1,7 @@ -using SharedLibraryCore.Dtos; -using SharedLibraryCore.QueryHelper; +using SharedLibraryCore.QueryHelper; using System; -namespace StatsWeb.Dtos +namespace Stats.Dtos { public class ChatSearchQuery : ClientPaginationRequest { @@ -30,5 +29,10 @@ namespace StatsWeb.Dtos /// only look for messages sent before this date0 /// public DateTime SentBefore { get; set; } = DateTime.UtcNow; + + /// + /// indicates if the chat is on the meta page + /// + public bool IsProfileMeta { get; set; } } } diff --git a/Plugins/Stats/Helpers/StatManager.cs b/Plugins/Stats/Helpers/StatManager.cs index 6ca7295c1..da9b91c38 100644 --- a/Plugins/Stats/Helpers/StatManager.cs +++ b/Plugins/Stats/Helpers/StatManager.cs @@ -248,6 +248,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers ctx.Entry(server).Property(_prop => _prop.HostName).IsModified = true; ctx.SaveChanges(); } + + ctx.Entry(server).Property(_prop => _prop.IsPasswordProtected).IsModified = true; + server.IsPasswordProtected = !string.IsNullOrEmpty(sv.GamePassword); + ctx.SaveChanges(); } // check to see if the stats have ever been initialized diff --git a/Plugins/Stats/Models/EFServer.cs b/Plugins/Stats/Models/EFServer.cs index 62f0fc140..c547278d1 100644 --- a/Plugins/Stats/Models/EFServer.cs +++ b/Plugins/Stats/Models/EFServer.cs @@ -16,5 +16,6 @@ namespace IW4MAdmin.Plugins.Stats.Models public string EndPoint { get; set; } public Game? GameName { get; set; } public string HostName { get; set; } + public bool IsPasswordProtected { get; set; } } } diff --git a/Plugins/Stats/Plugin.cs b/Plugins/Stats/Plugin.cs index fc2edc35a..e4a9d2028 100644 --- a/Plugins/Stats/Plugin.cs +++ b/Plugins/Stats/Plugin.cs @@ -5,12 +5,11 @@ using Microsoft.EntityFrameworkCore; using SharedLibraryCore; using SharedLibraryCore.Database; using SharedLibraryCore.Database.Models; -using SharedLibraryCore.Dtos; using SharedLibraryCore.Dtos.Meta.Responses; using SharedLibraryCore.Helpers; using SharedLibraryCore.Interfaces; using SharedLibraryCore.QueryHelper; -using SharedLibraryCore.Services; +using Stats.Dtos; using System; using System.Collections.Generic; using System.Linq; @@ -36,14 +35,16 @@ namespace IW4MAdmin.Plugins.Stats private readonly IDatabaseContextFactory _databaseContextFactory; private readonly ITranslationLookup _translationLookup; private readonly IMetaService _metaService; + private readonly IResourceQueryHelper _chatQueryHelper; public Plugin(IConfigurationHandlerFactory configurationHandlerFactory, IDatabaseContextFactory databaseContextFactory, - ITranslationLookup translationLookup, IMetaService metaService) + ITranslationLookup translationLookup, IMetaService metaService, IResourceQueryHelper chatQueryHelper) { Config = configurationHandlerFactory.GetConfigurationHandler("StatsPluginSettings"); _databaseContextFactory = databaseContextFactory; _translationLookup = translationLookup; _metaService = metaService; + _chatQueryHelper = chatQueryHelper; } public async Task OnEventAsync(GameEvent E, Server S) @@ -199,7 +200,7 @@ namespace IW4MAdmin.Plugins.Stats using (var ctx = _databaseContextFactory.CreateContext(enableTracking: false)) { clientStats = await ctx.Set().Where(c => c.ClientId == request.ClientId).ToListAsync(); - messageCount = await ctx.Set().CountAsync(_message => _message.ClientId == request.ClientId); + messageCount = await ctx.Set().CountAsync(_message => _message.ClientId == request.ClientId); } int kills = clientStats.Sum(c => c.Kills); @@ -392,45 +393,16 @@ namespace IW4MAdmin.Plugins.Stats async Task> getMessages(ClientPaginationRequest request) { - List messageMeta; - using (var ctx = _databaseContextFactory.CreateContext(enableTracking: false)) + var query = new ChatSearchQuery() { - var messages = ctx.Set() - .Where(m => m.ClientId == request.ClientId) - .Where(_message => _message.TimeSent < request.Before) - .OrderByDescending(_message => _message.TimeSent) - .Take(request.Count); + ClientId = request.ClientId, + Before = request.Before, + SentBefore = request.Before ?? DateTime.UtcNow, + Count = request.Count, + IsProfileMeta = true + }; - messageMeta = await messages.Select(m => new MessageResponse() - { - // todo: game name - Message = m.Message, - When = m.TimeSent, - ServerId = m.ServerId, - Type = MetaType.ChatMessage - }).ToListAsync(); - - foreach (var meta in messageMeta) - { - if ((meta.Message).IsQuickMessage()) - { - try - { - var quickMessages = ServerManager.GetApplicationSettings().Configuration() - .QuickMessages - .First(/*_qm => _qm.Game == meta.GameName*/); - meta.Message = quickMessages.Messages[(meta.Message as string).Substring(1)]; - meta.Type = MetaType.QuickMessage; - } - catch - { - - } - } - } - } - - return messageMeta; + return (await _chatQueryHelper.QueryResource(query)).Results; } if (Config.Configuration().EnableAntiCheat) diff --git a/Plugins/Stats/Stats.csproj b/Plugins/Stats/Stats.csproj index fa6e14430..879a9535b 100644 --- a/Plugins/Stats/Stats.csproj +++ b/Plugins/Stats/Stats.csproj @@ -16,7 +16,7 @@ - + diff --git a/Plugins/Web/StatsWeb/ChatResourceQueryHelper.cs b/Plugins/Web/StatsWeb/ChatResourceQueryHelper.cs index 54e7d6be1..cb5bed5e7 100644 --- a/Plugins/Web/StatsWeb/ChatResourceQueryHelper.cs +++ b/Plugins/Web/StatsWeb/ChatResourceQueryHelper.cs @@ -1,9 +1,13 @@ using IW4MAdmin.Plugins.Stats.Models; using Microsoft.EntityFrameworkCore; +using SharedLibraryCore; +using SharedLibraryCore.Configuration; +using SharedLibraryCore.Dtos.Meta.Responses; using SharedLibraryCore.Helpers; using SharedLibraryCore.Interfaces; -using StatsWeb.Dtos; +using Stats.Dtos; using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -12,31 +16,44 @@ namespace StatsWeb /// /// implementation of IResourceQueryHelper /// - public class ChatResourceQueryHelper : IResourceQueryHelper + public class ChatResourceQueryHelper : IResourceQueryHelper { private readonly IDatabaseContextFactory _contextFactory; private readonly ILogger _logger; + private readonly ApplicationConfiguration _appConfig; + private List serverCache; - public ChatResourceQueryHelper(ILogger logger, IDatabaseContextFactory contextFactory) + public ChatResourceQueryHelper(ILogger logger, IDatabaseContextFactory contextFactory, ApplicationConfiguration appConfig) { _contextFactory = contextFactory; _logger = logger; + _appConfig = appConfig; } /// - public async Task> QueryResource(ChatSearchQuery query) + public async Task> QueryResource(ChatSearchQuery query) { if (query == null) { throw new ArgumentException("Query must be specified"); } - var result = new ResourceQueryHelperResult(); + var result = new ResourceQueryHelperResult(); using var context = _contextFactory.CreateContext(enableTracking: false); - + + if (serverCache == null) + { + serverCache = await context.Set().ToListAsync(); + } + + if (int.TryParse(query.ServerId, out int serverId)) + { + query.ServerId = serverCache.FirstOrDefault(_server => _server.ServerId == serverId)?.EndPoint ?? query.ServerId; + } + var iqMessages = context.Set() .Where(_message => _message.TimeSent >= query.SentAfter) - .Where(_message => _message.TimeSent <= query.SentBefore); + .Where(_message => _message.TimeSent < query.SentBefore); if (query.ClientId != null) { @@ -50,27 +67,29 @@ namespace StatsWeb if (!string.IsNullOrEmpty(query.MessageContains)) { - iqMessages = iqMessages.Where(_message => EF.Functions.Like(_message.Message, $"%{query.MessageContains}%")); + iqMessages = iqMessages.Where(_message => EF.Functions.Like(_message.Message.ToLower(), $"%{query.MessageContains.ToLower()}%")); } var iqResponse = iqMessages - .Select(_message => new ChatSearchResult + .Select(_message => new MessageResponse { ClientId = _message.ClientId, - ClientName = _message.Client.CurrentAlias.Name, - Date = _message.TimeSent, + ClientName = query.IsProfileMeta ? "" : _message.Client.CurrentAlias.Name, + ServerId = _message.ServerId, + When = _message.TimeSent, Message = _message.Message, - ServerName = _message.Server.HostName + ServerName = query.IsProfileMeta ? "" : _message.Server.HostName, + GameName = _message.Server.GameName == null ? Server.Game.IW4 : _message.Server.GameName.Value }); if (query.Direction == SharedLibraryCore.Dtos.SortDirection.Descending) { - iqResponse = iqResponse.OrderByDescending(_message => _message.Date); + iqResponse = iqResponse.OrderByDescending(_message => _message.When); } else { - iqResponse = iqResponse.OrderBy(_message => _message.Date); + iqResponse = iqResponse.OrderBy(_message => _message.When); } var resultList = await iqResponse @@ -78,6 +97,27 @@ namespace StatsWeb .Take(query.Count) .ToListAsync(); + foreach (var message in resultList) + { + message.IsHidden = serverCache.Any(server => server.ServerId == message.ServerId && server.IsPasswordProtected); + + if (message.Message.IsQuickMessage()) + { + try + { + var quickMessages = _appConfig + .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; diff --git a/Plugins/Web/StatsWeb/Controllers/StatsController.cs b/Plugins/Web/StatsWeb/Controllers/StatsController.cs index 4b7e3311d..77a0a0e80 100644 --- a/Plugins/Web/StatsWeb/Controllers/StatsController.cs +++ b/Plugins/Web/StatsWeb/Controllers/StatsController.cs @@ -5,8 +5,9 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using SharedLibraryCore; using SharedLibraryCore.Dtos; +using SharedLibraryCore.Dtos.Meta.Responses; using SharedLibraryCore.Interfaces; -using StatsWeb.Dtos; +using Stats.Dtos; using StatsWeb.Extensions; using System; using System.Linq; @@ -18,10 +19,10 @@ namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers { private readonly ILogger _logger; private readonly IManager _manager; - private readonly IResourceQueryHelper _chatResourceQueryHelper; + private readonly IResourceQueryHelper _chatResourceQueryHelper; private readonly ITranslationLookup _translationLookup; - public StatsController(ILogger logger, IManager manager, IResourceQueryHelper resourceQueryHelper, + public StatsController(ILogger logger, IManager manager, IResourceQueryHelper resourceQueryHelper, ITranslationLookup translationLookup) : base(manager) { _logger = logger; @@ -72,51 +73,24 @@ namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers } [HttpGet] - public async Task GetMessageAsync(int serverId, long when) + public async Task GetMessageAsync(string serverId, long when) { var whenTime = DateTime.FromFileTimeUtc(when); var whenUpper = whenTime.AddMinutes(5); var whenLower = whenTime.AddMinutes(-5); - using (var ctx = new SharedLibraryCore.Database.DatabaseContext(true)) + var messages = await _chatResourceQueryHelper.QueryResource(new ChatSearchQuery() { - var iqMessages = from message in ctx.Set() - where message.ServerId == serverId - where message.TimeSent >= whenLower - where message.TimeSent <= whenUpper - select new ChatInfo() - { - ClientId = message.ClientId, - Message = message.Message, - Name = message.Client.CurrentAlias.Name, - Time = message.TimeSent, - ServerGame = message.Server.GameName ?? Server.Game.IW4 - }; + ServerId = serverId, + SentBefore = whenUpper, + SentAfter = whenLower + }); - var messages = await iqMessages.ToListAsync(); - - foreach (var message in messages) - { - if (message.Message.IsQuickMessage()) - { - try - { - var quickMessages = _manager.GetApplicationSettings().Configuration() - .QuickMessages - .First(_qm => _qm.Game == message.ServerGame); - message.Message = quickMessages.Messages[message.Message.Substring(1)]; - message.IsQuickMessage = true; - } - catch { } - } - } - - return View("_MessageContext", messages); - } + return View("_MessageContext", messages.Results); } [HttpGet("Message/Find")] - public async Task FindMessage([FromQuery]string query) + public async Task FindMessage([FromQuery] string query) { ViewBag.Localization = _translationLookup; ViewBag.EnableColorCodes = _manager.GetApplicationSettings().Configuration().EnableColorCodes; @@ -151,7 +125,7 @@ namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers } [HttpGet("Message/FindNext")] - public async Task FindNextMessages([FromQuery]string query, [FromQuery]int count, [FromQuery]int offset) + public async Task FindNextMessages([FromQuery] string query, [FromQuery] int count, [FromQuery] int offset) { ChatSearchQuery searchRequest; diff --git a/Plugins/Web/StatsWeb/Dtos/ChatSearchResult.cs b/Plugins/Web/StatsWeb/Dtos/ChatSearchResult.cs deleted file mode 100644 index 9390e1d18..000000000 --- a/Plugins/Web/StatsWeb/Dtos/ChatSearchResult.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; - -namespace StatsWeb.Dtos -{ - public class ChatSearchResult - { - /// - /// name of the client - /// - public string ClientName { get; set; } - - /// - /// client id - /// - public int ClientId { get; set; } - - /// - /// hostname of the server - /// - public string ServerName { get; set; } - - /// - /// chat message - /// - public string Message { get; set; } - - /// - /// date the chat occured on - /// - public DateTime Date { get; set; } - } -} diff --git a/Plugins/Web/StatsWeb/Extensions/SearchQueryExtensions.cs b/Plugins/Web/StatsWeb/Extensions/SearchQueryExtensions.cs index 66f582286..bde74b826 100644 --- a/Plugins/Web/StatsWeb/Extensions/SearchQueryExtensions.cs +++ b/Plugins/Web/StatsWeb/Extensions/SearchQueryExtensions.cs @@ -1,5 +1,5 @@ using SharedLibraryCore.Dtos; -using StatsWeb.Dtos; +using Stats.Dtos; using System; using System.Linq; diff --git a/Plugins/Web/StatsWeb/StatsWeb.csproj b/Plugins/Web/StatsWeb/StatsWeb.csproj index 100c8fd96..b7ce2d2df 100644 --- a/Plugins/Web/StatsWeb/StatsWeb.csproj +++ b/Plugins/Web/StatsWeb/StatsWeb.csproj @@ -14,7 +14,7 @@ Always - + diff --git a/Plugins/Web/StatsWeb/Views/Stats/Message/Find.cshtml b/Plugins/Web/StatsWeb/Views/Stats/Message/Find.cshtml index d4bc1aa87..713fdb1a6 100644 --- a/Plugins/Web/StatsWeb/Views/Stats/Message/Find.cshtml +++ b/Plugins/Web/StatsWeb/Views/Stats/Message/Find.cshtml @@ -1,4 +1,5 @@ -@model SharedLibraryCore.Helpers.ResourceQueryHelperResult +@using SharedLibraryCore.Dtos.Meta.Responses +@model SharedLibraryCore.Helpers.ResourceQueryHelperResult @if (ViewBag.Error != null) { diff --git a/Plugins/Web/StatsWeb/Views/Stats/Message/_Item.cshtml b/Plugins/Web/StatsWeb/Views/Stats/Message/_Item.cshtml index 6a5388fe5..45b3670fb 100644 --- a/Plugins/Web/StatsWeb/Views/Stats/Message/_Item.cshtml +++ b/Plugins/Web/StatsWeb/Views/Stats/Message/_Item.cshtml @@ -1,4 +1,5 @@ -@model IEnumerable +@using SharedLibraryCore.Dtos.Meta.Responses +@model IEnumerable @foreach (var message in Model) { @@ -10,13 +11,20 @@ - + @if (message.IsHidden && !ViewBag.Authorized) + { + + } + else + { + + } - @message.Date + @message.When @@ -33,7 +41,14 @@ @ViewBag.Localization["WEBFRONT_ACTION_LABEL_MESSAGE"] - + @if (message.IsHidden && !ViewBag.Authorized) + { + + } + else + { + + } @@ -47,7 +62,7 @@ @ViewBag.Localization["WEBFRONT_ADMIN_AUDIT_LOG_TIME"] - @message.Date + @message.When } \ No newline at end of file diff --git a/Plugins/Web/StatsWeb/Views/Stats/_MessageContext.cshtml b/Plugins/Web/StatsWeb/Views/Stats/_MessageContext.cshtml index 0d0459a4d..602d21b53 100644 --- a/Plugins/Web/StatsWeb/Views/Stats/_MessageContext.cshtml +++ b/Plugins/Web/StatsWeb/Views/Stats/_MessageContext.cshtml @@ -1,20 +1,21 @@ -@model IEnumerable +@using SharedLibraryCore.Dtos.Meta.Responses +@model IEnumerable @{ Layout = null; }
-
@Model.First().Time.ToString()
+
@Model.First().When.ToString()
@foreach (var message in Model) { - + - +
diff --git a/Plugins/Welcome/Welcome.csproj b/Plugins/Welcome/Welcome.csproj index a01c58720..02dc83ee4 100644 --- a/Plugins/Welcome/Welcome.csproj +++ b/Plugins/Welcome/Welcome.csproj @@ -16,7 +16,7 @@ - + diff --git a/SharedLibraryCore/Dtos/ChatInfo.cs b/SharedLibraryCore/Dtos/ChatInfo.cs index c67687f12..d7cdd081b 100644 --- a/SharedLibraryCore/Dtos/ChatInfo.cs +++ b/SharedLibraryCore/Dtos/ChatInfo.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using static SharedLibraryCore.Server; namespace SharedLibraryCore.Dtos @@ -11,5 +12,7 @@ namespace SharedLibraryCore.Dtos public string Name { get; set; } public Game ServerGame { get; set; } public bool IsQuickMessage { get; set; } + public bool IsHidden { get; set; } + public string HiddenMessage => string.Concat(Enumerable.Repeat('●', Message.Length)); } } \ No newline at end of file diff --git a/SharedLibraryCore/Dtos/Meta/Responses/MessageResponse.cs b/SharedLibraryCore/Dtos/Meta/Responses/MessageResponse.cs index 18cc845d0..8ca3693cf 100644 --- a/SharedLibraryCore/Dtos/Meta/Responses/MessageResponse.cs +++ b/SharedLibraryCore/Dtos/Meta/Responses/MessageResponse.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; +using System.Linq; namespace SharedLibraryCore.Dtos.Meta.Responses { @@ -8,5 +6,28 @@ namespace SharedLibraryCore.Dtos.Meta.Responses { public long ServerId { get; set; } public string Message { get; set; } + public bool IsHidden { get; set; } + + /// + /// name of the client + /// + public string ClientName { get; set; } + + /// + /// hostname of the server + /// + public string ServerName { get; set; } + + /// + /// specifies the game the chat occured on + /// + public Server.Game GameName { get; set; } + + /// + /// indicates if the chat message is a quick message phrase + /// + public bool IsQuickMessage { get; set; } + + public string HiddenMessage => string.Concat(Enumerable.Repeat('●', Message.Length)); } } diff --git a/SharedLibraryCore/Dtos/ServerInfo.cs b/SharedLibraryCore/Dtos/ServerInfo.cs index b86369f26..ca54da2ac 100644 --- a/SharedLibraryCore/Dtos/ServerInfo.cs +++ b/SharedLibraryCore/Dtos/ServerInfo.cs @@ -21,5 +21,6 @@ namespace SharedLibraryCore.Dtos public bool Online { get; set; } public string ConnectProtocolUrl { get; set; } public string IPAddress { get; set; } + public bool IsPasswordProtected { get; set; } } } diff --git a/SharedLibraryCore/Migrations/20200819224119_AddIsPasswordProtectedColumn.Designer.cs b/SharedLibraryCore/Migrations/20200819224119_AddIsPasswordProtectedColumn.Designer.cs new file mode 100644 index 000000000..f54f9cb2c --- /dev/null +++ b/SharedLibraryCore/Migrations/20200819224119_AddIsPasswordProtectedColumn.Designer.cs @@ -0,0 +1,925 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using SharedLibraryCore.Database; + +namespace SharedLibraryCore.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20200819224119_AddIsPasswordProtectedColumn")] + partial class AddIsPasswordProtectedColumn + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.7"); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b => + { + b.Property("SnapshotId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Active") + .HasColumnType("INTEGER"); + + b.Property("ClientId") + .HasColumnType("INTEGER"); + + b.Property("CurrentSessionLength") + .HasColumnType("INTEGER"); + + b.Property("CurrentStrain") + .HasColumnType("REAL"); + + b.Property("CurrentViewAngleId") + .HasColumnType("INTEGER"); + + b.Property("Deaths") + .HasColumnType("INTEGER"); + + b.Property("Distance") + .HasColumnType("REAL"); + + b.Property("EloRating") + .HasColumnType("REAL"); + + b.Property("HitDestinationId") + .HasColumnType("INTEGER"); + + b.Property("HitLocation") + .HasColumnType("INTEGER"); + + b.Property("HitOriginId") + .HasColumnType("INTEGER"); + + b.Property("HitType") + .HasColumnType("INTEGER"); + + b.Property("Hits") + .HasColumnType("INTEGER"); + + b.Property("Kills") + .HasColumnType("INTEGER"); + + b.Property("LastStrainAngleId") + .HasColumnType("INTEGER"); + + b.Property("RecoilOffset") + .HasColumnType("REAL"); + + b.Property("SessionAngleOffset") + .HasColumnType("REAL"); + + b.Property("SessionAverageSnapValue") + .HasColumnType("REAL"); + + b.Property("SessionSPM") + .HasColumnType("REAL"); + + b.Property("SessionScore") + .HasColumnType("INTEGER"); + + b.Property("SessionSnapHits") + .HasColumnType("INTEGER"); + + b.Property("StrainAngleBetween") + .HasColumnType("REAL"); + + b.Property("TimeSinceLastEvent") + .HasColumnType("INTEGER"); + + b.Property("WeaponId") + .HasColumnType("INTEGER"); + + b.Property("When") + .HasColumnType("TEXT"); + + b.HasKey("SnapshotId"); + + b.HasIndex("ClientId"); + + b.HasIndex("CurrentViewAngleId"); + + b.HasIndex("HitDestinationId"); + + b.HasIndex("HitOriginId"); + + b.HasIndex("LastStrainAngleId"); + + b.ToTable("EFACSnapshot"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshotVector3", b => + { + b.Property("ACSnapshotVector3Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Active") + .HasColumnType("INTEGER"); + + b.Property("SnapshotId") + .HasColumnType("INTEGER"); + + b.Property("Vector3Id") + .HasColumnType("INTEGER"); + + b.HasKey("ACSnapshotVector3Id"); + + b.HasIndex("SnapshotId"); + + b.HasIndex("Vector3Id"); + + b.ToTable("EFACSnapshotVector3"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b => + { + b.Property("KillId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Active") + .HasColumnType("INTEGER"); + + b.Property("AttackerId") + .HasColumnType("INTEGER"); + + b.Property("Damage") + .HasColumnType("INTEGER"); + + b.Property("DeathOriginVector3Id") + .HasColumnType("INTEGER"); + + b.Property("DeathType") + .HasColumnType("INTEGER"); + + b.Property("Fraction") + .HasColumnType("REAL"); + + b.Property("HitLoc") + .HasColumnType("INTEGER"); + + b.Property("IsKill") + .HasColumnType("INTEGER"); + + b.Property("KillOriginVector3Id") + .HasColumnType("INTEGER"); + + b.Property("Map") + .HasColumnType("INTEGER"); + + b.Property("ServerId") + .HasColumnType("INTEGER"); + + b.Property("VictimId") + .HasColumnType("INTEGER"); + + b.Property("ViewAnglesVector3Id") + .HasColumnType("INTEGER"); + + b.Property("VisibilityPercentage") + .HasColumnType("REAL"); + + b.Property("Weapon") + .HasColumnType("INTEGER"); + + b.Property("When") + .HasColumnType("TEXT"); + + b.HasKey("KillId"); + + b.HasIndex("AttackerId"); + + b.HasIndex("DeathOriginVector3Id"); + + b.HasIndex("KillOriginVector3Id"); + + b.HasIndex("ServerId"); + + b.HasIndex("VictimId"); + + b.HasIndex("ViewAnglesVector3Id"); + + b.ToTable("EFClientKills"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b => + { + b.Property("MessageId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Active") + .HasColumnType("INTEGER"); + + b.Property("ClientId") + .HasColumnType("INTEGER"); + + b.Property("Message") + .HasColumnType("TEXT"); + + b.Property("ServerId") + .HasColumnType("INTEGER"); + + b.Property("TimeSent") + .HasColumnType("TEXT"); + + b.HasKey("MessageId"); + + b.HasIndex("ClientId"); + + b.HasIndex("ServerId"); + + b.HasIndex("TimeSent"); + + b.ToTable("EFClientMessages"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b => + { + b.Property("RatingHistoryId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Active") + .HasColumnType("INTEGER"); + + b.Property("ClientId") + .HasColumnType("INTEGER"); + + b.HasKey("RatingHistoryId"); + + b.HasIndex("ClientId"); + + b.ToTable("EFClientRatingHistory"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b => + { + b.Property("ClientId") + .HasColumnType("INTEGER"); + + b.Property("ServerId") + .HasColumnType("INTEGER"); + + b.Property("Active") + .HasColumnType("INTEGER"); + + b.Property("AverageRecoilOffset") + .HasColumnType("REAL"); + + b.Property("AverageSnapValue") + .HasColumnType("REAL"); + + b.Property("Deaths") + .HasColumnType("INTEGER"); + + b.Property("EloRating") + .HasColumnType("REAL"); + + b.Property("Kills") + .HasColumnType("INTEGER"); + + b.Property("MaxStrain") + .HasColumnType("REAL"); + + b.Property("RollingWeightedKDR") + .HasColumnType("REAL"); + + b.Property("SPM") + .HasColumnType("REAL"); + + b.Property("Skill") + .HasColumnType("REAL"); + + b.Property("SnapHitCount") + .HasColumnType("INTEGER"); + + b.Property("TimePlayed") + .HasColumnType("INTEGER"); + + b.Property("VisionAverage") + .HasColumnType("REAL"); + + b.HasKey("ClientId", "ServerId"); + + b.HasIndex("ServerId"); + + b.ToTable("EFClientStatistics"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b => + { + b.Property("HitLocationCountId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Active") + .HasColumnType("INTEGER"); + + b.Property("EFClientStatisticsClientId") + .HasColumnName("EFClientStatisticsClientId") + .HasColumnType("INTEGER"); + + b.Property("EFClientStatisticsServerId") + .HasColumnName("EFClientStatisticsServerId") + .HasColumnType("INTEGER"); + + b.Property("HitCount") + .HasColumnType("INTEGER"); + + b.Property("HitOffsetAverage") + .HasColumnType("REAL"); + + b.Property("Location") + .HasColumnType("INTEGER"); + + b.Property("MaxAngleDistance") + .HasColumnType("REAL"); + + b.HasKey("HitLocationCountId"); + + b.HasIndex("EFClientStatisticsServerId"); + + b.HasIndex("EFClientStatisticsClientId", "EFClientStatisticsServerId"); + + b.ToTable("EFHitLocationCounts"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b => + { + b.Property("RatingId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Active") + .HasColumnType("INTEGER"); + + b.Property("ActivityAmount") + .HasColumnType("INTEGER"); + + b.Property("Newest") + .HasColumnType("INTEGER"); + + b.Property("Performance") + .HasColumnType("REAL"); + + b.Property("Ranking") + .HasColumnType("INTEGER"); + + b.Property("RatingHistoryId") + .HasColumnType("INTEGER"); + + b.Property("ServerId") + .HasColumnType("INTEGER"); + + b.Property("When") + .HasColumnType("TEXT"); + + b.HasKey("RatingId"); + + b.HasIndex("RatingHistoryId"); + + b.HasIndex("ServerId"); + + b.HasIndex("Performance", "Ranking", "When"); + + b.ToTable("EFRating"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b => + { + b.Property("ServerId") + .HasColumnType("INTEGER"); + + b.Property("Active") + .HasColumnType("INTEGER"); + + b.Property("EndPoint") + .HasColumnType("TEXT"); + + b.Property("GameName") + .HasColumnType("INTEGER"); + + b.Property("HostName") + .HasColumnType("TEXT"); + + b.Property("IsPasswordProtected") + .HasColumnType("INTEGER"); + + b.Property("Port") + .HasColumnType("INTEGER"); + + b.HasKey("ServerId"); + + b.ToTable("EFServers"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b => + { + b.Property("StatisticId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Active") + .HasColumnType("INTEGER"); + + b.Property("ServerId") + .HasColumnType("INTEGER"); + + b.Property("TotalKills") + .HasColumnType("INTEGER"); + + b.Property("TotalPlayTime") + .HasColumnType("INTEGER"); + + b.HasKey("StatisticId"); + + b.HasIndex("ServerId"); + + b.ToTable("EFServerStatistics"); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b => + { + b.Property("AliasId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Active") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("IPAddress") + .HasColumnType("INTEGER"); + + b.Property("LinkId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(24); + + b.Property("SearchableName") + .HasColumnType("TEXT") + .HasMaxLength(24); + + b.HasKey("AliasId"); + + b.HasIndex("IPAddress"); + + b.HasIndex("LinkId"); + + b.HasIndex("Name"); + + b.HasIndex("SearchableName"); + + b.HasIndex("Name", "IPAddress") + .IsUnique(); + + b.ToTable("EFAlias"); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAliasLink", b => + { + b.Property("AliasLinkId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Active") + .HasColumnType("INTEGER"); + + b.HasKey("AliasLinkId"); + + b.ToTable("EFAliasLinks"); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFChangeHistory", b => + { + b.Property("ChangeHistoryId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Active") + .HasColumnType("INTEGER"); + + b.Property("Comment") + .HasColumnType("TEXT") + .HasMaxLength(128); + + b.Property("CurrentValue") + .HasColumnType("TEXT"); + + b.Property("ImpersonationEntityId") + .HasColumnType("INTEGER"); + + b.Property("OriginEntityId") + .HasColumnType("INTEGER"); + + b.Property("PreviousValue") + .HasColumnType("TEXT"); + + b.Property("TargetEntityId") + .HasColumnType("INTEGER"); + + b.Property("TimeChanged") + .HasColumnType("TEXT"); + + b.Property("TypeOfChange") + .HasColumnType("INTEGER"); + + b.HasKey("ChangeHistoryId"); + + b.ToTable("EFChangeHistory"); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b => + { + b.Property("ClientId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Active") + .HasColumnType("INTEGER"); + + b.Property("AliasLinkId") + .HasColumnType("INTEGER"); + + b.Property("Connections") + .HasColumnType("INTEGER"); + + b.Property("CurrentAliasId") + .HasColumnType("INTEGER"); + + b.Property("FirstConnection") + .HasColumnType("TEXT"); + + b.Property("LastConnection") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("INTEGER"); + + b.Property("Masked") + .HasColumnType("INTEGER"); + + b.Property("NetworkId") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasColumnType("TEXT"); + + b.Property("PasswordSalt") + .HasColumnType("TEXT"); + + b.Property("TotalConnectionTime") + .HasColumnType("INTEGER"); + + b.HasKey("ClientId"); + + b.HasIndex("AliasLinkId"); + + b.HasIndex("CurrentAliasId"); + + b.HasIndex("NetworkId") + .IsUnique(); + + b.ToTable("EFClients"); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b => + { + b.Property("MetaId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Active") + .HasColumnType("INTEGER"); + + b.Property("ClientId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Extra") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(32); + + b.Property("Updated") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("MetaId"); + + b.HasIndex("ClientId"); + + b.HasIndex("Key"); + + b.ToTable("EFMeta"); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b => + { + b.Property("PenaltyId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Active") + .HasColumnType("INTEGER"); + + b.Property("AutomatedOffense") + .HasColumnType("TEXT"); + + b.Property("Expires") + .HasColumnType("TEXT"); + + b.Property("IsEvadedOffense") + .HasColumnType("INTEGER"); + + b.Property("LinkId") + .HasColumnType("INTEGER"); + + b.Property("OffenderId") + .HasColumnType("INTEGER"); + + b.Property("Offense") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PunisherId") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("When") + .HasColumnType("TEXT"); + + b.HasKey("PenaltyId"); + + b.HasIndex("LinkId"); + + b.HasIndex("OffenderId"); + + b.HasIndex("PunisherId"); + + b.ToTable("EFPenalties"); + }); + + modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b => + { + b.Property("Vector3Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("X") + .HasColumnType("REAL"); + + b.Property("Y") + .HasColumnType("REAL"); + + b.Property("Z") + .HasColumnType("REAL"); + + b.HasKey("Vector3Id"); + + b.ToTable("Vector3"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") + .WithMany() + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "CurrentViewAngle") + .WithMany() + .HasForeignKey("CurrentViewAngleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitDestination") + .WithMany() + .HasForeignKey("HitDestinationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitOrigin") + .WithMany() + .HasForeignKey("HitOriginId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "LastStrainAngle") + .WithMany() + .HasForeignKey("LastStrainAngleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshotVector3", b => + { + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", "Snapshot") + .WithMany("PredictedViewAngles") + .HasForeignKey("SnapshotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "Vector") + .WithMany() + .HasForeignKey("Vector3Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker") + .WithMany() + .HasForeignKey("AttackerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "DeathOrigin") + .WithMany() + .HasForeignKey("DeathOriginVector3Id"); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "KillOrigin") + .WithMany() + .HasForeignKey("KillOriginVector3Id"); + + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Victim") + .WithMany() + .HasForeignKey("VictimId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "ViewAngles") + .WithMany() + .HasForeignKey("ViewAnglesVector3Id"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") + .WithMany() + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") + .WithMany() + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") + .WithMany() + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") + .WithMany() + .HasForeignKey("EFClientStatisticsClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("EFClientStatisticsServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", null) + .WithMany("HitLocations") + .HasForeignKey("EFClientStatisticsClientId", "EFClientStatisticsServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b => + { + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", "RatingHistory") + .WithMany("Ratings") + .HasForeignKey("RatingHistoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("ServerId"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b => + { + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link") + .WithMany("Children") + .HasForeignKey("LinkId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "AliasLink") + .WithMany() + .HasForeignKey("AliasLinkId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SharedLibraryCore.Database.Models.EFAlias", "CurrentAlias") + .WithMany() + .HasForeignKey("CurrentAliasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") + .WithMany("Meta") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link") + .WithMany("ReceivedPenalties") + .HasForeignKey("LinkId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Offender") + .WithMany("ReceivedPenalties") + .HasForeignKey("OffenderId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Punisher") + .WithMany("AdministeredPenalties") + .HasForeignKey("PunisherId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/SharedLibraryCore/Migrations/20200819224119_AddIsPasswordProtectedColumn.cs b/SharedLibraryCore/Migrations/20200819224119_AddIsPasswordProtectedColumn.cs new file mode 100644 index 000000000..937548ff8 --- /dev/null +++ b/SharedLibraryCore/Migrations/20200819224119_AddIsPasswordProtectedColumn.cs @@ -0,0 +1,35 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace SharedLibraryCore.Migrations +{ + public partial class AddIsPasswordProtectedColumn : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + if (migrationBuilder.ActiveProvider == "Npgsql.EntityFrameworkCore.PostgreSQL") + { + migrationBuilder.AddColumn( + name: "IsPasswordProtected", + type: "bool", + table: "EFServers", + nullable: false, + defaultValue: false); + } + else + { + migrationBuilder.AddColumn( + name: "IsPasswordProtected", + table: "EFServers", + nullable: false, + defaultValue: false); + } + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsPasswordProtected", + table: "EFServers"); + } + } +} diff --git a/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs b/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs index 01743b0c8..66dc63c14 100644 --- a/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs +++ b/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs @@ -14,7 +14,7 @@ namespace SharedLibraryCore.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "3.1.3"); + .HasAnnotation("ProductVersion", "3.1.7"); modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b => { @@ -408,6 +408,9 @@ namespace SharedLibraryCore.Migrations b.Property("HostName") .HasColumnType("TEXT"); + b.Property("IsPasswordProtected") + .HasColumnType("INTEGER"); + b.Property("Port") .HasColumnType("INTEGER"); diff --git a/SharedLibraryCore/Server.cs b/SharedLibraryCore/Server.cs index 1b9f72f15..5b5a8f9d7 100644 --- a/SharedLibraryCore/Server.cs +++ b/SharedLibraryCore/Server.cs @@ -293,6 +293,7 @@ namespace SharedLibraryCore public string Hostname { get => ServerConfig.CustomHostname ?? hostname; protected set => hostname = value; } public string Website { get; protected set; } public string Gametype { get; set; } + public string GamePassword { get; protected set; } public Map CurrentMap { get; set; } public int ClientNum { diff --git a/SharedLibraryCore/SharedLibraryCore.csproj b/SharedLibraryCore/SharedLibraryCore.csproj index fe485e9b3..1d78e30d2 100644 --- a/SharedLibraryCore/SharedLibraryCore.csproj +++ b/SharedLibraryCore/SharedLibraryCore.csproj @@ -6,7 +6,7 @@ RaidMax.IW4MAdmin.SharedLibraryCore - 2.4.7 + 2.4.9 RaidMax Forever None Debug;Release;Prerelease @@ -21,8 +21,8 @@ true MIT Shared Library for IW4MAdmin - 2.4.7.0 - 2.4.7.0 + 2.4.9.0 + 2.4.9.0 diff --git a/SharedLibraryCore/Utilities.cs b/SharedLibraryCore/Utilities.cs index 4a0ee059b..d8b0c0059 100644 --- a/SharedLibraryCore/Utilities.cs +++ b/SharedLibraryCore/Utilities.cs @@ -672,11 +672,11 @@ namespace SharedLibraryCore return server.RconParser.GetDvarAsync(server.RemoteConnection, dvarName, fallbackValue); } - public static async Task> GetMappedDvarValueOrDefaultAsync(this Server server, string dvarName, string infoResponseName = null, IDictionary infoResponse = null) + public static async Task> GetMappedDvarValueOrDefaultAsync(this Server server, string dvarName, string infoResponseName = null, IDictionary infoResponse = null, T overrideDefault = default) { // todo: unit test this string mappedKey = server.RconParser.GetOverrideDvarName(dvarName); - var defaultValue = server.RconParser.GetDefaultDvarValue(mappedKey); + var defaultValue = server.RconParser.GetDefaultDvarValue(mappedKey) ?? overrideDefault; string foundKey = infoResponse?.Keys.Where(_key => new[] { mappedKey, dvarName, infoResponseName ?? dvarName }.Contains(_key)).FirstOrDefault(); @@ -811,7 +811,7 @@ namespace SharedLibraryCore /// true if the public static bool IsQuickMessage(this string message) { - return Regex.IsMatch(message, @"^\u0014(?:[A-Z]|_)+$"); + return Regex.IsMatch(message, @"^\u0014(?:\w|_|!|\s)+$"); } /// diff --git a/Tests/ApplicationTests/ApiTests.cs b/Tests/ApplicationTests/ApiTests.cs index 7278b2ec3..38e287f13 100644 --- a/Tests/ApplicationTests/ApiTests.cs +++ b/Tests/ApplicationTests/ApiTests.cs @@ -9,7 +9,6 @@ using SharedLibraryCore.Dtos; using SharedLibraryCore.Helpers; using SharedLibraryCore.Interfaces; using Stats.Dtos; -using StatsWeb.Dtos; using System; using System.Collections.Generic; using System.Linq; diff --git a/Tests/ApplicationTests/Fixtures/ConfigurationGenerators.cs b/Tests/ApplicationTests/Fixtures/ConfigurationGenerators.cs index 7c4a6b094..0fda83b62 100644 --- a/Tests/ApplicationTests/Fixtures/ConfigurationGenerators.cs +++ b/Tests/ApplicationTests/Fixtures/ConfigurationGenerators.cs @@ -18,7 +18,7 @@ namespace ApplicationTests.Fixtures Say = "say" } }; - public static ApplicationConfiguration CreateApplicationConfiguration() => new ApplicationConfiguration() { Servers = new[] { CreateServerConfiguration() } }; + public static ApplicationConfiguration CreateApplicationConfiguration() => new ApplicationConfiguration() { Servers = new[] { CreateServerConfiguration() }, QuickMessages = new QuickMessageConfiguration[0] }; public static CommandConfiguration CreateCommandConfiguration() => new CommandConfiguration(); } } diff --git a/Tests/ApplicationTests/Fixtures/MessageGenerators.cs b/Tests/ApplicationTests/Fixtures/MessageGenerators.cs index 19461e59e..939c65a7d 100644 --- a/Tests/ApplicationTests/Fixtures/MessageGenerators.cs +++ b/Tests/ApplicationTests/Fixtures/MessageGenerators.cs @@ -19,7 +19,7 @@ namespace ApplicationTests.Fixtures return new EFClientMessage() { Active = true, - Message = content, + Message = content ?? "test", TimeSent = sent.Value, Client = new EFClient() { diff --git a/Tests/ApplicationTests/StatsWebTests.cs b/Tests/ApplicationTests/StatsWebTests.cs index b3069a6a8..c4b95e99c 100644 --- a/Tests/ApplicationTests/StatsWebTests.cs +++ b/Tests/ApplicationTests/StatsWebTests.cs @@ -154,7 +154,7 @@ namespace ApplicationTests var query = $"chat|after {DateTime.Now.ToString()}".ParseSearchInfo(1, 0); var result = await queryHelper.QueryResource(query); - Assert.AreEqual(oneHourAhead, result.Results.First().Date); + Assert.AreEqual(oneHourAhead, result.Results.First().When); dbContext.Remove(msg); await dbContext.SaveChangesAsync(); @@ -173,7 +173,7 @@ namespace ApplicationTests var query = $"chat|before {DateTime.Now.ToString()}".ParseSearchInfo(1, 0); var result = await queryHelper.QueryResource(query); - Assert.AreEqual(oneHourAgo, result.Results.First().Date); + Assert.AreEqual(oneHourAgo, result.Results.First().When); dbContext.Remove(msg); await dbContext.SaveChangesAsync(); @@ -251,14 +251,14 @@ namespace ApplicationTests var query = $"chat|sort {SortDirection.Ascending}".ParseSearchInfo(2, 0); var result = await queryHelper.QueryResource(query); - Assert.AreEqual(firstMessage.TimeSent, result.Results.First().Date); - Assert.AreEqual(secondMessage.TimeSent, result.Results.Last().Date); + Assert.AreEqual(firstMessage.TimeSent, result.Results.First().When); + Assert.AreEqual(secondMessage.TimeSent, result.Results.Last().When); query = $"chat|sort {SortDirection.Descending}".ParseSearchInfo(2, 0); result = await queryHelper.QueryResource(query); - Assert.AreEqual(firstMessage.TimeSent, result.Results.Last().Date); - Assert.AreEqual(secondMessage.TimeSent, result.Results.First().Date); + Assert.AreEqual(firstMessage.TimeSent, result.Results.Last().When); + Assert.AreEqual(secondMessage.TimeSent, result.Results.First().When); dbContext.Remove(firstMessage); dbContext.Remove(secondMessage); diff --git a/WebfrontCore/Controllers/ServerController.cs b/WebfrontCore/Controllers/ServerController.cs index 3c1fc308c..3f50f0dec 100644 --- a/WebfrontCore/Controllers/ServerController.cs +++ b/WebfrontCore/Controllers/ServerController.cs @@ -42,7 +42,8 @@ namespace WebfrontCore.Controllers LevelInt = (int)p.Level }).ToList(), ChatHistory = s.ChatHistory.ToList(), - PlayerHistory = s.ClientHistory.ToArray() + PlayerHistory = s.ClientHistory.ToArray(), + IsPasswordProtected = !string.IsNullOrEmpty(s.GamePassword) }; return PartialView("_ClientActivity", serverInfo); } diff --git a/WebfrontCore/Startup.cs b/WebfrontCore/Startup.cs index 8bcd167bc..c2eb7c4a3 100644 --- a/WebfrontCore/Startup.cs +++ b/WebfrontCore/Startup.cs @@ -5,31 +5,24 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.ApplicationParts; -using Microsoft.AspNetCore.Mvc.Razor; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using SharedLibraryCore; +using SharedLibraryCore.Configuration; using SharedLibraryCore.Database; using SharedLibraryCore.Dtos; -using SharedLibraryCore.Helpers; +using SharedLibraryCore.Dtos.Meta.Responses; using SharedLibraryCore.Interfaces; using SharedLibraryCore.Services; using Stats.Dtos; using Stats.Helpers; using StatsWeb; -using StatsWeb.Dtos; -/*using Stats.Dtos; -using Stats.Helpers; -using StatsWeb; -using StatsWeb.Dtos;*/ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Reflection; using System.Threading.Tasks; -using WebfrontCore.Controllers.API.Dtos; using WebfrontCore.Controllers.API.Validation; using WebfrontCore.Middleware; @@ -117,7 +110,7 @@ namespace WebfrontCore #endif services.AddSingleton(Program.Manager); - services.AddSingleton, ChatResourceQueryHelper>(); + services.AddSingleton, ChatResourceQueryHelper>(); services.AddTransient, FindClientRequestValidator>(); services.AddSingleton, ClientService>(); services.AddSingleton, StatsResourceQueryHelper>(); @@ -130,6 +123,7 @@ namespace WebfrontCore services.AddSingleton(Program.ApplicationServiceProvider.GetService()); services.AddSingleton(Program.ApplicationServiceProvider.GetService>()); services.AddSingleton(Program.ApplicationServiceProvider.GetService()); + services.AddSingleton(Program.ApplicationServiceProvider.GetService()); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/WebfrontCore/Views/Client/Profile/Meta/_MessageResponse.cshtml b/WebfrontCore/Views/Client/Profile/Meta/_MessageResponse.cshtml index 6a717c979..b5d2f9c1b 100644 --- a/WebfrontCore/Views/Client/Profile/Meta/_MessageResponse.cshtml +++ b/WebfrontCore/Views/Client/Profile/Meta/_MessageResponse.cshtml @@ -1,9 +1,17 @@ -@using SharedLibraryCore.Dtos.Meta.Responses; - +@using SharedLibraryCore.Dtos.Meta.Responses @model MessageResponse + - - + + @if (Model.IsHidden && !ViewBag.Authorized) + { + + } + + else + { + + } \ No newline at end of file diff --git a/WebfrontCore/Views/Server/_ClientActivity.cshtml b/WebfrontCore/Views/Server/_ClientActivity.cshtml index 60e4d2019..de43e762a 100644 --- a/WebfrontCore/Views/Server/_ClientActivity.cshtml +++ b/WebfrontCore/Views/Server/_ClientActivity.cshtml @@ -15,6 +15,8 @@ continue; } + string message = Model.ChatHistory[i].IsHidden && !ViewBag.Authorized ? Model.ChatHistory[i].HiddenMessage : Model.ChatHistory[i].Message; + if (Model.ChatHistory[i].Message == "CONNECTED") { @@ -36,7 +38,7 @@ — - +
} } @@ -114,6 +116,8 @@ continue; } + string message = Model.ChatHistory[i].IsHidden && !ViewBag.Authorized ? Model.ChatHistory[i].HiddenMessage : Model.ChatHistory[i].Message; + if (Model.ChatHistory[i].Message == "CONNECTED") { @@ -135,7 +139,7 @@ — - +
} } diff --git a/WebfrontCore/wwwroot/js/loader.js b/WebfrontCore/wwwroot/js/loader.js index a334f4029..126aebbed 100644 --- a/WebfrontCore/wwwroot/js/loader.js +++ b/WebfrontCore/wwwroot/js/loader.js @@ -12,7 +12,7 @@ function initLoader(location, loaderId, count = 10, start = count, additional) { loaderResponseId = loaderId; loadCount = count; loaderOffset = start; - additionalParams = additional; + additionalParams = additional ?? []; setupListeners(); }