From 5acaaa75b445b8c83e1ac1d6fa7438caa2142a13 Mon Sep 17 00:00:00 2001 From: Meik Date: Wed, 1 Jul 2026 00:07:26 +0200 Subject: [PATCH] fix: invoke journal service compatibly across 26.1 patches --- F4SDM42WebApi/F4SD - M42WebApi.csproj | 2 +- F4SDM42WebApi/F4SDHelperService.cs | 127 +++++++++++++++++++++++++- 2 files changed, 124 insertions(+), 5 deletions(-) diff --git a/F4SDM42WebApi/F4SD - M42WebApi.csproj b/F4SDM42WebApi/F4SD - M42WebApi.csproj index 9e3939e..cf4d2dc 100644 --- a/F4SDM42WebApi/F4SD - M42WebApi.csproj +++ b/F4SDM42WebApi/F4SD - M42WebApi.csproj @@ -13,7 +13,7 @@ false 6673a25d-33d6-4072-91d9-abed4be1a966 C4ITF4SD*.* - 1.4.0.23 + 1.4.0.24 true diff --git a/F4SDM42WebApi/F4SDHelperService.cs b/F4SDM42WebApi/F4SDHelperService.cs index 6dcb390..a37e549 100644 --- a/F4SDM42WebApi/F4SDHelperService.cs +++ b/F4SDM42WebApi/F4SDHelperService.cs @@ -1408,15 +1408,15 @@ namespace C4IT.F4SD { await Task.Delay(0); List journalEntries = new List(); - var entries = F4SDM42WebApiController.defaultInstance.GetJournalService().GetJournalList(activityEOID, false, 0, 50, "{2}", 120); - LogEntry($"{entries.Length} Journal entries found for ObjectID={activityEOID}", LogLevels.Debug); - for (int i = 0; i < entries.Length; i++) + var entries = LoadJournalEntries(activityEOID); + LogEntry($"{entries.Count} Journal entries found for ObjectID={activityEOID}", LogLevels.Debug); + for (int i = 0; i < entries.Count; i++) { Matrix42.Contracts.Platform.Data.JournalEntryInfo item = entries[i]; var text = item.Text ?? string.Empty; var createdDate = item.CreatedDate ?? DateTime.MinValue; - LogEntry($"Journal entry {i + 1}/{entries.Length}: ID={item.Id}, CreatedDate={createdDate}, CreatedBy={item.Creator}, Header={item.Header}", LogLevels.Debug); + LogEntry($"Journal entry {i + 1}/{entries.Count}: ID={item.Id}, CreatedDate={createdDate}, CreatedBy={item.Creator}, Header={item.Header}", LogLevels.Debug); journalEntries.Add(new cTicketJournalItem() { JournalId = item.Id, @@ -1446,6 +1446,125 @@ namespace C4IT.F4SD } } + private static IReadOnlyList LoadJournalEntries(Guid activityEOID) + { + var journalService = F4SDM42WebApiController.defaultInstance.GetJournalService(); + var serviceType = journalService.GetType(); + var objectLinkTemplate = "{2}"; + var methods = serviceType + .GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) + .Where(IsJournalReaderMethod) + .OrderByDescending(method => method.GetParameters().Length) + .ToList(); + + foreach (var method in methods) + { + if (!TryBuildJournalListArguments(method, activityEOID, objectLinkTemplate, out var arguments)) + continue; + + try + { + var result = method.Invoke(journalService, arguments); + if (result is Matrix42.Contracts.Platform.Data.JournalEntryInfo[] arrayResult) + return arrayResult; + + if (result is IEnumerable enumerableResult) + return enumerableResult.ToList(); + + throw new MissingMethodException($"IJournalService.GetJournalList returned unsupported type '{result?.GetType().FullName ?? ""}'."); + } + catch (TargetInvocationException ex) when (ex.InnerException != null) + { + throw ex.InnerException; + } + } + + throw new MissingMethodException($"No compatible IJournalService.GetJournalList overload was found on '{serviceType.FullName}'. Available overloads: {string.Join("; ", methods.Select(FormatMethodSignature))}"); + } + + private static bool IsJournalReaderMethod(MethodInfo method) + { + var methodName = method.Name; + if (methodName.Contains(".")) + methodName = methodName.Substring(methodName.LastIndexOf(".", StringComparison.Ordinal) + 1); + + if (!(methodName.StartsWith("Get", StringComparison.OrdinalIgnoreCase) || methodName.StartsWith("Load", StringComparison.OrdinalIgnoreCase))) + return false; + + if (!methodName.Contains("Journal", StringComparison.OrdinalIgnoreCase)) + return false; + + if (!method.GetParameters().Any(parameter => parameter.ParameterType == typeof(Guid))) + return false; + + var returnType = method.ReturnType; + if (returnType.IsArray) + return returnType.GetElementType()?.FullName == typeof(Matrix42.Contracts.Platform.Data.JournalEntryInfo).FullName; + + if (returnType.FullName == typeof(Matrix42.Contracts.Platform.Data.JournalEntryInfo).FullName) + return true; + + return returnType.GetInterfaces() + .Where(type => type.IsGenericType) + .Select(type => type.GetGenericArguments().FirstOrDefault()) + .Any(type => type?.FullName == typeof(Matrix42.Contracts.Platform.Data.JournalEntryInfo).FullName); + } + + private static bool TryBuildJournalListArguments(MethodInfo method, Guid activityEOID, string objectLinkTemplate, out object[] arguments) + { + var parameters = method.GetParameters(); + arguments = new object[parameters.Length]; + + for (int i = 0; i < parameters.Length; i++) + { + var parameter = parameters[i]; + var parameterType = parameter.ParameterType; + var parameterName = parameter.Name ?? string.Empty; + var lowerName = parameterName.ToLowerInvariant(); + + if (parameterType == typeof(Guid)) + { + arguments[i] = activityEOID; + } + else if (parameterType == typeof(bool)) + { + arguments[i] = false; + } + else if (parameterType == typeof(int)) + { + if (lowerName.Contains("time")) + arguments[i] = 120; + else if (lowerName.Contains("count") || lowerName.Contains("take") || lowerName.Contains("limit") || lowerName.Contains("size")) + arguments[i] = 50; + else + arguments[i] = 0; + } + else if (parameterType == typeof(string)) + { + arguments[i] = lowerName.Contains("template") || lowerName.Contains("link") ? objectLinkTemplate : null; + } + else if (parameterType == typeof(string[])) + { + arguments[i] = null; + } + else if (parameter.HasDefaultValue) + { + arguments[i] = parameter.DefaultValue; + } + else + { + return false; + } + } + + return true; + } + + private static string FormatMethodSignature(MethodInfo method) + { + return $"{method.ReturnType.FullName} {method.Name}({string.Join(", ", method.GetParameters().Select(parameter => $"{parameter.ParameterType.FullName} {parameter.Name}"))})"; + } + internal async Task updateActivitySolution(Guid objectId, string solutionHtml) {