diff --git a/F4SDM42WebApi/F4SD - M42WebApi.csproj b/F4SDM42WebApi/F4SD - M42WebApi.csproj
index 3023793..e836f90 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.30
+ 1.4.0.31
true
diff --git a/F4SDM42WebApi/F4SDHelperService.cs b/F4SDM42WebApi/F4SDHelperService.cs
index c6fcc86..1c84ee2 100644
--- a/F4SDM42WebApi/F4SDHelperService.cs
+++ b/F4SDM42WebApi/F4SDHelperService.cs
@@ -1408,29 +1408,9 @@ namespace C4IT.F4SD
try
{
await Task.Delay(0);
- List journalEntries = new List();
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.Count}: ID={item.Id}, CreatedDate={createdDate}, CreatedBy={item.Creator}, Header={item.Header}", LogLevels.Debug);
- journalEntries.Add(new cTicketJournalItem()
- {
- JournalId = item.Id,
- ActivityObjectId = activityEOID,
- CreatedBy = item.Creator,
- CreationDate = createdDate,
- DescriptionHtml = text,
- Description = string.IsNullOrEmpty(text) ? string.Empty : Matrix42.Common.Html.HtmlConverter.ConvertHtmlToPlainText(text),
- Header = item.Header,
- IsVisibleForUser = item.VisibleInPortal
- });
- }
- return journalEntries;
+ return CreateTicketJournalItems(activityEOID, entries);
}
catch (MissingMethodException E)
{
@@ -1447,6 +1427,32 @@ namespace C4IT.F4SD
}
}
+ internal static List CreateTicketJournalItems(Guid activityEOID, IReadOnlyList entries)
+ {
+ List journalEntries = new List();
+ 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.Count}: ID={item.Id}, CreatedDate={createdDate}, CreatedBy={item.Creator}, Header={item.Header}", LogLevels.Debug);
+ journalEntries.Add(new cTicketJournalItem()
+ {
+ JournalId = item.Id,
+ ActivityObjectId = activityEOID,
+ CreatedBy = item.Creator,
+ CreationDate = createdDate,
+ DescriptionHtml = text,
+ Description = string.IsNullOrEmpty(text) ? string.Empty : Matrix42.Common.Html.HtmlConverter.ConvertHtmlToPlainText(text),
+ Header = item.Header,
+ IsVisibleForUser = item.VisibleInPortal
+ });
+ }
+
+ return journalEntries;
+ }
+
private static IReadOnlyList LoadJournalEntries(Guid activityEOID)
{
var journalService = F4SDM42WebApiController.defaultInstance.GetJournalServiceInstance();
diff --git a/F4SDM42WebApi/F4SDM42WebApiController.cs b/F4SDM42WebApi/F4SDM42WebApiController.cs
index 0d72fe5..b48d35d 100644
--- a/F4SDM42WebApi/F4SDM42WebApiController.cs
+++ b/F4SDM42WebApi/F4SDM42WebApiController.cs
@@ -45,6 +45,10 @@ namespace C4IT.F4SD
private readonly F4SDHelperService _f4stHelperService;
private const string TeamsNotificationServiceTypeName = "Matrix42.Contracts.Platform.MsTeams.ITeamsNotificationService";
private const string StorageServiceTypeName = "Matrix42.StorageService.Contracts.IStorageService";
+ private const int JournalStart = 0;
+ private const int JournalCount = 50;
+ private const int JournalTimeOffset = 120;
+ private const string JournalObjectLinkTemplate = "{2}";
public string BaseUrl => Request?.RequestUri == null ? string.Empty : $"{Request.RequestUri.Scheme}://{Request.RequestUri.Host}";
public string EndpointBaseUrl => $"{BaseUrl}/m42Services/api/c4itf4sdwebapi";
@@ -304,6 +308,13 @@ namespace C4IT.F4SD
{
try
{
+ var journalPortalEntries = await TryGetJournalPortalEntries(objectId);
+ if (journalPortalEntries != null)
+ {
+ LogEntry($"{journalPortalEntries.Count} Journal entries loaded from Matrix42 JournalPortalController for ObjectID={objectId}", LogLevels.Debug);
+ return F4SDHelperService.CreateTicketJournalItems(objectId, journalPortalEntries);
+ }
+
return await _f4stHelperService.GetJournalEntries(objectId);
}
catch (MissingMethodException ex)
@@ -312,6 +323,90 @@ namespace C4IT.F4SD
}
}
+ private async Task> TryGetJournalPortalEntries(Guid objectId)
+ {
+ if (Request?.RequestUri == null)
+ return null;
+
+ foreach (var requestUri in BuildJournalPortalUris(objectId))
+ {
+ try
+ {
+ using (var handler = new HttpClientHandler { UseDefaultCredentials = true, AutomaticDecompression = DecompressionMethods.All })
+ using (var client = new HttpClient(handler))
+ using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri))
+ {
+ client.Timeout = TimeSpan.FromSeconds(15);
+ CopyIncomingHeaders(request);
+ using (var response = await client.SendAsync(request))
+ {
+ var responseText = await response.Content.ReadAsStringAsync();
+ if (!response.IsSuccessStatusCode)
+ {
+ LogEntry($"Matrix42 JournalPortalController returned {(int)response.StatusCode} {response.ReasonPhrase} for {requestUri}. {responseText}", LogLevels.Warning);
+ continue;
+ }
+
+ var entries = DeserializeJournalPortalEntries(responseText);
+ if (entries != null)
+ return entries;
+
+ LogEntry($"Matrix42 JournalPortalController response could not be deserialized for {requestUri}. {responseText}", LogLevels.Warning);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogEntry($"Matrix42 JournalPortalController request failed for {requestUri}. {ex.GetType().FullName}: {ex.Message}", LogLevels.Warning);
+ }
+ }
+
+ return null;
+ }
+
+ private IEnumerable BuildJournalPortalUris(Guid objectId)
+ {
+ var query = $"objectId={Uri.EscapeDataString(objectId.ToString())}&start={JournalStart}&count={JournalCount}&objectLinkTemplate={Uri.EscapeDataString(JournalObjectLinkTemplate)}&timeOffset={JournalTimeOffset}";
+ yield return new Uri($"{BaseUrl}/m42Services/api/journalPortal?{query}");
+ yield return new Uri($"{BaseUrl}/api/journalPortal?{query}");
+ }
+
+ private void CopyIncomingHeaders(HttpRequestMessage request)
+ {
+ foreach (var header in Request.Headers)
+ {
+ if (string.Equals(header.Key, "Host", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(header.Key, "Connection", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(header.Key, "Accept-Encoding", StringComparison.OrdinalIgnoreCase))
+ continue;
+
+ request.Headers.TryAddWithoutValidation(header.Key, header.Value);
+ }
+ }
+
+ private static Matrix42.Contracts.Platform.Data.JournalEntryInfo[] DeserializeJournalPortalEntries(string responseText)
+ {
+ try
+ {
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(responseText);
+ }
+ catch
+ {
+ var token = Newtonsoft.Json.Linq.JToken.Parse(responseText);
+ if (token.Type == Newtonsoft.Json.Linq.JTokenType.Array)
+ return token.ToObject();
+
+ foreach (var propertyName in new[] { "result", "Result", "value", "Value" })
+ {
+ var resultToken = token[propertyName];
+ if (resultToken != null && resultToken.Type != Newtonsoft.Json.Linq.JTokenType.Null)
+ return resultToken.ToObject();
+ }
+
+ return null;
+ }
+ }
+
internal static List CreateMissingMethodDiagnostics(string stage, Guid objectId, MissingMethodException ex)
{
var details = BuildMissingMethodDiagnostic(stage, objectId, ex);