using C4IT.FASD.Base; using C4IT.Logging; using C4IT.Matrix42.WebClient; using C4IT.XML; using C4IT_DataHistoryProvider_Base.DataSources; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Reflection; using System.Security.Principal; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Web; using static C4IT.FASD.Base.cF4SDHealthCardRawData; using static C4IT.Logging.cLogManager; using static C4IT.Matrix42.WebClient.cM42WebClient; namespace C4IT.DataHistoryProvider { public class cDataHistoryCollectorM42Wpm : cDataHistoryCollectorModule, ISearchResultRelationProvider { 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}&queues={3}"; 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}"; private const string constUrlGetCreateTicketAssetParam = "&assetname={0}"; private const string constUrlUpdateSolution = "m42Services/api/c4itf4sdwebapi/updateactivitysolution/{0}/"; private const string constUrlGetPickupValues = "m42Services/api/c4itf4sdwebapi/getpickup/{0}?group={1}"; private const string constUrlGetRoleMeberships = "m42services/api/c4itf4sdwebapi/getrolememberships/?sid={0}"; private const string constUrlGetDataQueryRelationItems = "m42Services/api/dataquery/relationitems"; private const string constUrlGetDataQueryRelationItemsCount = "m42Services/api/dataquery/relationitems/count"; private const string constUrlCreateTicket = "m42Services/api/ticket/create?activitytype={0}"; private const string constUrlActivityGetQuickCallTemplateInfo = "m42Services/api/activity/quickcalltemplateinfo/{0}"; private const string constUrlCreateJournalEntry = "m42Services/api/journal/Add"; private const string constUrlFragmentsGetList = "m42Services/api/data/fragments/{0}?where={1}&columns={2}&pagesize={3}&pagenumber={4}&sort={5}"; private const string constUrlObjectsGetObject = "m42Services/api/data/objects/{0}/{1}?full={2}"; private const string constUrlObjectsUpdateObject = "m42Services/api/data/objects/{0}?full={1}"; private const string constUrlTicketClose = "m42Services/api/ticket/close"; private const string constUrlActivityPause = "m42Services/api/activity/Pause"; private const string constUrlActivityForward = "m42Services/api/activity/Forward"; private const string constUrlActivityTrackWorkingTime = "m42Services/api/activity/trackworkingtime"; private const string constUrlTicketTransform = "m42Services/api/ticket/transform"; private const string constUrlActivityReopen = "m42Services/api/activity/reopen"; private const string constUrlGenerateApiTokenForMe = "m42Services/api/apitoken/generateapitokenforme"; private const string constUrlGenerateAccessTokenFromApiToken = "m42Services/api/apitoken/generateaccesstokenfromapitoken"; public const string constTableNameTicketDetails = "M42Wpm-Tickets"; public const string constTableNameTicketHistory = "M42Wpm-Ticket-History"; public const string constTableNameUserTicket = "M42Wpm-User-NewTicket"; private readonly cM42WebClient WebClient = null; private Dictionary dicWebClients = new Dictionary(); private readonly Timer onlineTimer = null; private bool IsOnline = false; private Dictionary UserWebClientCache = new Dictionary(); private readonly cDataHistoryCollector _collector; private static class _OnlineCheckCriticalSection { public static SemaphoreSlim Semaphore = new SemaphoreSlim(1, 1); } private static class _LanguageDicWebClientCriticalSection { public static SemaphoreSlim Semaphore = new SemaphoreSlim(1, 1); } private struct WebClientCacheIndex { public Guid Id; public string Language; } private class WebClientCacheEntry { public cM42WebClient WebClient; public DateTime LastUsed; public DateTime ValidUntil; } public class cM42ApiTokenModel { public string ApiToken { get; set; } public string Name { get; set; } public bool? Enabled { get; set; } public DateTime? ValidUntil { get; set; } public string UserId { get; set; } } private class cApiTokenRequestModelBase { public string Name { get; set; } public int ExpirationDays { get; set; } } public cDataHistoryCollectorM42Wpm(cDataHistoryCollector Collector) : base(Collector, eDataHistoryOrigin.M42Wpm, constConnectorName, constLicenseId) { if (Collector.InfrastructureConfig.M42Wpm.Server == null) return; _collector = Collector; WebClient = new cM42WebClient(Collector.InfrastructureConfig.M42Wpm.Server); if (Collector.autoConnectionCheck) onlineTimer = new Timer(onlineTimerCallback, null, 0, 30000); } private async Task GetWebClient(cF4sdWebRequestInfo requestInfo, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { if (cLogManager.DefaultLogger.IsDebug) LogEntry($"M42 webclient culture: {requestInfo?.Culture?.TextInfo?.CultureName}", LogLevels.Debug); if (requestInfo?.Culture == null) { if (cLogManager.DefaultLogger.IsDebug) LogEntry($"M42 webclient requested with no culture", LogLevels.Debug); return WebClient; } await _LanguageDicWebClientCriticalSection.Semaphore.WaitAsync(Token); try { var _lang = requestInfo.Culture.TextInfo.CultureName; if (dicWebClients.TryGetValue(_lang, out var client)) { if (cLogManager.DefaultLogger.IsDebug) LogEntry($"M42 webclient request returned with culture: {client?.UserLanguage}", LogLevels.Debug); return client; } client = new cM42WebClient(Collector.InfrastructureConfig.M42Wpm.Server, _lang); var resLogon = await client.LogonWithApiKeyAsync(Collector.InfrastructureConfig.M42Wpm.Credential.NwCredential.Password); if (resLogon == cM42WebClient.eReason.ok) { dicWebClients[_lang] = client; if (cLogManager.DefaultLogger.IsDebug) LogEntry($"M42 webclient request returned with culture: {client?.UserLanguage}", LogLevels.Debug); return client; } else { LogEntry($"Could not logon to M42 server with culture {_lang}. Reason: {resLogon}", LogLevels.Warning); } } catch (Exception E) { LogException(E); } finally { _LanguageDicWebClientCriticalSection.Semaphore.Release(); } } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } if (cLogManager.DefaultLogger.IsDebug) LogEntry($"M42 webclient requested return with no culture.", LogLevels.Debug); return WebClient; } private async Task GetUserWebClient(cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { lock (requestInfo) if (requestInfo?.M42WebClient != null) return requestInfo.M42WebClient; if (requestInfo?.userInfo?.Id is null) return null; var _lang = requestInfo.Culture?.TextInfo?.CultureName; if (_lang == null) _lang = "en-Us"; var _index = new WebClientCacheIndex() { Id = requestInfo.userInfo.Id, Language = _lang }; lock (UserWebClientCache) { if (UserWebClientCache.TryGetValue(_index, out var _cacheEntry) && _cacheEntry.ValidUntil < DateTime.UtcNow + TimeSpan.FromMinutes(cDataHistoryCollector.constMinutesUntilTokenIsInvalid)) { _cacheEntry.LastUsed = DateTime.UtcNow; lock (requestInfo) requestInfo.M42WebClient = _cacheEntry.WebClient; return _cacheEntry.WebClient; } } if (Collector.TokenCache == null) return null; var _tokenInfo = await Collector.TokenCache.GetAsync(requestInfo.userInfo.Id, cF4SDTokenRegistration.enumTokenType.M42Bearer, requestInfo, LogDeep + 1); if (_tokenInfo == null || !_tokenInfo.IsValid()) return null; var client = new cM42WebClient(Collector.InfrastructureConfig.M42Wpm.Server, _lang); client.SetBearerToken(_tokenInfo.secret); var _reason = await client.Open(); if (_reason == eReason.ok) { lock (UserWebClientCache) { UserWebClientCache[_index] = new WebClientCacheEntry() { WebClient = client, LastUsed = DateTime.UtcNow, ValidUntil = _tokenInfo.validUntil }; } lock (requestInfo) requestInfo.M42WebClient = client; return client; } } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return null; } private void CleanupUserWebCache() { lock (UserWebClientCache) { var _del = new List(); foreach (var _entry in UserWebClientCache) if (_entry.Value.LastUsed < DateTime.UtcNow - TimeSpan.FromMinutes(10) || _entry.Value.ValidUntil < DateTime.UtcNow) _del.Add(_entry.Key); foreach (var entry in _del) UserWebClientCache.Remove(entry); } } public override async Task DoScanAsync(bool Always, bool Rescan, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool EnhancedDebug = false) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (Collector.M42WpmCollector is null) return false; Collector.DoProcessUiMessage(0, ""); if (!Always) { var scanInfo = await Collector.M42WpmCollector.GetScanTimeInfoAsync(requestInfo, LogDeep + 1, Token); if (scanInfo?.LastScan is DateTime _lastScan && scanInfo?.NextScan is DateTime _nextScan) { if (_lastScan >= _nextScan) { Collector.DoProcessUiMessage(0, $"currently no scan needed for M42 api token cleanup, lastScan={_lastScan} (UTC), nextScan={_nextScan} (UTC)"); return false; } } } await CleanupApiTokensAsync(Token); if (Token.IsCancellationRequested) return false; await Collector.SetLastScanTime("M42Scan-CleanupToken", DateTime.UtcNow, requestInfo, LogDeep + 1, Token); return true; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return true; } public override async Task> GetIds(cF4sdConnectorIds IdEntry, enumFasdInformationClass InfoClass, cF4sdWebRequestInfo requestInfo, int LogDeep) { await Task.CompletedTask; return new List() { IdEntry.Id }; } public override async Task GetScanTimeInfoAsync(cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var scanTiming = new cDataHistoryScanTiming() { IsValid = true, Interval = TimeSpan.FromDays(1), Offset = TimeSpan.FromHours(1), Timezone = TimeZoneInfo.Local }; return await GetScanTimeInfoAsync(scanTiming, "M42Scan-CleanupToken", requestInfo, LogDeep + 1, Token); } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } private async Task CheckLogonAsync(bool force, CancellationToken Token) { if (!force && WebClient.BearerToken != null) return true; MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { if (Collector.InfrastructureConfig.M42Wpm == null) return false; Collector.DoProcessUiMessage(0, ""); Collector.DoProcessUiMessage(0, $"Start estabishing M42 WPM connection to server {Collector.InfrastructureConfig.M42Wpm.Server}..."); var resLogon = await WebClient.LogonWithApiKeyAsync(Collector.InfrastructureConfig.M42Wpm.Credential.NwCredential.Password); if (resLogon == cM42WebClient.eReason.ok) { Collector.DoProcessUiMessage(0, "...M42 WPN connection established successful."); StartOnlineValidation(); return true; } Collector.DoProcessUiMessage(1, $"Logon failed: {resLogon}"); } catch (Exception E) { LogException(E); } finally { Collector.DoProcessUiMessage(0, ""); if (CM != null) LogMethodEnd(CM); } Collector.DoProcessUiMessage(0, "Error: Could not connect to M42 WPM."); return false; } public async Task ValidateConnectionAsync(bool forceLogon, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { await _OnlineCheckCriticalSection.Semaphore.WaitAsync(Token); try { var CheckResult = true; if (!IsOnline || forceLogon) CheckResult = await CheckLogonAsync(true, Token); if (CheckResult) { var resWeb = await WebClient.HttpEnh.GetAsync(constUrlIsAlive, Token); CheckResult = resWeb != null && resWeb.IsSuccessStatusCode; if (forceLogon) { if (CheckResult) Collector.DoProcessUiMessage(0, "...F4SD web api 'is alive' is reachable."); else Collector.DoProcessUiMessage(0, "Error: F4SD web api 'is alive' is not reachable. Maybe F4SD support is not installed or wrong version.", LogLevels.Error); } } IsOnline = CheckResult; if (onlineTimer != null) onlineTimer.Change(30000, 60000); return IsOnline; } catch (Exception E) { LogException(E); } finally { _OnlineCheckCriticalSection.Semaphore.Release(); } } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return false; } private enumTicketStatus ConvertM42TicketCode(int M42TicketStatus) { try { switch (M42TicketStatus) { case 200: return enumTicketStatus.New; case 201: case 202: return enumTicketStatus.InProgress; case 203: return enumTicketStatus.OnHold; case 204: return enumTicketStatus.Closed; } } catch (Exception E) { LogException(E); } return enumTicketStatus.Unknown; } public async Task> GetTicketsFromSid(cF4sdConnectorIds UserId, CancellationToken Token, cF4sdWebRequestInfo requestInfo) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { if (!await CheckOnline()) return null; var objSid = new SecurityIdentifier(UserId.sid, 0); var strSid = objSid.ToString(); string encodedQueues = string.Join("|", Collector.InfrastructureConfig.M42Wpm.ActivityQueues.Select(q => string.Format("{0}:{1}", HttpUtility.UrlEncode(q.QueueName), HttpUtility.UrlEncode(q.QueueID.ToString()) ) ) ); var strUrl = string.Format(constUrlGetTickets, strSid, Collector.InfrastructureConfig.M42Wpm.ClosedTicketHistory, (int)Collector.InfrastructureConfig.M42Wpm.ActivityQueueFilterOption, encodedQueues); var _wc = await GetWebClient(requestInfo, Token); var res = await _wc.HttpEnh.GetAsync(strUrl); if (res.IsSuccessStatusCode) { var strJson = await res.Content.ReadAsStringAsync(); if (!string.IsNullOrEmpty(strJson)) { var ticketInfoList = JsonConvert.DeserializeObject>(strJson); if (!(ticketInfoList?.Count > 0)) return null; foreach (var Entry in ticketInfoList) Entry.UserId = UserId.Id; return ticketInfoList; } } StartOnlineValidation(); } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return null; } public async Task> getTicketUsage(List lstTicketIds, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var lstTasks = new List>>(); foreach (var Entry in lstTicketIds) lstTasks.Add(GetTicketsFromSid(Entry, Token, requestInfo)); var result = await Task.WhenAll(lstTasks); if (result == null) return null; var retVal = new Dictionary(); foreach (var Entry in result) if (Entry != null) { foreach (var Entry2 in Entry) { if (Entry2.IsPrimaryAccount) retVal[Entry2.Name] = Entry2; else if (!retVal.ContainsKey(Entry2.Name)) retVal.Add(Entry2.Name, Entry2); } } if (retVal.Count > 0) { var ticketResult = new List(retVal.Count); foreach (var Entry in retVal.Values) { var Infos = new Dictionary() { { "Summary", Entry.Summary }, { "ActivityType", Entry.ActivityType }, { "Status", Entry.Status }, { "StatusId", ConvertM42TicketCode(Entry.StatusId).ToString() }, { "Asset", Entry.AssetName }, { "ServiceName", Entry.ServiceName }, { "ServiceId", Entry.ServiceId.ToString() }, { "AssetType", Entry.AssetCIName } }; var ticketInfo = new cF4sdApiSearchResultRelation() { Type = enumF4sdSearchResultClass.Ticket, Name = Entry.Name, DisplayName = Entry.Name, id = Entry.TicketObjectId, Status = enumF4sdSearchResultStatus.Active, Infos = Infos, Identities = new cF4sdIdentityList() { new cF4sdIdentityEntry(){ Class = enumFasdInformationClass.User, Id = Entry.UserId}, new cF4sdIdentityEntry(){ Class = enumFasdInformationClass.Ticket, Id = Entry.TicketObjectId} } }; ticketResult.Add(ticketInfo); } return ticketResult; } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public override async Task> GetTableResultsVirtualAsync(List Tables, Dictionary Identities, DateTime RefTime, int MaxAge, bool instantly, Guid? CacheId, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (!await CheckOnline()) return null; var bMainExists = Tables.Exists(v => v.Name == constTableNameTicketDetails && v.ParentCluster?.Origin == eDataHistoryOrigin.M42Wpm); var bHistoryExists = Tables.Exists(v => v.Name == constTableNameTicketHistory && v.ParentCluster?.Origin == eDataHistoryOrigin.M42Wpm); var bUserInfoExists = Tables.Exists(v => v.Name == constTableNameUserTicket && v.ParentCluster?.Origin == eDataHistoryOrigin.M42Wpm); var bPickupsExists = Tables.Exists(v => v.ParentCluster?.Origin == eDataHistoryOrigin.M42Wpm && v.SubTables?.Count == 1 && v.SubTables.Values.First().Template is cDataHistoryConfigQueryTemplateM42Pickup); if (!bMainExists && !bHistoryExists && !bUserInfoExists && !bPickupsExists) return null; if (!Identities.TryGetValue(enumFasdInformationClass.Ticket, out var idTicket)) { bMainExists = false; bHistoryExists = false; } if (!bMainExists && !bHistoryExists && !bUserInfoExists && !bPickupsExists) return null; var listTasks = new List>>(2); if (bMainExists && CacheId == null) listTasks.Add(Task.Run>(async () => { return await GetTicketMainTableAsync(idTicket.Id, requestInfo, LogDeep + 1, Token); })); if (bHistoryExists && (instantly || CacheId != null)) listTasks.Add(Task.Run>(async () => { return await GetTicketHistoryTableAsync(idTicket.Id, requestInfo, LogDeep + 1, Token); })); if (bUserInfoExists && (CacheId == null)) listTasks.Add(Task.Run>(async () => { return await GetUserTicketAsync(Identities, Token, requestInfo, LogDeep + 1); })); if (bPickupsExists && (instantly || CacheId != null)) { foreach (var _table in Tables) { if (_table.ParentCluster?.Origin != eDataHistoryOrigin.M42Wpm) continue; if (!(_table.SubTables.Values.First()?.Template is cDataHistoryConfigQueryTemplateM42Pickup)) continue; listTasks.Add(Task.Run>(async () => { return await GetUserPickupValuesAsync(_table, requestInfo, LogDeep + 1, Token); })); } } var arrRes = await Task.WhenAll(listTasks.ToArray()); var retVal = new List(); foreach (var Entry in arrRes) if (Entry != null) retVal.AddRange(Entry); // add the incomplete tables if (CacheId == null) { if (bHistoryExists) retVal.Add(new cF4SDHealthCardRawData.cHealthCardTable() { Name = constTableNameTicketHistory, InformationClass = enumFasdInformationClass.Ticket, IsIncomplete = true }); foreach (var _table in Tables) { if (_table.ParentCluster?.Origin != eDataHistoryOrigin.M42Wpm) continue; if (!(_table.SubTables.Values.First()?.Template is cDataHistoryConfigQueryTemplateM42Pickup)) continue; retVal.Add(new cF4SDHealthCardRawData.cHealthCardTable() { Name = _table.Name, InformationClass = _table.ParentCluster.InformationClass, IsIncomplete = true }); } } if (retVal.Count == 0) return null; return retVal; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } private async Task> GetTicketMainTableAsync(Guid TicketId, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (!Collector.ClusterConfig.Tables.TryGetValue(constTableNameTicketDetails, out var M42TableDetails)) return null; var strUrl = string.Format(constUrlGetTicketDetails, TicketId); var _wc = await GetWebClient(requestInfo, Token); var res = await _wc.HttpEnh.GetAsync(strUrl); if (cLogManager.DefaultLogger.IsDebug) LogEntry("SpecialDebug GetTicketMainTableAsync #1"); if (res?.IsSuccessStatusCode == true) { var strJson = await res.Content.ReadAsStringAsync(); if (!string.IsNullOrEmpty(strJson)) { if (cLogManager.DefaultLogger.IsDebug) LogEntry("SpecialDebug GetTicketMainTableAsync #2"); JObject ticketInfos = JsonConvert.DeserializeObject(strJson); var retVal = new cF4SDHealthCardRawData.cHealthCardTable() { Name = constTableNameTicketDetails, InformationClass = enumFasdInformationClass.Ticket, IsStatic = true, TableType = eDataHistoryTableType.Static }; var dicVals = new Dictionary(); var vals = ticketInfos.Children(); if (cLogManager.DefaultLogger.IsDebug) LogEntry("SpecialDebug GetTicketMainTableAsync #3"); foreach (var token in vals) { try { if (token is JProperty prop) if (prop.Value is JValue val) dicVals[prop.Name] = val.Value; } catch (Exception E) { LogEntry($"Error getting M42 ticket detail property '{token.Path}'", LogLevels.Error); LogException(E); } } if (cLogManager.DefaultLogger.IsDebug) LogEntry("SpecialDebug GetTicketMainTableAsync #4"); foreach (var colInfo in M42TableDetails.Columns.Values) { try { if (!dicVals.TryGetValue(colInfo.SourceName, out var objVal)) objVal = null; objVal = ConvertToF4sdType(objVal, colInfo.ValueType); var _col = new cF4SDHealthCardRawData.cHealthCardTableColumn() { ColumnName = colInfo.Name, Values = new List(1) { objVal } }; if (colInfo.IsWritable && colInfo.SourceName == "SolutionHtml") _col.IsWritable = true; retVal.Columns[colInfo.Name] = _col; } catch { } } if (cLogManager.DefaultLogger.IsDebug) LogEntry("SpecialDebug GetTicketMainTableAsync #5"); return new List(1) { retVal }; } else { LogEntry($"Could not get detailed ticket information for ticket wit id {TicketId}. Ticket content is empty.", LogLevels.Warning); } } else { cLogManager.DefaultLogger.LogHttpResponseMessage(res, $"Could not get detailed ticket information for ticket wit id {TicketId}.", LogLevels.Warning); } if (cLogManager.DefaultLogger.IsDebug) LogEntry("SpecialDebug GetTicketMainTableAsync #6"); StartOnlineValidation(); if (cLogManager.DefaultLogger.IsDebug) LogEntry("SpecialDebug GetTicketMainTableAsync #7"); } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } private object ConvertToF4sdType(object objVal, enumFasdValueType ValueType) { try { if (objVal != null) { switch (ValueType) { case enumFasdValueType.INT: return cF4SDHealthCardRawData.GetInteger(objVal); case enumFasdValueType.GUID: return cXmlParser.GetGuidFromString(objVal.ToString()); case enumFasdValueType.BOOLEAN: if (objVal == null) return false; if (objVal is bool) return (bool)objVal; if (objVal is int) return (int)objVal != 0; if (objVal is string) return bool.TryParse((string)objVal, out bool result) ? result : ((string)objVal == "1"); return false; // Standardrückgabewert, falls keine Bedingung zutrifft case enumFasdValueType.DATETIME: DateTime? dt = null; if (objVal is DateTime _dt) dt = _dt; else { if (DateTime.TryParse(objVal.ToString(), out _dt)) dt = _dt; } if (dt is DateTime _dt2) { if (_dt2 == new DateTime(1, 1, 1, 0, 0, 0)) dt = null; } return dt; default: return objVal.ToString(); } } } catch (Exception E) { LogException(E); } finally { } return null; } private async Task> GetTicketHistoryTableAsync(Guid TicketId, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (!Collector.ClusterConfig.Tables.TryGetValue(constTableNameTicketHistory, out var M42TableDetails)) return null; var strUrl = string.Format(constUrlGetTicketHistory, TicketId); var _wc = await GetWebClient(requestInfo, Token); var res = await _wc.HttpEnh.GetAsync(strUrl); if (res?.IsSuccessStatusCode == true) { var strJson = await res.Content.ReadAsStringAsync(); if (!string.IsNullOrEmpty(strJson)) { JContainer ticketInfos = JsonConvert.DeserializeObject(strJson); var retVal = new cF4SDHealthCardRawData.cHealthCardTable() { Name = constTableNameTicketHistory, InformationClass = enumFasdInformationClass.Ticket, IsStatic = false, TableType = eDataHistoryTableType.HistoryEvents }; var hLength = ticketInfos.Count; retVal.Columns = new Dictionary(M42TableDetails.Columns.Count); foreach (var colInfo in M42TableDetails.Columns.Values) { retVal.Columns[colInfo.Name] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { ColumnName = colInfo.Name, Values = new List(hLength) }; } foreach (var Entry in ticketInfos) { var dicVals = new Dictionary(); var vals = Entry.Children(); foreach (var token in vals) { try { if (token is JProperty prop) if (prop.Value is JValue val) dicVals[prop.Name] = val.Value; } catch (Exception E) { LogEntry($"Error getting M42 ticket detail property '{token.Path}'", LogLevels.Error); LogException(E); } } foreach (var col in M42TableDetails.Columns.Values) { if (!retVal.Columns.TryGetValue(col.Name, out var dataCol)) continue; if (dicVals.TryGetValue(col.SourceName, out var _val)) { _val = ConvertToF4sdType(_val, col.ValueType); dataCol.Values.Add(_val); } else dataCol.Values.Add(null); } } return new List(1) { retVal }; } } StartOnlineValidation(); } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } private async Task> GetUserTicketAsync(Dictionary Identities, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { // get table definition if (!Collector.ClusterConfig.Tables.TryGetValue(constTableNameUserTicket, out var tableConfig)) return null; // get the user sid if (!Identities.TryGetValue(enumFasdInformationClass.User, out var idUser)) return null; var strSid = new SecurityIdentifier(idUser.sid, 0).ToString(); // get the asset name, if computer is in Identities if (!Identities.TryGetValue(enumFasdInformationClass.Computer, out var idComuter)) idComuter = null; // create the api url var strOpt = ""; if (idComuter != null && !string.IsNullOrEmpty(idComuter.name)) strOpt = string.Format(constUrlGetCreateTicketAssetParam, HttpUtility.UrlEncode(idComuter.name)); var strUrl = string.Format(constUrlGetCreateTicket, HttpUtility.UrlEncode(strSid), strOpt); // call the api var _wc = await GetWebClient(requestInfo, Token); var res = await _wc.HttpEnh.GetAsync(strUrl); if (res?.IsSuccessStatusCode == true) { var strJson = await res.Content.ReadAsStringAsync(); if (!string.IsNullOrEmpty(strJson)) { // construct the result JObject ticketInfos = JsonConvert.DeserializeObject(strJson); var retVal = new cF4SDHealthCardRawData.cHealthCardTable() { Name = constTableNameUserTicket, InformationClass = enumFasdInformationClass.User, IsStatic = true, TableType = eDataHistoryTableType.Static }; var dicVals = new Dictionary(); var vals = ticketInfos.Children(); foreach (var token in vals) { try { if (token is JProperty prop) if (prop.Value is JValue val) dicVals[prop.Name] = val.Value; } catch (Exception E) { LogEntry($"Error getting M42 ticket detail property '{token.Path}'", LogLevels.Error); LogException(E); } } foreach (var colInfo in tableConfig.Columns.Values) { try { object objVal = null; if (colInfo.Name == "id") objVal = idUser.sid; else if (!dicVals.TryGetValue(colInfo.SourceName, out objVal)) objVal = null; objVal = ConvertToF4sdType(objVal, colInfo.ValueType); retVal.Columns[colInfo.Name] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { ColumnName = colInfo.Name, Values = new List(1) { objVal } }; } catch { } } return new List(1) { retVal }; } } StartOnlineValidation(); } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } private async Task> GetUserPickupValuesAsync(cDataHistoryConfigTable TableConfig, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (!(TableConfig?.SubTables.Count > 0)) return null; if (!(TableConfig.SubTables.Values.First().Template is cDataHistoryConfigQueryTemplateM42Pickup _template)) return null; // create the api url var colInfo = new List(); foreach (var _colInfo in TableConfig.Columns.Values) { colInfo.Add(_colInfo.SourceName); } var columns = string.Join(",", colInfo); var where = _template.FilteredGroup == -1 ? "" : string.Format("StateGroup = '{0}'", _template.FilteredGroup); var _strUrl = string.Format(constUrlFragmentsGetList, _template.PickupName, where, columns, string.Empty, string.Empty, string.Empty); _strUrl = RemoveEmptyQueryParameters(_strUrl); // call the api var _wc = await GetWebClient(requestInfo, Token); var res = await _wc.HttpEnh.GetAsync(_strUrl); if (res?.IsSuccessStatusCode == true) { var strJson = await res.Content.ReadAsStringAsync(); if (!string.IsNullOrEmpty(strJson)) { // construct the result JArray PickupResult = JsonConvert.DeserializeObject(strJson); var retVal = new cF4SDHealthCardRawData.cHealthCardTable() { Name = TableConfig.Name, InformationClass = enumFasdInformationClass.User, IsStatic = true, TableType = eDataHistoryTableType.Static }; var _dicColInfo = new Dictionary(TableConfig.Columns.Count); var _dicIndex = new Dictionary(TableConfig.Columns.Count); var _lstResultCols = new List(TableConfig.Columns.Count); var _idxPosition = -1; var _idxName = -1; var _i = 0; foreach (var _colInfo in TableConfig.Columns.Values) { var _col = new cF4SDHealthCardRawData.cHealthCardTableColumn() { ColumnName = _colInfo.Name }; retVal.Columns[_colInfo.Name] = _col; _dicColInfo[_colInfo.SourceName] = _colInfo; _dicIndex[_colInfo.SourceName] = _i; _lstResultCols.Add(_col); if (_colInfo.SourceName == "Position") _idxPosition = _i; if (_colInfo.SourceName == "DisplayString") _idxName = _i; _i++; } var _result = new List(); foreach (var _row in PickupResult) { var _s = _row.ToString(); try { // get the row values from JSON result var IdsValid = true; var _resultRow = new object[TableConfig.Columns.Count]; _resultRow.Initialize(); foreach (var _col in _row) { if (_col is JProperty prop) if (prop.Value is JValue val) { if (_dicColInfo.TryGetValue(prop.Name, out var _colInfo)) if (_dicIndex.TryGetValue(prop.Name, out var _idx)) { var objVal = ConvertToF4sdType(val.Value, _colInfo.ValueType); if (TableConfig.KeyColumns.Contains(_colInfo)) if (objVal == null || objVal is string _str && _str == string.Empty) IdsValid = false; _resultRow[_idx] = objVal; } } } if (!IdsValid) continue; _result.Add(_resultRow); } catch (Exception E) { LogEntry($"Error getting M42 pickup values for tale {TableConfig.Name} at '{_row}'", LogLevels.Error); LogException(E); } } // sort the result switch (_template.Sorting) { case cDataHistoryConfigQueryTemplateM42Pickup.enumSorting.byPosition: if (_idxPosition >= 0) try { _result.Sort((x, y) => { var xVal = x[_idxPosition]; var yVal = y[_idxPosition]; // Wenn x null ist und y nicht, soll y zuerst kommen (x ist also größer) if (xVal == null && yVal != null) return 1; // Wenn y null ist und x nicht, soll x zuerst kommen (x ist also kleiner) if (xVal != null && yVal == null) return -1; // Wenn beide null sind, sind sie gleich if (xVal == null && yVal == null) return 0; // Wenn keines der beiden null ist, normal vergleichen return ((Int32)xVal).CompareTo((Int32)yVal); }); } catch { } break; case cDataHistoryConfigQueryTemplateM42Pickup.enumSorting.byName: if (_idxName >= 0) try { _result.Sort((x, y) => ((string)(x[_idxName])).CompareTo((string)(y[_idxName]))); } catch { } break; } // put the result into the result colums foreach (var _entry in _result) { for (int _idx = 0; _idx < TableConfig.Columns.Count; _idx++) { var _col = _lstResultCols[_idx]; _col.Values.Add(_entry[_idx]); } } return new List(1) { retVal }; } } StartOnlineValidation(); } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public override bool CheckIfLateDelivery(cDataHistoryConfigTable Table) { if (Table.Name == constTableNameTicketHistory) return true; if (Table.SubTables?.First().Value?.Template is cDataHistoryConfigQueryTemplateM42Pickup) return true; return false; } public override async Task WritePropertyAsync(cF4SDWriteParameters PropertiesToWrite, cF4sdWebRequestInfo requestInfo, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { if (PropertiesToWrite.TableName != constTableNameTicketDetails) return false; if (PropertiesToWrite.Values.Count != 1) return false; if (!Collector.ClusterConfig.Tables.TryGetValue(constTableNameTicketDetails, out var tableConfig)) return false; if (!tableConfig.Columns.TryGetValue(PropertiesToWrite.Values.First().Key, out var colInfo)) return false; if (!colInfo.IsWritable) return false; var strSolution = JsonConvert.SerializeObject(PropertiesToWrite.Values.First().Value.ToString()); var _content = new StringContent(strSolution); var _url = string.Format(constUrlUpdateSolution, HttpUtility.UrlEncode(PropertiesToWrite.id.ToString())); var _wc = await GetWebClient(requestInfo, Token); var res = await _wc.HttpEnh.PostAsync(_url, _content, Token); if (res?.IsSuccessStatusCode == true) return true; StartOnlineValidation(); return false; } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return false; } private async void onlineTimerCallback(object state) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { CleanupUserWebCache(); await ValidateConnectionAsync(false, CancellationToken.None); } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } } private void StartOnlineValidation() { if (Collector?.autoConnectionCheck == true) _ = Task.Run(() => ValidateConnectionAsync(false, CancellationToken.None)); } public async Task CheckOnline() { await _OnlineCheckCriticalSection.Semaphore.WaitAsync(); try { return IsOnline; } catch (Exception E) { LogException(E); } finally { _OnlineCheckCriticalSection.Semaphore.Release(); } return false; } public async Task GetM42UserInfoAsync(string userSid, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { var strUrl = string.Format(constUrlGetRoleMeberships, userSid); var res = await WebClient.HttpEnh.GetAsync(strUrl, Token); if (Token.IsCancellationRequested) return null; if (res?.IsSuccessStatusCode == true) { var strJson = await res.Content.ReadAsStringAsync(); if (!string.IsNullOrEmpty(strJson)) { var _userInfo = JsonConvert.DeserializeObject(strJson); if (_userInfo?.User != null && _userInfo.User.Id != Guid.Empty) return _userInfo; } } } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return null; } private async Task> GetUserRoles(Guid UserId, CancellationToken Token, string ReportTag = null, bool logDetailed = false) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { var _QueryRelationInfo = new cM42DataQueryRelationInfo2() { EntityClassName = "SPSUserClassBase", EntityTypeName = "SPSSecurityTypeRole", FragmentId = UserId, columns = "Name", pageSize = 0, RelationName = "MemberOf" }; var _json = JsonConvert.SerializeObject(_QueryRelationInfo); var _content = new StringContent(_json, Encoding.UTF8, "application/json"); var _res = await WebClient.HttpEnh.PostAsync(constUrlGetDataQueryRelationItems, _content, Token); if (_res.IsSuccessStatusCode) { var _strResult = await _res.Content.ReadAsStringAsync(); if (string.IsNullOrEmpty(_strResult)) return null; List _roles = JsonConvert.DeserializeObject>(_strResult); var _retVal = new List(); foreach (var _roleEntry in _roles) { var _vals = _roleEntry.Children(); foreach (var _val in _vals) { try { if (_val is JProperty prop) { if (prop.Name == "Name") { var _propGroupName = prop.Value; if (prop.Value is JValue _jVal && _jVal.Value != null) { var _groupName = _jVal.Value.ToString(); _retVal.Add(_groupName); } } } } catch (Exception E) { LogException(E); } } } if (_retVal.Count > 0) return _retVal; } } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return null; } private async Task> GetF4SDRoles(Guid UserId, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { var _M42UserInfoRoles = await GetUserRoles(UserId, Token); if (_M42UserInfoRoles != null && _M42UserInfoRoles.Count > 0) { var _M42Memberships = Collector?.InfrastructureConfig?.Authorisation?.MembershipGroups?.GroupsM42; var _resMembershipGroups = new List(); if (_M42Memberships != null) { foreach (var _membership in Collector.InfrastructureConfig.Authorisation.MembershipGroups.GroupsM42.Values) { foreach (var _M42Role in _M42UserInfoRoles) { if (_M42Role.ToLowerInvariant() == _membership.RoleName.ToLowerInvariant()) if (!_resMembershipGroups.Contains(_membership)) _resMembershipGroups.Add(_membership); } } } return _resMembershipGroups; } } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return null; } public async Task AddM42UserInfosAsync(cF4sdUserInfo userInfo, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { // set M42 Logon to possible if (userInfo.possibleLogons == null) userInfo.possibleLogons = new List(); if (!userInfo.possibleLogons.Contains(enumAdditionalAuthentication.M42WinLogon)) userInfo.possibleLogons.Add(enumAdditionalAuthentication.M42WinLogon); // check, if the ad sid can be found in M42 var _M42UserInfo = await GetM42UserInfoAsync(userInfo.AdSid, Token); if (Token.IsCancellationRequested) return; // if yes, set M42 for an addidional automatic logon possibility if (_M42UserInfo?.User != null) { if (userInfo.additionalLogons == null) userInfo.additionalLogons = new List(); if (!userInfo.additionalLogons.Contains(enumAdditionalAuthentication.M42WinLogon)) userInfo.additionalLogons.Add(enumAdditionalAuthentication.M42WinLogon); } // check, if we have already a valid token for the user if (Collector.TokenCache != null) { // get the api token from token cache cM42UserInfoResult m42UserInfo = null; var _res = await Collector.TokenCache.GetAsync(userInfo.Id, cF4SDTokenRegistration.enumTokenType.M42Api, requestInfo, LogDeep + 1); if (_res != null && _res.IsValid()) { // check the api token, if it's still valid var _m42 = new cM42WebClient(Collector.InfrastructureConfig.M42Wpm.Server, UseSSL: true); var _m42Reason = await _m42.LogonWithApiKeyAsync(_res.secret, Token); if (_m42Reason == eReason.ok && _m42.BearerToken != null) { // get the user info m42UserInfo = await _m42.GetUserInfoAsync(); // save the new bearer token to token cache var TokenRegistration = new cF4SDTokenRegistration() { TokenType = cF4SDTokenRegistration.enumTokenType.M42Bearer, UserId = userInfo.Id, Secret = _m42.BearerToken }; // set the new bearer token into the token cache await Collector.TokenCache.SetAsync(TokenRegistration, GetTokenValidityPeriod(_m42.BearerLifeTime), Token, requestInfo, LogDeep + 1); if (Token.IsCancellationRequested) return; // set the valid until info if (userInfo.ValidLogonsUntil == null) userInfo.ValidLogonsUntil = new Dictionary(); userInfo.ValidLogonsUntil[enumAdditionalAuthentication.M42WinLogon] = cF4SDTokenValidityPeriod.Create(_res.validUntil, _res.renewUntil); } } else { // check, if there is a valid bearer token for M42 _res = await Collector.TokenCache.GetAsync(userInfo.Id, cF4SDTokenRegistration.enumTokenType.M42Bearer, requestInfo, LogDeep + 1); if (_res != null && _res.IsValid()) { // if yes, get the user info var _m42 = new cM42WebClient(Collector.InfrastructureConfig.M42Wpm.Server, UseSSL: true); _m42.SetBearerToken(_res.secret); var _res2 = await _m42.Open(); if (_res2 == eReason.ok) { m42UserInfo = await _m42.GetUserInfoAsync(); // set the valid until info if (userInfo.ValidLogonsUntil == null) userInfo.ValidLogonsUntil = new Dictionary(); userInfo.ValidLogonsUntil[enumAdditionalAuthentication.M42WinLogon] = cF4SDTokenValidityPeriod.Create(_res.validUntil, _res.renewUntil); } } } // get the role memberships relatet to the M42 roles if (m42UserInfo?.User?.Id != null) { var _F4SDRoles = await GetF4SDRoles((Guid)m42UserInfo.User.Id, Token); if (_F4SDRoles?.Count > 0) Collector.AddRolesByMembership(userInfo, _F4SDRoles); return; } } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } public override async Task GetSelectionTableResultCountAsync(cDataHistoryConfigTable Table, List Identities, string search, cF4sdWebRequestInfo requestInfo, CancellationToken Token, bool resetFilter = false, List filterParams = null) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { if (!(Table.SubTables.Values.First().Template is cDataHistoryConfigQueryTemplateM42DataQueryItems _template)) return -1; if (string.IsNullOrEmpty(search)) search = ""; string _whereExpr = null; if (!resetFilter && !string.IsNullOrEmpty(_template.WhereExpression)) { if (filterParams != null && filterParams.Count > 0) _whereExpr = string.Format(_template.WhereExpression, filterParams.ToArray()); else _whereExpr = _template.WhereExpression; } var _cols = Table.KeyColumns.First().SourceName; var _QueryRelationInfo = new cM42DataQueryRelationInfo() { EntityClassName = _template.EntityClassName, EntityTypeName = string.Join(",", _template.EntityTypeNames), search = search, WhereExpression = _whereExpr, pageSize = 0, page = 0, totalCounted = true, columns = _cols }; var _json = JsonConvert.SerializeObject(_QueryRelationInfo); var _content = new StringContent(_json, Encoding.UTF8, "application/json"); var _wc = await GetWebClient(requestInfo, Token); var res = await _wc.HttpEnh.PostAsync(constUrlGetDataQueryRelationItemsCount, _content); if (res.IsSuccessStatusCode) { var _strResult = await res.Content.ReadAsStringAsync(); if (Int64.TryParse(_strResult, out var count)) { return count; } } } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return -1; } public override async Task GetSelectionTableResultAsync(cDataHistoryConfigTable Table, List Identities, string search, int PageSize, int Page, cF4sdWebRequestInfo requestInfo, CancellationToken Token, bool resetFilter = false, List filterParams = null) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { if (!(Table.SubTables.Values.First().Template is cDataHistoryConfigQueryTemplateM42DataQueryItems _template)) return null; if (string.IsNullOrEmpty(search)) search = ""; string _whereExpr = null; if (!resetFilter && !string.IsNullOrEmpty(_template.WhereExpression)) { if (filterParams != null && filterParams.Count > 0) _whereExpr = string.Format(_template.WhereExpression, filterParams.ToArray()); else _whereExpr = _template.WhereExpression; } var _cols = Table.KeyColumns.First().SourceName; var _QueryRelationInfo = new cM42DataQueryRelationInfo() { EntityClassName = _template.EntityClassName, EntityTypeName = string.Join(",", _template.EntityTypeNames), WhereExpression = _whereExpr, search = search, pageSize = PageSize, page = Page, columns = _cols }; var _json = JsonConvert.SerializeObject(_QueryRelationInfo); var _content = new StringContent(_json, Encoding.UTF8, "application/json"); var _wc = await GetWebClient(requestInfo, Token); var res = await _wc.HttpEnh.PostAsync(constUrlGetDataQueryRelationItems, _content, Token); if (res.IsSuccessStatusCode) { var _strResult = await res.Content.ReadAsStringAsync(); if (string.IsNullOrEmpty(_strResult)) return null; List ticketInfos = JsonConvert.DeserializeObject>(_strResult); var _valueCount = ticketInfos.Count; var retVal = new cF4SDHealthCardRawData.cHealthCardTable() { Name = Table.Name, InformationClass = Table.ParentCluster.InformationClass, IsStatic = false, TableType = Table.Type }; var _dicColInfo = Table.Columns.ToDictionary(v => v.Value.SourceName, v => v.Value); foreach (var colInfo in Table.Columns.Values) { retVal.Columns[colInfo.Name] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { ColumnName = colInfo.Name, Values = new List(_valueCount) }; } foreach (var _entry in ticketInfos) { var _vals = _entry.Children(); var _maxCount = 0; foreach (var _token in _vals) { try { if (_token is JProperty prop) if (!string.IsNullOrEmpty(prop.Name) && prop.Value is JValue _val) { var _value = _val.Value; if (!_dicColInfo.TryGetValue(prop.Name, out var _colInfo)) continue; if (!retVal.Columns.TryGetValue(_colInfo.Name, out var _colData)) continue; _value = ConvertToF4sdType(_value, _colInfo.ValueType); _colData.Values.Add(_value); _maxCount = Math.Max(_maxCount, _colData.Values.Count); } } catch (Exception E) { LogEntry($"Error getting M42 ticket detail property '{_token?.Path}'", LogLevels.Error); LogException(E); } } foreach (var _colData in retVal.Columns.Values) { while (_colData.Values.Count < _maxCount) _colData.Values.Add(null); } } return retVal; } } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return null; } private cF4SDTokenValidityPeriod GetTokenValidityPeriod(DateTime validUntil) { var _renew = validUntil - TimeSpan.FromSeconds(Math.Max(0, (validUntil - DateTime.UtcNow).TotalSeconds * 2 / 10)); return cF4SDTokenValidityPeriod.Create(validUntil, _renew); } public override async Task ValidateTokenAsync(cF4SDTokenRegistration TokenRegistration, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (TokenRegistration?.TokenType is cF4SDTokenRegistration.enumTokenType.M42Bearer && !string.IsNullOrEmpty(Collector?.InfrastructureConfig?.M42Wpm.Server) && !string.IsNullOrEmpty(TokenRegistration?.Secret) ) { var _M42UserInfo = await cM42WebClient.LogonBearer(Collector.InfrastructureConfig.M42Wpm.Server, TokenRegistration.Secret, Token, UseSSL: true, LogDetailed: true); if (Token.IsCancellationRequested) return null; if (_M42UserInfo != null) { if (_M42UserInfo.BearerValidUntil > DateTime.UtcNow && TokenRegistration.AutoCreatePermanent && _M42UserInfo.User?.Id != null) { var _res2 = await CreateApiToken(TokenRegistration, _M42UserInfo, Token, requestInfo, LogDeep + 1); if (Token.IsCancellationRequested) return null; if (_res2 < DateTime.UtcNow) return null; } // user info & f4sd token aktualisieren var _validityPeriod = GetTokenValidityPeriod(_M42UserInfo.BearerValidUntil); var Roles = new List(); if (_M42UserInfo?.User?.Id != null) { var _F4SDRoles = await GetF4SDRoles((Guid)_M42UserInfo.User.Id, Token); if (_F4SDRoles?.Count > 0) Collector.AddRolesByMembership(Roles, _F4SDRoles, requestInfo?.userInfo?.Name); } var _retVal = new cF4SdUserInfoChange() { ValidLogonsUntil = new Dictionary { { enumAdditionalAuthentication.M42WinLogon, _validityPeriod } }, Roles = Roles }; return _retVal; } } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } private class cM42IdResult { public Guid Id { get; set; } public string Name { get; set; } } private async Task CreateApiToken(cF4SDTokenRegistration TokenRegistration, cM42UserInfoResult UserInfo, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { // obtain token name var tokenName = $"F4SD_{UserInfo.User.LastName ?? ""}_{UserInfo.User.FirstName ?? ""}_{UserInfo.User.Id}"; // create M42 web client var _m42 = new cM42WebClient(Collector.InfrastructureConfig.M42Wpm.Server, UseSSL: true); _m42.SetBearerToken(UserInfo.BearerToken); var _resOpen = await _m42.Open(); if (_resOpen != eReason.ok) return DateTime.MinValue; // check if token alsready exist var _strListToken = await _m42.GetFragmentListAsync("PLSTSApiTokenBase", Token, $"Name='{tokenName}'"); if (!string.IsNullOrEmpty(_strListToken)) { // remove all existing tokens with corresponding name var lstIds = JsonConvert.DeserializeObject>(_strListToken); foreach (var objId in lstIds) { var _delRequest = new Dictionary() { { objId.Id, "PLSTSApiTokenType" } }; await _m42.DeleteObjectsAsync("F4SD Cockpit", _delRequest, Token); if (Token.IsCancellationRequested) return DateTime.MinValue; } } // create token generation request var tokenRequest = new cApiTokenRequestModelBase() { Name = tokenName, ExpirationDays = (int)(Collector?.InfrastructureConfig?.M42Wpm?.ApiLifetime ?? cDataHistoryConfigM42Wpm.enumApiTokenLifetime.days30) }; // generate token var strJson = JsonConvert.SerializeObject(tokenRequest); var CO = new StringContent(strJson, Encoding.UTF8, "application/json"); var _resPost = await _m42.Http.PostAsync(constUrlGenerateApiTokenForMe, CO); if (Token.IsCancellationRequested) return DateTime.MinValue; var _content = await _resPost.Content.ReadAsStringAsync(); if (Token.IsCancellationRequested) return DateTime.MinValue; if (_resPost.IsSuccessStatusCode) { var _tokenModel = JsonConvert.DeserializeObject(_content); if (!string.IsNullOrEmpty(_tokenModel?.ApiToken) && _tokenModel?.ValidUntil >= DateTime.UtcNow) { var _validUntil = (DateTime)_tokenModel.ValidUntil; var _renewUntil = _validUntil - TimeSpan.FromDays(1); var _tr = new cF4SDTokenRegistration() { TokenType = cF4SDTokenRegistration.enumTokenType.M42Api, UserId = TokenRegistration.UserId, Name = _tokenModel?.Name, Secret = _tokenModel.ApiToken, AutoCreatePermanent = false }; await Collector.TokenCache.SetAsync(_tr, cF4SDTokenValidityPeriod.Create(_validUntil, _renewUntil), Token, requestInfo, LogDeep + 1); if (Token.IsCancellationRequested) return DateTime.MinValue; return _validUntil; } } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return DateTime.MinValue; } public async Task CreateM42TicketAsync(cApiM42Ticket ticketInfo, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var _webClient = await GetUserWebClient(requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested || _webClient == null) return null; var userFragmentListTask = GetFragmentListAsync(new cDataFragmentsParams { Columns = "ID", Ddname = "SPSUserClassBase", Pagenumber = 0, Pagesize = 10, Where = string.Format("T(SPSCommonClassbase).State = 2023 AND Accounts.T(SPSAccountClassAD).ADCn = '{0}'", ticketInfo.User) }, requestInfo, LogDeep + 1, token); List tasksToAwait = new List { userFragmentListTask }; Task assetFragmentListTask = null; if (!ticketInfo.AffectedAsset.Equals("RemoveAffectedAssetEntry", StringComparison.InvariantCultureIgnoreCase) && !string.IsNullOrEmpty(ticketInfo.AffectedAsset)) { assetFragmentListTask = GetFragmentListAsync(new cDataFragmentsParams { Columns = "ID", Ddname = "SPSAssetClassBase", Pagenumber = 0, Pagesize = 10, Where = string.Format("T(SPSCommonClassbase).State = 710 AND T(SPSComputerClassBase).Name = '{0}'", ticketInfo.AffectedAsset) }, requestInfo, LogDeep + 1, token); tasksToAwait.Add(assetFragmentListTask); } Task quickCallFragmentListTask = null; if (ticketInfo.Quickcall.HasValue && ticketInfo.Quickcall.Value != Guid.Empty) { quickCallFragmentListTask = GetQuickCallTemplateInfoAsync(ticketInfo.Quickcall.Value, requestInfo, LogDeep + 1, token); tasksToAwait.Add(quickCallFragmentListTask); } // Warte auf alle gestarteten Tasks await Task.WhenAll(tasksToAwait); var fragments = await userFragmentListTask; var idAsString = ""; Guid? assetId = null; var assetNotFound = false; if (assetFragmentListTask != null) { var assetFragments = await assetFragmentListTask; if (token.IsCancellationRequested) return null; if (assetFragments == null || assetFragments.Count == 0) { assetNotFound = true; } else { idAsString = (string)assetFragments?[0]?.ID; if (Guid.TryParse(idAsString, out Guid assetIdTemp)) { assetId = assetIdTemp; } else assetNotFound = true; } } idAsString = (string)fragments?[0]?.ID; if (!Guid.TryParse(idAsString, out Guid userID)) { LogEntry($"No initiating user found with state active (710) and AD Common Name: {ticketInfo.User}", LogLevels.Error); return null; } var ticketInfo2 = new cM42TicketInfo() { Subject = ticketInfo.Summary, DescriptionHTML = ticketInfo.DescriptionHtml, SolutionHTML = ticketInfo.SolutionHtml, User = userID, Asset = assetId, Service = ticketInfo.AffectedService, Template = ticketInfo.Quickcall, EntryBy = 20500 }; var quickCallFragments = await quickCallFragmentListTask; if (quickCallFragments != null) { var quickCallData = quickCallFragments; if (int.TryParse((string)quickCallData?.Impact, out int impact)) ticketInfo2.Impact = impact; if (int.TryParse((string)quickCallData?.Urgency, out int urgency)) ticketInfo2.Urgency = urgency; if (int.TryParse((string)quickCallData?.EntryBy, out int entryBy)) ticketInfo2.EntryBy = entryBy; if (int.TryParse((string)quickCallData?.ErrorType, out int errorType)) ticketInfo2.ErrorType = errorType; if (int.TryParse((string)quickCallData?.Priority, out int priority)) ticketInfo2.Priority = priority; if (Guid.TryParse((string)quickCallData?.RecipientRole, out Guid recipientRole)) ticketInfo2.ResponsibleRole = recipientRole; if (Guid.TryParse((string)quickCallData?.RecipientID, out Guid recipient)) ticketInfo2.ResponsibleUser = recipient; if (Guid.TryParse((string)quickCallData?.Asset, out Guid asset)) ticketInfo2.Asset = ticketInfo2.Asset ?? asset; if (Guid.TryParse((string)quickCallData?.Service, out Guid service)) ticketInfo2.Service = ticketInfo2.Service ?? service; if (Guid.TryParse((string)quickCallData?.Category, out Guid category)) ticketInfo2.Category = category; if (bool.TryParse((string)quickCallData?.NotifyResponsible, out bool notifyResponsible)) ticketInfo2.NotifyResponsible = notifyResponsible; if (int.TryParse((string)quickCallData?.Classification, out int Classification)) ticketInfo2.Classification = Classification; } var _jsonContent = JsonConvert.SerializeObject(ticketInfo2, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); var _content = new StringContent(_jsonContent, Encoding.UTF8, "application/json"); var url = string.Format(constUrlCreateTicket, ticketInfo2.Classification); var response = await _webClient.HttpEnh.PostAsync(url, _content, token); if (token.IsCancellationRequested) return null; if (response.IsSuccessStatusCode) { var json = await response.Content.ReadAsStringAsync(); Guid TicketId = Guid.TryParse(json?.Trim('"'), out TicketId) ? TicketId : Guid.Empty; await AddWorkingTimesAsync(TicketId, ticketInfo.workTimes, requestInfo, LogDeep + 1, token); cCreateJournalEntryInfo journalEntry = null; if (assetNotFound) { string assetNotFoundText = ""; if (ticketInfo.AdditionalValues.TryGetValue("Dialog.CloseCase.AssetNotFoundInMatrix42", out object valueObj)) { assetNotFoundText = valueObj as string; } if (!string.IsNullOrEmpty(assetNotFoundText)) { journalEntry = new cCreateJournalEntryInfo() { Comments = string.Format(assetNotFoundText, ticketInfo.AffectedAsset), ObjectId = TicketId, EntryType = 0 }; await CreateM42JournalAsync(journalEntry, requestInfo, LogDeep + 1, token); } } journalEntry = new cCreateJournalEntryInfo() { Comments = ticketInfo.CopyTemplates, ObjectId = TicketId, EntryType = 20600 }; await CreateM42JournalAsync(journalEntry, requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested) return null; if (ticketInfo.QuickActionHistory != null) foreach (var entry in ticketInfo.QuickActionHistory) { cCreateJournalEntryInfo _entry = null; switch (entry.ResultCode) { case -1: case 1: case 0: var entryType = entry.wasRunningOnAffectedDevice ? 20602 : 20601; _entry = new cCreateJournalEntryInfo() { Comments = "", ObjectId = TicketId, EntryType = entryType, Parameters = new List() { new cCreateJournalEntryInfo.Parameter() { Name = "result", Value = entry.Output ?? entry.MeasureValues ?? entry.ErrorMessage }, new cCreateJournalEntryInfo.Parameter() { Name = "quickActionName", Value = entry.QuickActionName }, new cCreateJournalEntryInfo.Parameter() { Name = "QuickActionId", Value = entry.QuickActionId }, new cCreateJournalEntryInfo.Parameter() { Name = "quickActionExecutionType", Value = entry.QuickActionExecutionType }, new cCreateJournalEntryInfo.Parameter() { Name = "ExecutionTime", Value = entry.ExecutionTime }, new cCreateJournalEntryInfo.Parameter() { Name = "AffectedDeviceName", Value = entry.AffectedDeviceName },} }; break; default: break; } if (_entry != null) { await CreateM42JournalAsync(_entry, requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested) return null; } } ticketInfo.Ticket = TicketId; await UpdateM42TicketUnreadAsync(ticketInfo, requestInfo, LogDeep + 1, token); return TicketId.ToString(); } } catch (Exception e) { LogException(e); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task UpdateM42TicketAsync(cApiM42Ticket ticketInfo, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var _webClient = await GetUserWebClient(requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested || _webClient == null) return null; string activityType = "SPSActivityTypeIncident"; if (ticketInfo.AdditionalValues.TryGetValue("ActivityType", out object value) && value is string stringValue) { activityType = stringValue; } var url = string.Format(constUrlObjectsUpdateObject, activityType, false); var ticketID = (Guid)ticketInfo.Ticket; var ticket = await GetObjectAsync(activityType, ticketID, false, requestInfo, LogDeep + 1, token); if (ticketInfo.Quickcall.HasValue && ticketInfo.Quickcall.Value != Guid.Empty) { ticket["SPSActivityClassIncident"]["Quickcall"] = ticketInfo.Quickcall.Value; } if (ticketInfo.AffectedService.HasValue && ticketInfo.AffectedService.Value == Guid.Empty) { ticket["SPSActivityClassBase"]["Service"] = null; } else if (ticketInfo.AffectedService.HasValue && ticketInfo.AffectedService.Value != Guid.Empty) ticket["SPSActivityClassBase"]["Service"] = ticketInfo.AffectedService.Value; var createAssetNotFoundJournalEntry = false; if (ticketInfo.AffectedAsset.Equals("RemoveAffectedAssetEntry", StringComparison.InvariantCultureIgnoreCase)) { ticket["SPSActivityClassIncident"]["Asset"] = null; } else if (!string.IsNullOrEmpty(ticketInfo.AffectedAsset)) { var assetNotFound = true; Guid? assetId = null; var assetFragments = await GetFragmentListAsync(new cDataFragmentsParams() { Columns = "ID", Ddname = "SPSAssetClassBase", Pagenumber = 0, Pagesize = 10, Where = string.Format("T(SPSCommonClassbase).State = 710 AND T(SPSComputerClassBase).Name = '{0}'", ticketInfo.AffectedAsset) }, requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested) return null; if (assetFragments == null || assetFragments.Count == 0) { assetNotFound = true; } else { var idAsString = (string)assetFragments?[0]?.ID; if (Guid.TryParse(idAsString, out Guid assetIdTemp)) { assetId = assetIdTemp; assetNotFound = false; } else { assetNotFound = true; } } if (assetNotFound) { createAssetNotFoundJournalEntry = true; } if (assetId != null) { ticket["SPSActivityClassBase"]["AffectedAsset"] = assetId; } } ticket["SPSActivityClassBase"]["Subject"] = ticketInfo.Summary; var _jsonContent = JsonConvert.SerializeObject(ticket, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); var _content = new StringContent(_jsonContent, Encoding.UTF8, "application/json"); var response = await _webClient.HttpEnh.PutAsync(url, _content, token); if (token.IsCancellationRequested) return null; if (response.IsSuccessStatusCode) { await AddWorkingTimesAsync(ticketID, ticketInfo.workTimes, requestInfo, LogDeep + 1, token); cCreateJournalEntryInfo _entry = null; if (createAssetNotFoundJournalEntry) { string assetNotFoundText = ""; if (ticketInfo.AdditionalValues.TryGetValue("Dialog.CloseCase.AssetNotFoundInMatrix42", out object valueObj)) { assetNotFoundText = valueObj as string; } if (!string.IsNullOrEmpty(assetNotFoundText)) { _entry = new cCreateJournalEntryInfo() { Comments = string.Format(assetNotFoundText, ticketInfo.AffectedAsset), ObjectId = ticketID, EntryType = 0 }; await CreateM42JournalAsync(_entry, requestInfo, LogDeep + 1, token); } } // Case Notes as Journal Entry if (!string.IsNullOrEmpty(ticketInfo.DescriptionHtml)) { _entry = new cCreateJournalEntryInfo() { Comments = ticketInfo.DescriptionHtml, ObjectId = ticketID, EntryType = 20603, }; await CreateM42JournalAsync(_entry, requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested) return null; } // CopyTemplates as Journal Entry if (!string.IsNullOrEmpty(ticketInfo.CopyTemplates)) { _entry = new cCreateJournalEntryInfo() { Comments = ticketInfo.CopyTemplates, ObjectId = ticketID, EntryType = 20604 }; await CreateM42JournalAsync(_entry, requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested) return null; } if (ticketInfo.QuickActionHistory != null) { foreach (var entry in ticketInfo.QuickActionHistory) { switch (entry.ResultCode) { case -1: case 1: case 0: var entryType = entry.wasRunningOnAffectedDevice ? 20602 : 20601; _entry = new cCreateJournalEntryInfo() { Comments = "", ObjectId = ticketID, EntryType = entryType, Parameters = new List() { new cCreateJournalEntryInfo.Parameter() { Name = "result", Value = entry.Output ?? entry.MeasureValues ?? entry.ErrorMessage }, new cCreateJournalEntryInfo.Parameter() { Name = "quickActionName", Value = entry.QuickActionName }, new cCreateJournalEntryInfo.Parameter() { Name = "QuickActionId", Value = entry.QuickActionId }, new cCreateJournalEntryInfo.Parameter() { Name = "quickActionExecutionType", Value = entry.QuickActionExecutionType }, new cCreateJournalEntryInfo.Parameter() { Name = "ExecutionTime", Value = entry.ExecutionTime }, new cCreateJournalEntryInfo.Parameter() { Name = "AffectedDeviceName", Value = entry.AffectedDeviceName },} }; break; default: break; } if (_entry != null) { await CreateM42JournalAsync(_entry, requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested) return null; } } } await UpdateM42TicketUnreadAsync(ticketInfo, requestInfo, LogDeep + 1, token); return string.Empty; } } catch (Exception e) { LogException(e); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task UpdateM42TicketUnreadAsync(cApiM42Ticket ticketInfo, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var _webClient = await GetUserWebClient(requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested || _webClient == null) return null; string activityType = "SPSActivityTypeIncident"; if (ticketInfo.AdditionalValues.TryGetValue("ActivityType", out object value) && value is string stringValue) { activityType = stringValue; } var url = string.Format(constUrlObjectsUpdateObject, activityType, false); var ticketID = (Guid)ticketInfo.Ticket; var ticket = await GetObjectAsync(activityType, ticketID, false, requestInfo, LogDeep + 1, token); if (ticket != null) { ticket["SPSActivityClassBase"]["NewInformationReceived"] = 0; var _jsonContent = JsonConvert.SerializeObject(ticket, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); var _content = new StringContent(_jsonContent, Encoding.UTF8, "application/json"); var response = await _webClient.HttpEnh.PutAsync(url, _content, token); if (token.IsCancellationRequested) return null; if (response.IsSuccessStatusCode) { //await Collector.ReportTicketAsync(ticketInfo, requestInfo, LogDeep + 1, token); return string.Empty; } } } catch (Exception e) { LogException(e); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task CloseM42TicketAsync(cApiM42Ticket ticketInfo, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var _webClient = await GetUserWebClient(requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested || _webClient == null) return null; var ticketId = Guid.Empty; if (ticketInfo.Ticket == null || ticketInfo.Ticket.HasValue && ticketInfo.Ticket.Equals(Guid.Empty)) { var res = await CreateM42TicketAsync(ticketInfo, requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested) return null; if (!string.IsNullOrEmpty(res)) { Guid.TryParse(res, out ticketId); } } else { await UpdateM42TicketAsync(ticketInfo, requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested) return null; ticketId = (Guid)ticketInfo.Ticket; } bool isTicket = false; if (ticketInfo.AdditionalValues.TryGetValue("IsTicket", out object value) && value is bool boolValue) { isTicket = boolValue; if (isTicket) { await TransformM42TicketAsync(ticketInfo, requestInfo, LogDeep + 1, token); } } var url = constUrlTicketClose; var ticket = new cApiM42TicketClosureInfo() { ObjectIds = new List() { ticketId }, Comments = ticketInfo.SolutionHtml, ErrorType = (int)ticketInfo.ErrorType == -1 ? null : ticketInfo.ErrorType, Reason = 408, }; var _jsonContent = JsonConvert.SerializeObject(ticket, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); var _content = new StringContent(_jsonContent, Encoding.UTF8, "application/json"); var response = await _webClient.HttpEnh.PostAsync(url, _content, token); if (token.IsCancellationRequested) return null; if (response.IsSuccessStatusCode) { ticketInfo.Ticket = ticketInfo.Ticket != null && ticketInfo.Ticket != Guid.Empty ? ticketInfo.Ticket : ticketId; await UpdateM42TicketUnreadAsync(ticketInfo, requestInfo, LogDeep + 1, token); return string.Empty; } } catch (Exception e) { LogException(e); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task AddWorkingTimesAsync(Guid TicketEOID, Dictionary workTimes, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (Collector == null) return false; var globalConfig = Collector.GetGlobalConfig(); var timeTrackingDisabled = globalConfig.TicketConfiguration.DisableAutomaticTimeTracking; if (timeTrackingDisabled) return false; var _webClient = await GetUserWebClient(requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested || _webClient == null) return false; if (token.IsCancellationRequested) return false; var fragments = await GetFragmentListAsync(new cDataFragmentsParams() { Columns = "ID, TypeID", Ddname = "SPSCommonClassBase", Pagenumber = 0, Pagesize = 10, Where = string.Format("[Expression-ObjectId] = '{0}'", TicketEOID) }, requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested) return false; var idAsString = ""; Guid? typeId = null; if (fragments != null) { idAsString = (string)fragments?[0]?.ID; if (Guid.TryParse(idAsString, out Guid typeIdTemp)) { typeId = typeIdTemp; } } string description = default; DateTime startTime = default; DateTime endTime = default; TimeSpan bruttoWorkingTime = default; int nettoWorkingTime = 0; TimeSpan totalPausedTime = default; if (workTimes.TryGetValue("Description", out object tempDescription) && tempDescription is string) { description = (string)tempDescription; } if (workTimes.TryGetValue("StartTime", out object tempStartTime) && tempStartTime is DateTime) { startTime = (DateTime)tempStartTime; } if (workTimes.TryGetValue("EndTime", out object tempEndTime) && tempEndTime is DateTime) { endTime = (DateTime)tempEndTime; } if (workTimes.TryGetValue("BruttoWorkingTime", out object tempBruttoWorkingTime) && tempBruttoWorkingTime is TimeSpan) { bruttoWorkingTime = (TimeSpan)tempBruttoWorkingTime; } if (workTimes.TryGetValue("NettoWorkingTime", out object tempNettoWorkingTime) && tempNettoWorkingTime is double) { nettoWorkingTime = (int)Math.Round((double)tempNettoWorkingTime / 60); } if (workTimes.TryGetValue("TotalPausedTime", out object tempTotalPausedTime) && tempTotalPausedTime is TimeSpan) { totalPausedTime = (TimeSpan)tempTotalPausedTime; } var requestBody = new cApiM42TicketAddWorkingTimesInfo() { ObjectIds = new List() { TicketEOID }, Begin = startTime, End = endTime, TypeId = typeId, ActivityType = 4, Minutes = nettoWorkingTime <= 0 ? 1 : nettoWorkingTime, Description = description }; var url = constUrlActivityTrackWorkingTime; var _jsonContent = JsonConvert.SerializeObject(requestBody, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); var _content = new StringContent(_jsonContent, Encoding.UTF8, "application/json"); var response = await _webClient.HttpEnh.PostAsync(url, _content, token); if (token.IsCancellationRequested) return false; if (response.IsSuccessStatusCode) { return true; } } catch (Exception e) { LogException(e); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return false; } public async Task TransformM42TicketAsync(cApiM42Ticket ticketInfo, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var _webClient = await GetUserWebClient(requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested || _webClient == null) return null; var ticketId = Guid.Empty; if (ticketInfo.Ticket == null || ticketInfo.Ticket.HasValue && ticketInfo.Ticket.Equals(Guid.Empty)) return null; else ticketId = ticketInfo.Ticket.Value; var url = constUrlTicketTransform; var ticket = new cM42TransformTicketInfo() { ObjectIds = new List() { ticketId }, SourceTypeName = "SPSActivityTypeTicket", TargetTypeName = "SPSActivityTypeIncident" }; var _jsonContent = JsonConvert.SerializeObject(ticket, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); var _content = new StringContent(_jsonContent, Encoding.UTF8, "application/json"); var response = await _webClient.HttpEnh.PostAsync(url, _content, token); if (token.IsCancellationRequested) return null; if (response.IsSuccessStatusCode) { //await Collector.ReportTicketAsync(ticketInfo, requestInfo, LogDeep + 1, token); return string.Empty; } } catch (Exception e) { LogException(e); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task GetQuickCallTemplateInfoAsync(Guid quickCallId, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var _webClient = await GetUserWebClient(requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested || _webClient == null) return null; if (quickCallId.Equals(Guid.Empty)) return null; var url = string.Format(constUrlActivityGetQuickCallTemplateInfo, quickCallId); var response = await _webClient.HttpEnh.GetAsync(url, token); if (token.IsCancellationRequested) return null; if (response.IsSuccessStatusCode) { var json = await response.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject(json); } } catch (Exception e) { LogException(e); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task ReopenM42TicketAsync(cApiM42Ticket ticketInfo, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var _webClient = await GetUserWebClient(requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested || _webClient == null) return null; var ticketId = Guid.Empty; if (ticketInfo.Ticket == null || ticketInfo.Ticket.HasValue && ticketInfo.Ticket.Equals(Guid.Empty)) return null; else ticketId = ticketInfo.Ticket.Value; var url = constUrlActivityReopen; string ReopenReasonText = ""; if (ticketInfo.AdditionalValues.TryGetValue("Dialog.CloseCase.ReopenReasonText", out object valueObj)) { ReopenReasonText = valueObj as string; } var ticket = new cM42ReopenTicketInfo() { ObjectIds = new List() { ticketId }, Reason = ReopenReasonText, }; var _jsonContent = JsonConvert.SerializeObject(ticket, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); var _content = new StringContent(_jsonContent, Encoding.UTF8, "application/json"); var response = await _webClient.HttpEnh.PostAsync(url, _content, token); if (token.IsCancellationRequested) return null; if (response.IsSuccessStatusCode) { //await Collector.ReportTicketAsync(ticketInfo, requestInfo, LogDeep + 1, token).ConfigureAwait(false); return string.Empty; } } catch (Exception e) { LogException(e); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task PauseM42TicketAsync(cApiM42Ticket ticketInfo, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var _webClient = await GetUserWebClient(requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested || _webClient == null) return null; var ticketId = Guid.Empty; if (ticketInfo.Ticket == null || ticketInfo.Ticket.HasValue && ticketInfo.Ticket.Equals(Guid.Empty)) { var res = await CreateM42TicketAsync(ticketInfo, requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested) return null; if (!string.IsNullOrEmpty(res)) { Guid.TryParse(res, out ticketId); } } else { await UpdateM42TicketAsync(ticketInfo, requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested) return null; ticketId = (Guid)ticketInfo.Ticket; } bool isTicket = false; if (ticketInfo.AdditionalValues.TryGetValue("IsTicket", out object value) && value is bool boolValue) { isTicket = boolValue; if (isTicket) { await TransformM42TicketAsync(ticketInfo, requestInfo, LogDeep + 1, token); } } var url = constUrlActivityPause; var ticket = new cApiM42TicketPauseInfo() { ObjectIds = new List() { ticketId }, Comments = ticketInfo.Comment, ReminderDate = (DateTime)ticketInfo.ReminderDate, NotEscalateWhilePaused = (bool)ticketInfo.DoNotEscalateWhilePaused, Reason = (int)ticketInfo.Reason }; var _jsonContent = JsonConvert.SerializeObject(ticket, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); var _content = new StringContent(_jsonContent, Encoding.UTF8, "application/json"); var response = await _webClient.HttpEnh.PostAsync(url, _content, token); if (token.IsCancellationRequested) return null; if (response.IsSuccessStatusCode) { ticketInfo.Ticket = ticketInfo.Ticket != null && ticketInfo.Ticket != Guid.Empty ? ticketInfo.Ticket : ticketId; await UpdateM42TicketUnreadAsync(ticketInfo, requestInfo, LogDeep + 1, token); return string.Empty; } } catch (Exception e) { LogException(e); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task ForwardM42TicketAsync(cApiM42Ticket ticketInfo, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var _webClient = await GetUserWebClient(requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested || _webClient == null) return null; var ticketId = Guid.Empty; if (ticketInfo.Ticket == null || ticketInfo.Ticket.HasValue && ticketInfo.Ticket.Equals(Guid.Empty)) { var res = await CreateM42TicketAsync(ticketInfo, requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested) return null; if (!string.IsNullOrEmpty(res)) { Guid.TryParse(res, out ticketId); } } else { await UpdateM42TicketAsync(ticketInfo, requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested) return null; ticketId = (Guid)ticketInfo.Ticket; } var url = constUrlActivityForward; var ticket = new cApiM42TicketForwardInfo() { Tickets = new List() { new cApiM42TicketForwardInfo.cTicket() { Item1 = "SPSActivityTypeIncident", Item2 = ticketId }}, Comments = ticketInfo.Comment, RoleId = ticketInfo.ResponsibleRole, UserId = ticketInfo.ResponsiblePerson, }; var _jsonContent = JsonConvert.SerializeObject(ticket, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); var _content = new StringContent(_jsonContent, Encoding.UTF8, "application/json"); var response = await _webClient.HttpEnh.PostAsync(url, _content, token); if (token.IsCancellationRequested) return null; if (response.IsSuccessStatusCode) { ticketInfo.Ticket = ticketInfo.Ticket != null && ticketInfo.Ticket != Guid.Empty ? ticketInfo.Ticket : ticketId; await UpdateM42TicketUnreadAsync(ticketInfo, requestInfo, LogDeep + 1, token); return string.Empty; } } catch (Exception e) { LogException(e); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task CreateM42JournalAsync(cCreateJournalEntryInfo journalEntryInfo, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var _webClient = await GetUserWebClient(requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested || _webClient == null) return null; var _jsonContent = JsonConvert.SerializeObject(journalEntryInfo, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); var _content = new StringContent(_jsonContent, Encoding.UTF8, "application/json"); var response = await _webClient.HttpEnh.PostAsync(constUrlCreateJournalEntry, _content, token); if (token.IsCancellationRequested) return null; if (response.IsSuccessStatusCode) { var json = await response.Content.ReadAsStringAsync(); if (token.IsCancellationRequested) return null; return json; } } catch (Exception e) { LogException(e); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public static string GetFragmentUrlWithParameters(cDataFragmentsParams parameters) { return string.Format(constUrlFragmentsGetList, parameters.Ddname, Uri.EscapeDataString(parameters.Where), // Ensure proper URI encoding parameters.Columns, parameters.Pagesize, parameters.Pagenumber, parameters.Sort); } public async Task CleanupApiTokensAsync(CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (WebClient is null) return; try { var _strFilter = (DateTime.UtcNow - TimeSpan.FromHours(24)).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss"); _strFilter = string.Format("Name like 'F4SD_%' and ValidUntil < '{0}'", _strFilter); var _strListToken = await WebClient.GetFragmentListAsync("PLSTSApiTokenBase", Token, Where: _strFilter, Columns: "ID,Name"); if (Token.IsCancellationRequested) return; if (!string.IsNullOrEmpty(_strListToken)) { // remove all existing tokens with corresponding name var lstIds = JsonConvert.DeserializeObject>(_strListToken); foreach (var objId in lstIds) { if (string.IsNullOrEmpty(objId.Name)) continue; if (objId.Name.Length < 37) continue; var _strGuid = objId.Name.Substring(objId.Name.Length - 37, 37); if (!_strGuid.StartsWith("_")) continue; _strGuid = _strGuid.Remove(0, 1); if (!Guid.TryParse(_strGuid, out _)) continue; var _delRequest = new Dictionary() { { objId.Id, "PLSTSApiTokenType" } }; await WebClient.DeleteObjectsAsync("F4SD Cockpit", _delRequest, Token); if (Token.IsCancellationRequested) return; } } } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } } public override async Task GetAdditionalUserInfo(enumAdditionalAuthentication Type, cF4sdWebRequestInfo RequestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { if (Type != enumAdditionalAuthentication.M42WinLogon) return null; if (RequestInfo?.userInfo?.Id is null) return null; var _uc = await Collector.TokenCache.GetAsync(RequestInfo.userInfo.Id, cF4SDTokenRegistration.enumTokenType.M42Bearer, RequestInfo, LogDeep + 1); if (_uc == null) return null; var _m42 = new cM42WebClient(Collector.InfrastructureConfig.M42Wpm.Server, UseSSL: true); _m42.SetBearerToken(_uc.secret); var _m42Reason = await _m42.Open(); if (_m42Reason == eReason.ok && _m42.BearerToken != null) { var m42UserInfo = await _m42.GetUserInfoAsync(); if (m42UserInfo?.User != null) { var _retVal = new cF4SDAdditionalUserInfo() { internalID = m42UserInfo.User.Id.ToString(), Name = m42UserInfo.User.LastName + ", " + m42UserInfo.User.FirstName, Type = enumAdditionalAuthentication.M42WinLogon, ValidUntil = _uc.validUntil }; return _retVal; } } } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return null; } public async Task GetFragmentListAsync(cDataFragmentsParams fragmentsParams, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var _webClient = await GetUserWebClient(requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested || _webClient == null) return null; var response = await _webClient.HttpEnh.GetAsync(GetFragmentUrlWithParameters(fragmentsParams), token); if (token.IsCancellationRequested) return null; if (response.IsSuccessStatusCode) { var json = await response.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject(json); } } catch (Exception e) { LogException(e); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task GetObjectAsync(string ci, Guid id, bool full, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var _webClient = await GetUserWebClient(requestInfo, LogDeep + 1, token); if (token.IsCancellationRequested || _webClient == null) return null; var url = string.Format(constUrlObjectsGetObject, ci, id, full); var response = await _webClient.HttpEnh.GetAsync(url, token); if (token.IsCancellationRequested) return null; if (response.IsSuccessStatusCode) { var json = await response.Content.ReadAsStringAsync(); if (token.IsCancellationRequested) return null; return JsonConvert.DeserializeObject(json); } } catch (Exception e) { LogException(e); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } static string RemoveEmptyQueryParameters(string url) { var uri = new Uri("http://dummy.com/" + url); var queryParts = HttpUtility.ParseQueryString(uri.Query); var newQuery = ""; foreach (string key in queryParts.AllKeys) { if (!string.IsNullOrEmpty(queryParts[key])) { newQuery += string.IsNullOrEmpty(newQuery) ? "?" : "&"; newQuery += $"{key}={queryParts[key]}"; } } string cleanedUrl = uri.AbsolutePath.Substring(1) + newQuery; return cleanedUrl; } public HashSet GetSupportedInformationClasses() => new HashSet() { enumFasdInformationClass.Ticket }; public async Task GetRelationsAsync(IEnumerable ids, enumFasdInformationClass informationClass, int age, CancellationToken token = default) { try { List ticketIds = await _collector.getConnectorIdList(ids.ToList(), token, null, 0); List relations = await getTicketUsage(ticketIds, token, null, 0); return new cF4sdStagedSearchResultRelations() { Relations = relations }; } catch (Exception ex) { LogException(ex); } return null; } } public class cDataFragmentsParams { public string Ddname { get; set; } public string Where { get; set; } public string Columns { get; set; } public int Pagesize { get; set; } public int Pagenumber { get; set; } public string Sort { get; set; } } public class cCreateJournalEntryInfo { public Guid ObjectId { get; set; } public Guid TypeId { get; set; } public bool Publish { get; set; } public string Comments { get; set; } public int EntryType { get; set; } public Guid Creator { get; set; } public bool VisibleInPortal { get; set; } public List FileIds { get; set; } public List Parameters { get; set; } public class Parameter { public string Name { get; set; } public object Value { get; set; } public string Format { get; set; } public bool IsCurrency { get; set; } } } public class cM42TransformTicketInfo { public Guid? Category { get; set; } = null; public Guid? Sla { get; set; } = null; public Guid? RecipientRole { get; set; } = null; public string SourceTypeName { get; set; } = null; public string TargetTypeName { get; set; } = null; public List ObjectIds { get; set; } = new List(); public bool? UpdateFavoriteView { get; set; } = null; public bool? RaiseCoRuTypeInsertEvent { get; set; } = null; } public class cM42ReopenTicketInfo { public string Reason { get; set; } = null; public List ObjectIds { get; set; } = new List(); } public class cM42TicketInfo { public JournalEntryData EntryData { get; set; } public Guid? Asset { get; set; } = null; public Guid? AffectedAsset { get; set; } = null; public Guid? AffectedService { get; set; } = null; public string UserReachableAt { get; set; } = null; public int EntryBy { get; set; } = 0; public int Classification { get; set; } = 0; public Guid? QueueProfile { get; set; } = null; public Guid? Template { get; set; } = null; public Guid? Category { get; set; } = null; public string Subject { get; set; } = null; public string Description { get; set; } = null; public string DescriptionHTML { get; set; } = null; public string Solution { get; set; } = null; public string SolutionHTML { get; set; } = null; public int ActivityAction { get; set; } = 0; public int TaskType { get; set; } = 0; public int ErrorType { get; set; } = 0; public int State { get; set; } = 0; public int Priority { get; set; } = 0; public int Impact { get; set; } = 0; public int Urgency { get; set; } = 0; public Guid? User { get; set; } = null; public Guid? ResponsibleUser { get; set; } = null; public Guid? ResponsibleRole { get; set; } = null; public Guid? Service { get; set; } = null; public Guid? SLA { get; set; } = null; public string TicketNumber { get; set; } = null; public DateTime Deadline { get; set; } = DateTime.UtcNow; public bool NotifyResponsible { get; set; } = false; public int NotificationMode { get; set; } = 0; public bool CloseOnTasksCompletion { get; set; } = false; public Guid? WorkflowId { get; set; } = null; public List RelatedUsers { get; set; } = new List(); public List RelatedServices { get; set; } = new List(); public List SimpleServiceForms { get; set; } = new List(); public List ConfigurationItems { get; set; } = new List(); public List RelatedTasks { get; set; } = new List(); public List RelatedAssets { get; set; } = new List(); public List RelatedIncidents { get; set; } = new List(); public List RelatedProblems { get; set; } = new List(); public bool NewInformationReceived { get; set; } = false; public bool SkipSettingOwner { get; set; } = false; public bool RecalculateResponsibleRole { get; set; } = false; public List ExtraProperties { get; set; } = new List(); } public class JournalEntryData { public Guid? ObjectId { get; set; } = null; public Guid? TypeId { get; set; } = null; public bool Publish { get; set; } = false; public string Comments { get; set; } = null; public int EntryType { get; set; } = 0; public Guid? Creator { get; set; } = null; public bool VisibleInPortal { get; set; } = false; public List Parameters { get; set; } = new List(); public bool SkipRaiseCoRuEvent { get; set; } = false; } public class Parameter { public bool IsPortalMode { get; set; } = false; public bool IsExportMode { get; set; } = false; public string Name { get; set; } = null; } public class ExtraProperty { public string Name { get; set; } = null; public object Value { get; set; } = null; } } public class cM42DataQueryRelationInfo { public int ClientTimeOffset { get; set; } = 0; public string EntityClassName { get; set; } public string EntityTypeName { get; set; } public string AddedRelations { get; set; } = ""; public string RemovedRelations { get; set; } = ""; public string WhereExpression { get; set; } = ""; public cM42QueryFilterGroup AdditionalFilter { get; set; } = new cM42QueryFilterGroup(); public int pageSize { get; set; } = 20; public int page { get; set; } = 0; public bool totalCounted { get; set; } = false; public string search { get; set; } = ""; public string orderBy { get; set; } = ""; public string columns { get; set; } } public class cM42DataQueryRelationInfo2 { public int ClientTimeOffset { get; set; } = 0; public string EntityClassName { get; set; } public string EntityTypeName { get; set; } public string AddedRelations { get; set; } = ""; public string RemovedRelations { get; set; } = ""; public string WhereExpression { get; set; } = ""; public cM42QueryFilterGroup AdditionalFilter { get; set; } = new cM42QueryFilterGroup(); public int pageSize { get; set; } = 0; public int page { get; set; } = 0; public string search { get; set; } = ""; public string orderBy { get; set; } = ""; public string columns { get; set; } public string RelationName { get; set; } public Guid FragmentId { get; set; } public bool Archived { get; set; } = false; public string Filters { get; set; } = ""; } public class cM42QueryFilterGroup { public cM42QueryFilterCondition[] Conditions { get; set; } = new cM42QueryFilterCondition[0]; public cM42QueryFilterGroup[] Groups { get; set; } = new cM42QueryFilterGroup[0]; public int LogicalOperator { get; set; } = 1; } public class cM42QueryFilterCondition { public int Operator { get; set; } public string Property { get; set; } public string[] Value { get; set; } public bool IsExpression { get; set; } public bool DenyWildcard { get; set; } } public class cF4SDTicketSummary { public Guid TicketObjectId { get; set; } public string Name { get; set; } public string ActivityType { get; set; } public string Summary { get; set; } public string Sid { get; set; } public string Status { get; set; } public int StatusId { get; set; } public string AssetCIName { get; set; } public string AssetName { get; set; } public string ServiceName { get; set; } public Guid ServiceId { get; set; } public bool IsPrimaryAccount { get; set; } public Guid UserId { get; set; } } public class M42UserUserInfo { public class M42User { public Guid Id { get; set; } = Guid.Empty; public Guid ObjectId { get; set; } public string Name { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Email { get; set; } public string Photo { get; set; } public string Phone { get; set; } public string Currency { get; set; } public string Locale { get; set; } public int LanguageId { get; set; } public bool IsAdmin { get; set; } public int State { get; set; } public string StateDisp { get; set; } } public class M42Role { public Guid Id { get; set; } public string Name { get; set; } } public M42User User { get; set; } public List Roles { get; set; } }