diff --git a/Plugins/Stats/Dtos/ChatSearchQuery.cs b/Plugins/Stats/Dtos/ChatSearchQuery.cs index 66f010e9f..f58f1145f 100644 --- a/Plugins/Stats/Dtos/ChatSearchQuery.cs +++ b/Plugins/Stats/Dtos/ChatSearchQuery.cs @@ -25,11 +25,24 @@ namespace Stats.Dtos /// public DateTime? SentAfter { get; set; } + /// + /// The time associated with SentAfter date + /// + public string SentAfterTime { get; set; } = "00:00"; + + public DateTime? SentAfterDateTime => SentAfter?.Add(TimeSpan.Parse(SentAfterTime)); + /// /// only look for messages sent before this date0 /// - public DateTime SentBefore { get; set; } = DateTime.UtcNow; + public DateTime SentBefore { get; set; } = DateTime.UtcNow.Date; + public string SentBeforeTime { get; set; } = DateTime.UtcNow.ToString("HH:mm"); + + public DateTime? SentBeforeDateTime => SentBefore.Add(TimeSpan.Parse(SentBeforeTime)); + + public bool IsExactMatch { get; set; } + /// /// indicates if the chat is on the meta page /// diff --git a/Plugins/Stats/Helpers/ChatResourceQueryHelper.cs b/Plugins/Stats/Helpers/ChatResourceQueryHelper.cs index 3e7c63ede..f00bd8fec 100644 --- a/Plugins/Stats/Helpers/ChatResourceQueryHelper.cs +++ b/Plugins/Stats/Helpers/ChatResourceQueryHelper.cs @@ -53,11 +53,11 @@ namespace Stats.Helpers } var iqMessages = context.Set() - .Where(message => message.TimeSent < query.SentBefore); + .Where(message => message.TimeSent < query.SentBeforeDateTime); - if (query.SentAfter is not null) + if (query.SentAfterDateTime is not null) { - iqMessages = iqMessages.Where(message => message.TimeSent >= query.SentAfter); + iqMessages = iqMessages.Where(message => message.TimeSent >= query.SentAfterDateTime); } if (query.ClientId is not null) @@ -72,7 +72,10 @@ namespace Stats.Helpers if (!string.IsNullOrEmpty(query.MessageContains)) { - iqMessages = iqMessages.Where(message => EF.Functions.Like(message.Message.ToLower(), $"%{query.MessageContains.ToLower()}%")); + iqMessages = query.IsExactMatch + ? iqMessages.Where(message => message.Message.ToLower() == query.MessageContains.ToLower()) + : iqMessages.Where(message => + EF.Functions.Like(message.Message.ToLower(), $"%{query.MessageContains.ToLower()}%")); } var iqResponse = iqMessages diff --git a/SharedLibraryCore/BaseController.cs b/SharedLibraryCore/BaseController.cs index 45b1c7d10..8123b444c 100644 --- a/SharedLibraryCore/BaseController.cs +++ b/SharedLibraryCore/BaseController.cs @@ -179,6 +179,7 @@ namespace SharedLibraryCore server.Reports.Count(report => DateTime.UtcNow - report.ReportedOn <= TimeSpan.FromHours(24))); ViewBag.PermissionsSet = PermissionsSet; ViewBag.Alerts = AlertManager.RetrieveAlerts(Client); + ViewBag.Manager = Manager; base.OnActionExecuting(context); } diff --git a/WebfrontCore/Controllers/Client/Legacy/StatsController.cs b/WebfrontCore/Controllers/Client/Legacy/StatsController.cs index 4e6339109..13528d2ed 100644 --- a/WebfrontCore/Controllers/Client/Legacy/StatsController.cs +++ b/WebfrontCore/Controllers/Client/Legacy/StatsController.cs @@ -17,6 +17,7 @@ using Microsoft.Extensions.Logging; using ILogger = Microsoft.Extensions.Logging.ILogger; using Data.Abstractions; using Stats.Config; +using WebfrontCore.QueryHelpers.Models; namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers { @@ -121,7 +122,7 @@ namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers } [HttpGet("Message/Find")] - public async Task FindMessage([FromQuery] string query) + public async Task FindMessage([FromQuery] ChatResourceRequest query) { ViewBag.Localization = _translationLookup; ViewBag.EnableColorCodes = _manager.GetApplicationSettings().Configuration().EnableColorCodes; @@ -130,26 +131,8 @@ namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers ViewBag.Title = _translationLookup["WEBFRONT_STATS_MESSAGES_TITLE"]; ViewBag.Error = null; ViewBag.IsFluid = true; - ChatSearchQuery searchRequest = null; - - try - { - searchRequest = query.ParseSearchInfo(int.MaxValue, 0); - } - - catch (ArgumentException e) - { - _logger.LogWarning(e, "Could not parse chat message search query {query}", query); - ViewBag.Error = e; - } - - catch (FormatException e) - { - _logger.LogWarning(e, "Could not parse chat message search query filter format {query}", query); - ViewBag.Error = e; - } - - var result = searchRequest != null ? await _chatResourceQueryHelper.QueryResource(searchRequest) : null; + + var result = query != null ? await _chatResourceQueryHelper.QueryResource(query) : null; return View("~/Views/Client/Message/Find.cshtml", result); } diff --git a/WebfrontCore/QueryHelpers/Models/ChatResourceRequest.cs b/WebfrontCore/QueryHelpers/Models/ChatResourceRequest.cs new file mode 100644 index 000000000..4cd8d43a7 --- /dev/null +++ b/WebfrontCore/QueryHelpers/Models/ChatResourceRequest.cs @@ -0,0 +1,9 @@ +using Stats.Dtos; + +namespace WebfrontCore.QueryHelpers.Models; + +public class ChatResourceRequest : ChatSearchQuery +{ + public bool HasData => !string.IsNullOrEmpty(MessageContains) || !string.IsNullOrEmpty(ServerId) || + ClientId is not null || SentAfterDateTime is not null; +} diff --git a/WebfrontCore/QueryHelpers/Models/ClientResourceRequest.cs b/WebfrontCore/QueryHelpers/Models/ClientResourceRequest.cs index eeb71da97..d3054ea7d 100644 --- a/WebfrontCore/QueryHelpers/Models/ClientResourceRequest.cs +++ b/WebfrontCore/QueryHelpers/Models/ClientResourceRequest.cs @@ -16,4 +16,7 @@ public class ClientResourceRequest : ClientPaginationRequest public EFClient.Permission? ClientLevel { get; set; } public Reference.Game? GameName { get; set; } public bool IncludeGeolocationData { get; set; } = true; + + public bool HasData => !string.IsNullOrEmpty(ClientName) || !string.IsNullOrEmpty(ClientIp) || + !string.IsNullOrEmpty(ClientGuid) || ClientLevel is not null || GameName is not null; } diff --git a/WebfrontCore/Views/Shared/Partials/Search/_ChatSearch.cshtml b/WebfrontCore/Views/Shared/Partials/Search/_ChatSearch.cshtml new file mode 100644 index 000000000..45546b272 --- /dev/null +++ b/WebfrontCore/Views/Shared/Partials/Search/_ChatSearch.cshtml @@ -0,0 +1,86 @@ +@using WebfrontCore.QueryHelpers.Models +@using SharedLibraryCore.Interfaces +@using System.Globalization +@using Microsoft.AspNetCore.Mvc.TagHelpers +@model string +@{ + var existingChatFilter = ViewBag.Query as ChatResourceRequest; + var manager = ViewBag.Manager as IManager; +} + +
+
+ +
+ +
+
+ @if (existingChatFilter?.IsExactMatch ?? false) + { + + } + else + { + + } + + +
+
+
+
+ +
+ + + +
+ + +
+
+ +
+ + @{ + var afterDate = existingChatFilter?.SentAfterDateTime ?? DateTime.UtcNow.AddHours(-1); + } +
+ + + +
+
+ +
+ + @{ + var beforeDate = existingChatFilter?.SentBeforeDateTime ?? DateTime.UtcNow; + } +
+ + +
+
+ + +
diff --git a/WebfrontCore/Views/Shared/Partials/Search/_ClientSearch.cshtml b/WebfrontCore/Views/Shared/Partials/Search/_ClientSearch.cshtml new file mode 100644 index 000000000..2e85d120b --- /dev/null +++ b/WebfrontCore/Views/Shared/Partials/Search/_ClientSearch.cshtml @@ -0,0 +1,116 @@ +@using WebfrontCore.QueryHelpers.Models +@using System.Globalization +@using Data.Models +@using Data.Models.Client +@using Microsoft.AspNetCore.Mvc.TagHelpers +@using SharedLibraryCore.Dtos +@model string +@{ + var existingClientFilter = ViewBag.ClientResourceRequest as ClientResourceRequest; +} + +
+
+ +
+ +
+
+ @if (existingClientFilter?.IsExactClientName ?? false) + { + + } + else + { + + } + +
+
+
+
+ +
+ +
+ +
+
+ @if (existingClientFilter?.IsExactClientIp ?? false) + { + + } + else + { + + } + +
+
+
+
+ +
+ + +
+ +
+ + + +
+ + +
+
+ +
+ +
+ @{ var presetDate = (existingClientFilter?.ClientConnected ?? DateTime.UtcNow.AddYears(-1)).ToString("s", CultureInfo.InvariantCulture); } + + +
+
+ @if ((existingClientFilter?.Direction ?? SortDirection.Descending) is SortDirection.Descending) + { + + } + else + { + + } + +
+
+
+
+ + +
diff --git a/WebfrontCore/Views/Shared/Partials/_SearchResourceFilter.cshtml b/WebfrontCore/Views/Shared/Partials/_SearchResourceFilter.cshtml index e7d36ce77..a935d8aa1 100644 --- a/WebfrontCore/Views/Shared/Partials/_SearchResourceFilter.cshtml +++ b/WebfrontCore/Views/Shared/Partials/_SearchResourceFilter.cshtml @@ -1,126 +1,21 @@ -@using Data.Models.Client -@using SharedLibraryCore.Dtos -@using WebfrontCore.QueryHelpers.Models -@using Data.Models -@using System.Globalization @model string -@{ - var existingClientFilter = ViewBag.ClientResourceRequest as ClientResourceRequest; -} + diff --git a/WebfrontCore/wwwroot/js/search.js b/WebfrontCore/wwwroot/js/search.js index 253b51616..370142551 100644 --- a/WebfrontCore/wwwroot/js/search.js +++ b/WebfrontCore/wwwroot/js/search.js @@ -31,5 +31,38 @@ prevArrow: '<', orientation: 'auto top' }); - }) + }); + + + const clientSearchWrapper = $('*[id^="clientSearchWrapper"]'); + const chatSearchWrapper = $('*[id^="chatSearchWrapper"]'); + const searchTypeSelector = $('#searchTypeSelectorParent select'); + let isClients = false; + + searchTypeSelector.on('change', function () { + if (isClients) { + clientSearchWrapper.removeClass('d-none'); + chatSearchWrapper.addClass('d-none'); + } else { + chatSearchWrapper.removeClass('d-none'); + clientSearchWrapper.addClass('d-none'); + } + isClients = !isClients; + }); + + const isDefault = clientSearchWrapper.data('has-data') !== 'True' && chatSearchWrapper.data('has-data') !== 'True'; + + if (isDefault) { + isClients = false; + searchTypeSelector.val('client').change(); + } else { + if (clientSearchWrapper.data('has-data') === 'True') { + isClients = false; + searchTypeSelector.val('client').change(); + } + if (chatSearchWrapper.data('has-data') === 'True') { + isClients = true; + searchTypeSelector.val('chat').change(); + } + } });