From 8f669239523a5d775281d81bea809bc08b621bac Mon Sep 17 00:00:00 2001 From: "Drechsler, Meik" Date: Thu, 23 Jul 2026 11:18:42 +0200 Subject: [PATCH] Add generic ticket activity filters --- .../F4SD-Cockpit-Server.csproj | 11 +- .../Config/F4SD-Global-Configuration.xml | 16 + .../Config/F4SD-Global-Configuration.xsd | 39 +++ .../F4SD-Infrastructure-Configuration.xml | 8 +- .../DataHistoryCollector.cs | 18 +- .../DataHistoryCollectorM42Wpm.cs | 302 ++++++++++-------- .../DataHistoryConfigGolabalParameters.cs | 127 +++++++- .../DataHistoryConfigInfrastructure.cs | 33 +- .../DataSources/ITicketActivityProvider.cs | 38 +++ .../Config/F4SD-Global-Configuration.xml | 16 + .../F4SD-Infrastructure-Configuration.xml | 8 +- .../Controllers/TicketOverviewController.cs | 4 +- .../Config/F4SD-Global-Configuration.xml | 16 + .../Config/F4SD-Global-Configuration.xsd | 39 +++ .../F4SD-Infrastructure-Configuration.xml | 8 +- 15 files changed, 502 insertions(+), 181 deletions(-) create mode 100644 F4SD-Cockpit-ServerCore/DataSources/ITicketActivityProvider.cs diff --git a/C4IT_DataHistoryProvider_Base/F4SD-Cockpit-Server.csproj b/C4IT_DataHistoryProvider_Base/F4SD-Cockpit-Server.csproj index 0c6f115..cfb5a2a 100644 --- a/C4IT_DataHistoryProvider_Base/F4SD-Cockpit-Server.csproj +++ b/C4IT_DataHistoryProvider_Base/F4SD-Cockpit-Server.csproj @@ -302,9 +302,12 @@ DataSources\IRemoteDesktopManager.cs - - DataSources\ISearchResultRelationProvider.cs - + + DataSources\ISearchResultRelationProvider.cs + + + DataSources\ITicketActivityProvider.cs + F4SDConfigGlobalParametersXml.cs @@ -381,4 +384,4 @@ - \ No newline at end of file + diff --git a/C4IT_DataHistoryProvider_Test/Config/F4SD-Global-Configuration.xml b/C4IT_DataHistoryProvider_Test/Config/F4SD-Global-Configuration.xml index 5b3fbaa..437d50f 100644 --- a/C4IT_DataHistoryProvider_Test/Config/F4SD-Global-Configuration.xml +++ b/C4IT_DataHistoryProvider_Test/Config/F4SD-Global-Configuration.xml @@ -24,6 +24,22 @@ + + + + + + + + + + + + + + + + diff --git a/C4IT_DataHistoryProvider_Test/Config/F4SD-Global-Configuration.xsd b/C4IT_DataHistoryProvider_Test/Config/F4SD-Global-Configuration.xsd index 3d01823..dda5729 100644 --- a/C4IT_DataHistoryProvider_Test/Config/F4SD-Global-Configuration.xsd +++ b/C4IT_DataHistoryProvider_Test/Config/F4SD-Global-Configuration.xsd @@ -132,6 +132,21 @@ + + + + + + + + + + + + + + + @@ -182,6 +197,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/C4IT_DataHistoryProvider_Test/Config/F4SD-Infrastructure-Configuration.xml b/C4IT_DataHistoryProvider_Test/Config/F4SD-Infrastructure-Configuration.xml index 3bb761d..eed8339 100644 --- a/C4IT_DataHistoryProvider_Test/Config/F4SD-Infrastructure-Configuration.xml +++ b/C4IT_DataHistoryProvider_Test/Config/F4SD-Infrastructure-Configuration.xml @@ -82,15 +82,11 @@ - + M42 Demo Server (Imagoverum) - - - - - + diff --git a/F4SD-Cockpit-ServerCore/DataHistoryCollector.cs b/F4SD-Cockpit-ServerCore/DataHistoryCollector.cs index 3b1fe00..1b5c25f 100644 --- a/F4SD-Cockpit-ServerCore/DataHistoryCollector.cs +++ b/F4SD-Cockpit-ServerCore/DataHistoryCollector.cs @@ -276,7 +276,8 @@ namespace C4IT.DataHistoryProvider public readonly Dictionary Connectors = new Dictionary(); public readonly cDataHistoryCollectorActiveDirectory ActiveDirectory = null; public readonly cDataHistoryCollectorClientAgent F4sdAgent = null; - public cDataHistoryCollectorM42Wpm M42WpmCollector { get; private set; } = null; + public cDataHistoryCollectorM42Wpm M42WpmCollector { get; private set; } = null; + public ITicketActivityProvider TicketActivityProvider { get; private set; } = null; public cDataHistoryCollectorNxql NxqlCollector { get; private set; } = null; public cDataHistoryCollectorCitrix CitrixCollector { get; private set; } = null; //public cDataHistoryCollectorEmpirum EmpirumCollector { get; private set; } = null; @@ -409,10 +410,12 @@ namespace C4IT.DataHistoryProvider GlobalParametersConfigFile = _cfgGlobalParameters; - GlobalConfig = new cF4sdGlobalConfig(regPath: null); - if (GlobalParametersConfigFile.Parameters != null) - GlobalConfig.Load(CentralParameters: GlobalParametersConfigFile.Parameters); - } + GlobalConfig = new cF4sdGlobalConfig(regPath: null); + if (GlobalParametersConfigFile.Parameters != null) + GlobalConfig.Load(CentralParameters: GlobalParametersConfigFile.Parameters); + GlobalConfig.TicketConfiguration.ActivityFilters = + GlobalParametersConfigFile.ActivityFilters ?? new cActivityFilterPolicy(); + } return true; } @@ -514,8 +517,9 @@ namespace C4IT.DataHistoryProvider if (cF4SDLicense.Instance?.Modules != null) if (cF4SDLicense.Instance.Modules.ContainsKey(_M42WpmCollector.LicenseId)) { - M42WpmCollector = _M42WpmCollector; - Connectors.Add(enumDataHistoryOrigin.M42Wpm, M42WpmCollector); + M42WpmCollector = _M42WpmCollector; + TicketActivityProvider = _M42WpmCollector; + Connectors.Add(enumDataHistoryOrigin.M42Wpm, M42WpmCollector); RegisterSearchRelationProvider(_M42WpmCollector); } } diff --git a/F4SD-Cockpit-ServerCore/DataHistoryCollectorM42Wpm.cs b/F4SD-Cockpit-ServerCore/DataHistoryCollectorM42Wpm.cs index 19aa0db..b9462b5 100644 --- a/F4SD-Cockpit-ServerCore/DataHistoryCollectorM42Wpm.cs +++ b/F4SD-Cockpit-ServerCore/DataHistoryCollectorM42Wpm.cs @@ -2,8 +2,9 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Net.Http; +using System.Linq; +using System.Net; +using System.Net.Http; using System.Numerics; using System.Reflection; using System.Security.Principal; @@ -31,14 +32,17 @@ using static C4IT.Matrix42.WebClient.cM42WebClient; namespace C4IT.DataHistoryProvider { - public class cDataHistoryCollectorM42Wpm : cDataHistoryCollectorModule, ISearchResultRelationProvider + public class cDataHistoryCollectorM42Wpm : cDataHistoryCollectorModule, ISearchResultRelationProvider, ITicketActivityProvider { public const string constConnectorName = "Matrix42 WPM conntector"; public const string constLicenseId = "9CE1A6BE-6A0C-4A27-94A5-44AB997B8E62"; private const string constUrlIsAlive = "m42Services/api/c4itf4sdwebapi/isalive"; - private const string constUrlGetTickets = "m42Services/api/c4itf4sdwebapi/getticketlist?sid={0}&hours={1}&queueoption={2}"; - private const string constUrlGetTicketsQueuesParam = "&queues={0}"; + private const string constUrlGetTickets = "m42Services/api/c4itf4sdwebapi/getticketlist?sid={0}&hours={1}&queueoption={2}"; + private const string constUrlGetTicketsQueuesParam = "&queues={0}"; + private const string constUrlGetTicketsV2 = "m42Services/api/c4itf4sdwebapi/v2/getticketlist"; + private const string constUrlGetTicketOverviewCountsV2 = "m42Services/api/c4itf4sdwebapi/v2/getticketoverviewcounts"; + private const string constUrlGetTicketOverviewRelationsV2 = "m42Services/api/c4itf4sdwebapi/v2/getticketoverviewrelations"; private const string constUrlGetTicketDetails = "m42Services/api/c4itf4sdwebapi/getticketdetails?objectid={0}"; private const string constUrlGetTicketHistory = "m42Services/api/c4itf4sdwebapi/gettickethistory?objectid={0}"; private const string constUrlGetCreateTicket = "m42Services/api/c4itf4sdwebapi/getdirectlinkcreateticket?sid={0}{1}"; @@ -687,24 +691,33 @@ namespace C4IT.DataHistoryProvider if (!await CheckOnline()) return null; - var objSid = new SecurityIdentifier(UserId.sid, 0); - var strSid = objSid.ToString(); - var queueOption = (int)Collector.InfrastructureConfig.M42Wpm.ActivityQueueFilterOption; - var strUrl = string.Format(constUrlGetTickets, - strSid, - Collector.InfrastructureConfig.M42Wpm.ClosedTicketHistory, - queueOption); - - if (queueOption != 0) - { - var encodedQueues = GetEncodedActivityQueues(); - if (!string.IsNullOrWhiteSpace(encodedQueues)) - strUrl += string.Format(constUrlGetTicketsQueuesParam, encodedQueues); - } - - var _wc = await GetWebClient(requestInfo, Token); - var res = await _wc.HttpEnh.GetAsync(strUrl); - if (res.IsSuccessStatusCode) + var objSid = new SecurityIdentifier(UserId.sid, 0); + var strSid = objSid.ToString(); + var _wc = await GetWebClient(requestInfo, Token); + var request = new cTicketActivityListRequest + { + Sid = strSid, + Hours = Collector.InfrastructureConfig.M42Wpm.ClosedTicketHistory, + Filters = GetActivityFilters() + }; + var res = await PostJsonAsync(_wc, constUrlGetTicketsV2, request, Token); + if (res?.StatusCode == HttpStatusCode.NotFound) + { + if (!TryGetLegacyQueueFilter(out var queueOption, out var encodedQueues)) + { + LogEntry("The activity filter policy requires the v2 ticket API; legacy fallback was rejected (fail closed).", LogLevels.Warning); + return null; + } + var strUrl = string.Format( + constUrlGetTickets, + strSid, + Collector.InfrastructureConfig.M42Wpm.ClosedTicketHistory, + queueOption); + if (!string.IsNullOrWhiteSpace(encodedQueues)) + strUrl += string.Format(constUrlGetTicketsQueuesParam, encodedQueues); + res = await _wc.HttpEnh.GetAsync(strUrl); + } + if (res?.IsSuccessStatusCode == true) { var strJson = await res.Content.ReadAsStringAsync(); if (!string.IsNullOrEmpty(strJson)) @@ -1093,12 +1106,76 @@ namespace C4IT.DataHistoryProvider return filtered; } - private int GetActivityQueueOption() - { - return (int)Collector.InfrastructureConfig.M42Wpm.ActivityQueueFilterOption; - } - - private string GetEncodedActivityQueues() + private int GetActivityQueueOption() + { + return (int)Collector.InfrastructureConfig.M42Wpm.ActivityQueueFilterOption; + } + + private cActivityFilterPolicy GetActivityFilters() + { + return Collector?.GetGlobalConfig()?.TicketConfiguration?.ActivityFilters + ?? new cActivityFilterPolicy(); + } + + private bool TryGetLegacyQueueFilter(out int queueOption, out string encodedQueues) + { + queueOption = 0; + encodedQueues = null; + var activeFilters = (GetActivityFilters()?.Filters ?? new List()) + .Where(entry => entry?.Enabled == true) + .ToList(); + if (activeFilters.Count == 0) + return true; + if (activeFilters.Count != 1) + return false; + + var activityFilter = activeFilters[0]; + if (!string.Equals(activityFilter.Provider, "Matrix42", StringComparison.OrdinalIgnoreCase) + || !string.Equals(activityFilter.Field, "Queue", StringComparison.OrdinalIgnoreCase) + || activityFilter.Match != enumActivityFilterMatch.include + || activityFilter.EmptyHandling == enumActivityFilterEmptyHandling.only) + { + return false; + } + + queueOption = activityFilter.EmptyHandling == enumActivityFilterEmptyHandling.include ? 1 : 2; + var values = (activityFilter.Values ?? new List()) + .Where(value => value != null) + .Select(value => + { + if (Guid.TryParse(value.ID, out var id) && id != Guid.Empty) + return ":" + HttpUtility.UrlEncode(id.ToString("D")); + return string.IsNullOrWhiteSpace(value.Name) + ? null + : HttpUtility.UrlEncode(value.Name.Trim()); + }) + .Where(value => !string.IsNullOrWhiteSpace(value)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + if (values.Count == 0) + return false; + + encodedQueues = string.Join("|", values); + return true; + } + + private static Task PostJsonAsync( + cM42WebClient webClient, + string url, + object request, + CancellationToken token) + { + var json = JsonConvert.SerializeObject( + request, + Formatting.None, + new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); + return webClient.HttpEnh.PostAsync( + url, + new StringContent(json, Encoding.UTF8, "application/json"), + token); + } + + private string GetEncodedActivityQueues() { var queues = Collector.InfrastructureConfig.M42Wpm.ActivityQueues; if (queues == null || queues.Count == 0) @@ -1140,28 +1217,36 @@ namespace C4IT.DataHistoryProvider string scope, IReadOnlyCollection requestedKeys, cF4sdWebRequestInfo requestInfo, - CancellationToken token) - { - try - { - var urlBuilder = new StringBuilder(constUrlGetTicketOverviewCounts); - urlBuilder.Append("?sid=").Append(HttpUtility.UrlEncode(sid)); - urlBuilder.Append("&scope=").Append(HttpUtility.UrlEncode(scope ?? string.Empty)); - - if (requestedKeys != null && requestedKeys.Count > 0) - { - urlBuilder.Append("&keys=").Append(HttpUtility.UrlEncode(string.Join(",", requestedKeys))); - } - - var queueOption = GetActivityQueueOption(); - var encodedQueues = queueOption != 0 ? GetEncodedActivityQueues() : null; - AppendQueueFilterQuery(urlBuilder, queueOption, encodedQueues); - - var url = urlBuilder.ToString(); - var wc = await GetWebClient(requestInfo, token); - var res = await wc.HttpEnh.GetAsync(url, token); - if (token.IsCancellationRequested) - return new Dictionary(StringComparer.OrdinalIgnoreCase); + CancellationToken token) + { + try + { + var wc = await GetWebClient(requestInfo, token); + var request = new cTicketOverviewFilterRequest + { + Sid = sid, + Scope = scope, + Keys = requestedKeys?.ToList() ?? new List(), + Filters = GetActivityFilters() + }; + var res = await PostJsonAsync(wc, constUrlGetTicketOverviewCountsV2, request, token); + if (res?.StatusCode == HttpStatusCode.NotFound) + { + if (!TryGetLegacyQueueFilter(out var queueOption, out var encodedQueues)) + { + LogEntry("The activity filter policy requires the v2 overview API; legacy fallback was rejected (fail closed).", LogLevels.Warning); + return new Dictionary(StringComparer.OrdinalIgnoreCase); + } + var urlBuilder = new StringBuilder(constUrlGetTicketOverviewCounts); + urlBuilder.Append("?sid=").Append(HttpUtility.UrlEncode(sid)); + urlBuilder.Append("&scope=").Append(HttpUtility.UrlEncode(scope ?? string.Empty)); + if (requestedKeys != null && requestedKeys.Count > 0) + urlBuilder.Append("&keys=").Append(HttpUtility.UrlEncode(string.Join(",", requestedKeys))); + AppendQueueFilterQuery(urlBuilder, queueOption, encodedQueues); + res = await wc.HttpEnh.GetAsync(urlBuilder.ToString(), token); + } + if (token.IsCancellationRequested) + return new Dictionary(StringComparer.OrdinalIgnoreCase); if (res?.IsSuccessStatusCode == true) { @@ -1227,64 +1312,12 @@ namespace C4IT.DataHistoryProvider if (string.IsNullOrWhiteSpace(sid)) return new Dictionary(StringComparer.OrdinalIgnoreCase); - var normalizedKeys = (keys ?? Enumerable.Empty()) - .Where(k => !string.IsNullOrWhiteSpace(k)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - var now = DateTime.UtcNow; - var ttl = GetTicketOverviewCacheDuration(useRoleScope); - - if (!useRoleScope) - { - // process thr personal scope - if (TryGetTicketOverviewPersonalCache(sid, now, out var cachedPersonal)) - return FilterTicketOverviewCounts(cachedPersonal, normalizedKeys); - - var counts = await FetchTicketOverviewCountsAsync(sid, "personal", normalizedKeys, requestInfo, Token); - if (Token.IsCancellationRequested) - return new Dictionary(StringComparer.OrdinalIgnoreCase); - - SetTicketOverviewPersonalCache(sid, counts, now.Add(ttl)); - return FilterTicketOverviewCounts(counts, normalizedKeys); - } - - // process the role scope - var roleIds = await GetTicketOverviewRoleIdsAsync(sid, now, ttl, Token); - if (roleIds == null || roleIds.Count == 0) - return new Dictionary(StringComparer.OrdinalIgnoreCase); - - var countsByRole = new Dictionary>(); - var missingRoles = new List(); - - foreach (var roleId in roleIds) - { - if (TryGetTicketOverviewRoleCache(roleId, now, out var cachedRole)) - { - countsByRole[roleId] = cachedRole; - } - else - { - missingRoles.Add(roleId); - } - } - - if (missingRoles.Count > 0) - { - var fetched = await FetchTicketOverviewCountsByRolesAsync(missingRoles, normalizedKeys, requestInfo, LogDeep + 1, Token); - var expiresAt = DateTime.UtcNow.Add(ttl); - - foreach (var roleId in missingRoles) - { - if (!fetched.TryGetValue(roleId, out var roleCounts)) - roleCounts = new Dictionary(StringComparer.OrdinalIgnoreCase); - - SetTicketOverviewRoleCache(roleId, roleCounts, expiresAt); - countsByRole[roleId] = roleCounts; - } - } - - var summed = SumTicketOverviewCounts(countsByRole.Values); - return FilterTicketOverviewCounts(summed, normalizedKeys); + var normalizedKeys = (keys ?? Enumerable.Empty()) + .Where(k => !string.IsNullOrWhiteSpace(k)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + var scope = useRoleScope ? "role" : "personal"; + return await FetchTicketOverviewCountsAsync(sid, scope, normalizedKeys, requestInfo, Token); } catch (Exception E) { @@ -1314,26 +1347,37 @@ namespace C4IT.DataHistoryProvider return new List(); var sid = requestInfo?.userInfo?.AdSid; - if (string.IsNullOrWhiteSpace(sid)) - return new List(); - - var scope = useRoleScope ? "role" : "personal"; - var urlBuilder = new StringBuilder(constUrlGetTicketOverviewRelations); - urlBuilder.Append("?sid=").Append(HttpUtility.UrlEncode(sid)); - urlBuilder.Append("&scope=").Append(HttpUtility.UrlEncode(scope)); - urlBuilder.Append("&key=").Append(HttpUtility.UrlEncode(key)); - urlBuilder.Append("&count=").Append(Math.Max(0, count)); - - var queueOption = GetActivityQueueOption(); - var encodedQueues = queueOption != 0 ? GetEncodedActivityQueues() : null; - AppendQueueFilterQuery(urlBuilder, queueOption, encodedQueues); - - var url = urlBuilder.ToString(); - - var wc = await GetWebClient(requestInfo, Token); - var res = await wc.HttpEnh.GetAsync(url, Token); - if (Token.IsCancellationRequested) - return new List(); + if (string.IsNullOrWhiteSpace(sid)) + return new List(); + + var scope = useRoleScope ? "role" : "personal"; + var wc = await GetWebClient(requestInfo, Token); + var request = new cTicketOverviewFilterRequest + { + Sid = sid, + Scope = scope, + Key = key, + Count = Math.Max(0, count), + Filters = GetActivityFilters() + }; + var res = await PostJsonAsync(wc, constUrlGetTicketOverviewRelationsV2, request, Token); + if (res?.StatusCode == HttpStatusCode.NotFound) + { + if (!TryGetLegacyQueueFilter(out var queueOption, out var encodedQueues)) + { + LogEntry("The activity filter policy requires the v2 relation API; legacy fallback was rejected (fail closed).", LogLevels.Warning); + return new List(); + } + var urlBuilder = new StringBuilder(constUrlGetTicketOverviewRelations); + urlBuilder.Append("?sid=").Append(HttpUtility.UrlEncode(sid)); + urlBuilder.Append("&scope=").Append(HttpUtility.UrlEncode(scope)); + urlBuilder.Append("&key=").Append(HttpUtility.UrlEncode(key)); + urlBuilder.Append("&count=").Append(Math.Max(0, count)); + AppendQueueFilterQuery(urlBuilder, queueOption, encodedQueues); + res = await wc.HttpEnh.GetAsync(urlBuilder.ToString(), Token); + } + if (Token.IsCancellationRequested) + return new List(); if (res?.IsSuccessStatusCode == true) { diff --git a/F4SD-Cockpit-ServerCore/DataHistoryConfigGolabalParameters.cs b/F4SD-Cockpit-ServerCore/DataHistoryConfigGolabalParameters.cs index 0151aa4..d4252ef 100644 --- a/F4SD-Cockpit-ServerCore/DataHistoryConfigGolabalParameters.cs +++ b/F4SD-Cockpit-ServerCore/DataHistoryConfigGolabalParameters.cs @@ -1,7 +1,10 @@ using System; -using System.Collections.Generic; -using System.Reflection; -using System.Xml; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Security; +using System.Text; +using System.Xml; using Newtonsoft.Json; @@ -21,7 +24,8 @@ namespace C4IT.DataHistoryProvider private const string constFileNameF4sdSchema = "F4SD-Global-Configuration.xsd"; private const string constConfigRootElement = "F4SD-Global-Configuration"; - public cConfigHelperParameterList Parameters { get; private set; } = null; + public cConfigHelperParameterList Parameters { get; private set; } = null; + public cActivityFilterPolicy ActivityFilters { get; private set; } = new cActivityFilterPolicy(); private cDataHistoryConfigInfrastructure InfrastructureConfig = null; @@ -102,12 +106,15 @@ namespace C4IT.DataHistoryProvider if (_overrideValues != null && _overrideValues.ValueList != null && _overrideValues.ValueList.Count > 0) _result.Items[_overrideValues.Name] = _overrideValues; continue; - case "TicketProcessing": - var _ticketProcessingEntry = getTicketProcessingEntry(_item, Parser); - if (_ticketProcessingEntry != null) - _result.Items[_ticketProcessingEntry.Name] = _ticketProcessingEntry; - continue; - } + case "TicketProcessing": + var _ticketProcessingEntry = getTicketProcessingEntry(_item, Parser); + if (_ticketProcessingEntry != null) + _result.Items[_ticketProcessingEntry.Name] = _ticketProcessingEntry; + continue; + case "ActivityFilters": + ActivityFilters = getActivityFilters(_item, Parser); + continue; + } if (_attPolicy != null && _attValue != null && _ElementCount == 0) { @@ -156,8 +163,89 @@ namespace C4IT.DataHistoryProvider if (CM != null) LogMethodEnd(CM); } - return _result; - } + return _result; + } + + private static cActivityFilterPolicy getActivityFilters(XmlElement node, cXmlParser parser) + { + var result = new cActivityFilterPolicy(); + foreach (XmlElement filterNode in node.SelectNodes("Filter").OfType()) + { + parser.EnterElement(filterNode.Name); + try + { + if (!Enum.TryParse(filterNode.GetAttribute("Match"), true, out enumActivityFilterMatch match)) + match = enumActivityFilterMatch.exclude; + if (!Enum.TryParse(filterNode.GetAttribute("EmptyHandling"), true, out enumActivityFilterEmptyHandling emptyHandling)) + emptyHandling = enumActivityFilterEmptyHandling.include; + + var filter = new cActivityFilter + { + Provider = filterNode.GetAttribute("Provider"), + Field = filterNode.GetAttribute("Field"), + Enabled = bool.TryParse(filterNode.GetAttribute("Enabled"), out var enabled) && enabled, + Match = match, + EmptyHandling = emptyHandling + }; + + foreach (XmlElement valueNode in filterNode.SelectNodes("Value").OfType()) + { + filter.Values.Add(new cActivityFilterValue + { + ID = valueNode.GetAttribute("ID"), + Name = valueNode.GetAttribute("Name") + }); + } + + result.Filters.Add(filter); + } + finally + { + parser.LeaveElement(filterNode.Name); + } + } + + return result; + } + + private string getDefaultActivityFiltersXml() + { + var queueOption = InfrastructureConfig?.M42Wpm?.ActivityQueueFilterOption + ?? enumActivityQueueFilterOptions.showAll; + var queues = InfrastructureConfig?.M42Wpm?.ActivityQueues + ?? new List(); + var enableQueueFilter = queueOption != enumActivityQueueFilterOptions.showAll && queues.Count > 0; + var emptyHandling = queueOption == enumActivityQueueFilterOptions.onlyListedQueues + ? enumActivityFilterEmptyHandling.exclude + : enumActivityFilterEmptyHandling.include; + + var xml = new StringBuilder(); + xml.Append(""); + xml.AppendFormat( + "", + enableQueueFilter.ToString().ToLowerInvariant(), + emptyHandling); + foreach (var queue in queues.Where(queue => queue != null)) + { + xml.AppendFormat( + "", + queue.QueueID == Guid.Empty ? string.Empty : queue.QueueID.ToString("D"), + SecurityElement.Escape(queue.QueueName ?? string.Empty)); + } + xml.Append(""); + xml.Append(""); + xml.Append(""); + xml.Append(""); + xml.Append(""); + xml.Append(""); + xml.Append(""); + xml.Append(""); + xml.Append(""); + xml.Append(""); + xml.Append(""); + xml.Append(""); + return xml.ToString(); + } private cConfigHelperParameterEntry getInformationClassSearchPriority(XmlElement XNode, cXmlParser Parser) { @@ -487,11 +575,16 @@ namespace C4IT.DataHistoryProvider , "ShowOverview" , "" ); - RetVal |= DoXmlInsertElement(XmlRoot - , "TicketConfiguration" - , "TicketProcessing" - , "" - ); + RetVal |= DoXmlInsertElement(XmlRoot + , "TicketConfiguration" + , "TicketProcessing" + , "" + ); + RetVal |= DoXmlInsertElement(XmlRoot + , "TicketConfiguration" + , "ActivityFilters" + , getDefaultActivityFiltersXml() + ); RetVal |= DoXmlRemoveElement(XmlRoot , "TicketConfiguration" , "OpenActivitiesExternally" diff --git a/F4SD-Cockpit-ServerCore/DataHistoryConfigInfrastructure.cs b/F4SD-Cockpit-ServerCore/DataHistoryConfigInfrastructure.cs index b0c910b..32a039e 100644 --- a/F4SD-Cockpit-ServerCore/DataHistoryConfigInfrastructure.cs +++ b/F4SD-Cockpit-ServerCore/DataHistoryConfigInfrastructure.cs @@ -49,7 +49,7 @@ namespace C4IT.DataHistoryProvider { } - public override bool InstantiateProperties(XmlElement XRoot, cXmlParser Parser) + public override bool InstantiateProperties(XmlElement XRoot, cXmlParser Parser) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try @@ -118,9 +118,34 @@ namespace C4IT.DataHistoryProvider if (CM != null) LogMethodEnd(CM); } - return false; - } - } + return false; + } + + public override bool DoXmlUpdates(XmlElement xmlRoot, bool withM42Config = false, bool withIntuneConfig = false, bool withMobileDeviceConfig = false, bool withCitrixConfig = false) + { + // Queue filtering moved to the provider-neutral global ActivityFilters policy. + // InstantiateProperties runs first, so the values remain available for the + // one-time migration while the obsolete XML is removed. + if (!(xmlRoot.SelectSingleNode("Matrix42-WPM") is XmlElement matrix42)) + return false; + + var changed = false; + if (matrix42.HasAttribute("ActivityQueueFilter")) + { + matrix42.RemoveAttribute("ActivityQueueFilter"); + changed = true; + } + + var queues = matrix42.SelectSingleNode("Queues"); + if (queues != null) + { + matrix42.RemoveChild(queues); + changed = true; + } + + return changed; + } + } public class cDataHistoryConfigDatabase : IConfigNodeValidation { diff --git a/F4SD-Cockpit-ServerCore/DataSources/ITicketActivityProvider.cs b/F4SD-Cockpit-ServerCore/DataSources/ITicketActivityProvider.cs new file mode 100644 index 0000000..d530aa2 --- /dev/null +++ b/F4SD-Cockpit-ServerCore/DataSources/ITicketActivityProvider.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +using C4IT.DataHistoryProvider; +using C4IT.FASD.Base; + +namespace C4IT_DataHistoryProvider_Base.DataSources +{ + /// + /// Provider-neutral access to ticket-system activities used by search and overview. + /// Provider-specific filter fields remain opaque configuration values. + /// + public interface ITicketActivityProvider + { + bool TicketAndServiceRequestsEnabled { get; } + + Task> GetTicketsFromSid( + cF4sdConnectorIds userId, + CancellationToken token, + cF4sdWebRequestInfo requestInfo); + + Task> GetTicketOverviewCountsAsync( + IEnumerable keys, + bool useRoleScope, + cF4sdWebRequestInfo requestInfo, + int logDeep, + CancellationToken token); + + Task> GetTicketOverviewRelationsAsync( + string key, + bool useRoleScope, + int count, + cF4sdWebRequestInfo requestInfo, + int logDeep, + CancellationToken token); + } +} diff --git a/F4SDwebService/Config/F4SD-Global-Configuration.xml b/F4SDwebService/Config/F4SD-Global-Configuration.xml index 5b3fbaa..437d50f 100644 --- a/F4SDwebService/Config/F4SD-Global-Configuration.xml +++ b/F4SDwebService/Config/F4SD-Global-Configuration.xml @@ -24,6 +24,22 @@ + + + + + + + + + + + + + + + + diff --git a/F4SDwebService/Config/F4SD-Infrastructure-Configuration.xml b/F4SDwebService/Config/F4SD-Infrastructure-Configuration.xml index 3bb761d..eed8339 100644 --- a/F4SDwebService/Config/F4SD-Infrastructure-Configuration.xml +++ b/F4SDwebService/Config/F4SD-Infrastructure-Configuration.xml @@ -82,15 +82,11 @@ - + M42 Demo Server (Imagoverum) - - - - - + diff --git a/F4SDwebService/Controllers/TicketOverviewController.cs b/F4SDwebService/Controllers/TicketOverviewController.cs index 8ea78b4..898a0ac 100644 --- a/F4SDwebService/Controllers/TicketOverviewController.cs +++ b/F4SDwebService/Controllers/TicketOverviewController.cs @@ -39,7 +39,7 @@ namespace FasdWebService.Controllers return Ok(new TicketOverviewCountsResult()); } - var collector = WebApiApplication.Collector?.M42WpmCollector; + var collector = WebApiApplication.Collector?.TicketActivityProvider; if (collector == null) { return Ok(new TicketOverviewCountsResult()); @@ -95,7 +95,7 @@ namespace FasdWebService.Controllers return Ok(new List()); } - var collector = WebApiApplication.Collector?.M42WpmCollector; + var collector = WebApiApplication.Collector?.TicketActivityProvider; if (collector == null) { return Ok(new List()); diff --git a/F4SDwebService/Publish/Config/F4SD-Global-Configuration.xml b/F4SDwebService/Publish/Config/F4SD-Global-Configuration.xml index 5b3fbaa..437d50f 100644 --- a/F4SDwebService/Publish/Config/F4SD-Global-Configuration.xml +++ b/F4SDwebService/Publish/Config/F4SD-Global-Configuration.xml @@ -24,6 +24,22 @@ + + + + + + + + + + + + + + + + diff --git a/F4SDwebService/Publish/Config/F4SD-Global-Configuration.xsd b/F4SDwebService/Publish/Config/F4SD-Global-Configuration.xsd index 3d01823..dda5729 100644 --- a/F4SDwebService/Publish/Config/F4SD-Global-Configuration.xsd +++ b/F4SDwebService/Publish/Config/F4SD-Global-Configuration.xsd @@ -132,6 +132,21 @@ + + + + + + + + + + + + + + + @@ -182,6 +197,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/F4SDwebService/Publish/Config/F4SD-Infrastructure-Configuration.xml b/F4SDwebService/Publish/Config/F4SD-Infrastructure-Configuration.xml index 3bb761d..eed8339 100644 --- a/F4SDwebService/Publish/Config/F4SD-Infrastructure-Configuration.xml +++ b/F4SDwebService/Publish/Config/F4SD-Infrastructure-Configuration.xml @@ -82,15 +82,11 @@ - + M42 Demo Server (Imagoverum) - - - - - +