fix(search): open unassigned tickets in Matrix42
This commit is contained in:
@@ -0,0 +1,106 @@
|
|||||||
|
using C4IT.FASD.Base;
|
||||||
|
using FasdDesktopUi.Basics.Helper;
|
||||||
|
|
||||||
|
namespace F4SD.Cockpit.Client.Test.Basics.Helper;
|
||||||
|
|
||||||
|
public class TicketExternalLinkHelperTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void HasValidUserIdentity_NullIdentities_ReturnsFalse()
|
||||||
|
{
|
||||||
|
var relation = CreateTicketRelation();
|
||||||
|
|
||||||
|
Assert.False(TicketExternalLinkHelper.HasValidUserIdentity(relation));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void HasValidUserIdentity_EmptyUserId_ReturnsFalse()
|
||||||
|
{
|
||||||
|
var relation = CreateTicketRelation();
|
||||||
|
relation.Identities =
|
||||||
|
[
|
||||||
|
new cF4sdIdentityEntry { Class = enumFasdInformationClass.Ticket, Id = relation.id },
|
||||||
|
new cF4sdIdentityEntry { Class = enumFasdInformationClass.User, Id = Guid.Empty }
|
||||||
|
];
|
||||||
|
|
||||||
|
Assert.False(TicketExternalLinkHelper.HasValidUserIdentity(relation));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void HasValidUserIdentity_ValidUserId_ReturnsTrue()
|
||||||
|
{
|
||||||
|
var relation = CreateTicketRelation();
|
||||||
|
relation.Identities =
|
||||||
|
[
|
||||||
|
new cF4sdIdentityEntry { Class = enumFasdInformationClass.User, Id = Guid.NewGuid() }
|
||||||
|
];
|
||||||
|
|
||||||
|
Assert.True(TicketExternalLinkHelper.HasValidUserIdentity(relation));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetTicketLink_UsesProvidedPreviewLink()
|
||||||
|
{
|
||||||
|
var relation = CreateTicketRelation();
|
||||||
|
relation.Infos = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
["DirectLinkPreview"] = "https://m42.example/wm/ticket/preview"
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = TicketExternalLinkHelper.TryGetTicketLink(relation, null, out var ticketLink);
|
||||||
|
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Equal("https://m42.example/wm/ticket/preview", ticketLink.TrimEnd('/'));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetTicketLink_BuildsPreviewLinkForOverviewRelation()
|
||||||
|
{
|
||||||
|
var relation = CreateTicketRelation();
|
||||||
|
relation.Infos = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
["ActivityType"] = "SPSActivityTypeIncident"
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = TicketExternalLinkHelper.TryGetTicketLink(relation, "m42.example", out var ticketLink);
|
||||||
|
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Equal(
|
||||||
|
$"https://m42.example/wm/app-ServiceDesk/notSet/preview-object/SPSActivityTypeIncident/{relation.id:D}/0/",
|
||||||
|
ticketLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetTicketLink_UsesDefaultTicketActivityType()
|
||||||
|
{
|
||||||
|
var relation = CreateTicketRelation();
|
||||||
|
|
||||||
|
var result = TicketExternalLinkHelper.TryGetTicketLink(relation, "https://m42.example/", out var ticketLink);
|
||||||
|
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Contains("/SPSActivityTypeTicket/", ticketLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetTicketLink_MissingTicketId_ReturnsFalse()
|
||||||
|
{
|
||||||
|
var relation = CreateTicketRelation();
|
||||||
|
relation.id = Guid.Empty;
|
||||||
|
|
||||||
|
var result = TicketExternalLinkHelper.TryGetTicketLink(relation, "https://m42.example", out var ticketLink);
|
||||||
|
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(ticketLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static cF4sdApiSearchResultRelation CreateTicketRelation()
|
||||||
|
{
|
||||||
|
return new cF4sdApiSearchResultRelation
|
||||||
|
{
|
||||||
|
Type = enumF4sdSearchResultClass.Ticket,
|
||||||
|
Name = "TCK00001",
|
||||||
|
DisplayName = "TCK00001",
|
||||||
|
id = Guid.NewGuid()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,8 @@ namespace FasdDesktopUi.Basics.Helper
|
|||||||
{
|
{
|
||||||
internal static class TicketExternalLinkHelper
|
internal static class TicketExternalLinkHelper
|
||||||
{
|
{
|
||||||
|
private const string DefaultTicketActivityType = "SPSActivityTypeTicket";
|
||||||
|
|
||||||
internal static bool TryOpenTicketRelationExternally(cF4sdApiSearchResultRelation relation)
|
internal static bool TryOpenTicketRelationExternally(cF4sdApiSearchResultRelation relation)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -25,15 +27,21 @@ namespace FasdDesktopUi.Basics.Helper
|
|||||||
var processing = ShouldOpenExternally(ticketType);
|
var processing = ShouldOpenExternally(ticketType);
|
||||||
|
|
||||||
// check if we have a valid user id in the id list => if not we could open this ticket only extern.
|
// check if we have a valid user id in the id list => if not we could open this ticket only extern.
|
||||||
var hasUser = relation.Identities.Any(e => (e.Class == enumFasdInformationClass.User && e.Id != null && e.Id != Guid.Empty));
|
var hasUser = HasValidUserIdentity(relation);
|
||||||
if (!hasUser)
|
if (!hasUser)
|
||||||
processing = enumTicketProcessing.Extern;
|
processing = enumTicketProcessing.Extern;
|
||||||
|
|
||||||
if (processing == enumTicketProcessing.Intern)
|
if (processing == enumTicketProcessing.Intern)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (relation?.Infos?.TryGetValue("TicketLink", out var ticketLink) == true && !string.IsNullOrWhiteSpace(ticketLink))
|
var m42Server = cCockpitConfiguration.Instance?.m42ServerConfiguration?.Server;
|
||||||
new cBrowsers().Start("default", ticketLink);
|
if (!TryGetTicketLink(relation, m42Server, out var ticketLink))
|
||||||
|
{
|
||||||
|
LogEntry($"Could not resolve an external Matrix42 link for ticket '{relation.DisplayName ?? relation.Name}'.", LogLevels.Warning);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
new cBrowsers().Start("default", ticketLink);
|
||||||
|
|
||||||
return processing == enumTicketProcessing.Extern;
|
return processing == enumTicketProcessing.Extern;
|
||||||
}
|
}
|
||||||
@@ -45,6 +53,79 @@ namespace FasdDesktopUi.Basics.Helper
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static bool HasValidUserIdentity(cF4sdApiSearchResultRelation relation)
|
||||||
|
{
|
||||||
|
return relation?.Identities?.Any(identity =>
|
||||||
|
identity.Class == enumFasdInformationClass.User && identity.Id != Guid.Empty) == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool TryGetTicketLink(cF4sdApiSearchResultRelation relation, string m42Server, out string ticketLink)
|
||||||
|
{
|
||||||
|
ticketLink = null;
|
||||||
|
if (relation == null || relation.Type != enumF4sdSearchResultClass.Ticket)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (TryGetHttpLink(relation, "TicketLink", out ticketLink) ||
|
||||||
|
TryGetHttpLink(relation, "DirectLinkPreview", out ticketLink))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (relation.id == Guid.Empty || string.IsNullOrWhiteSpace(m42Server))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var server = m42Server.Trim();
|
||||||
|
if (!server.Contains("://"))
|
||||||
|
server = $"https://{server}";
|
||||||
|
|
||||||
|
if (!Uri.TryCreate(server, UriKind.Absolute, out var serverUri) ||
|
||||||
|
(serverUri.Scheme != Uri.UriSchemeHttp && serverUri.Scheme != Uri.UriSchemeHttps))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var activityType = GetActivityType(relation);
|
||||||
|
var encodedActivityType = Uri.EscapeDataString(activityType);
|
||||||
|
ticketLink = $"{serverUri.Scheme}://{serverUri.Authority}/wm/app-ServiceDesk/notSet/preview-object/{encodedActivityType}/{relation.id:D}/0/";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryGetHttpLink(cF4sdApiSearchResultRelation relation, string key, out string ticketLink)
|
||||||
|
{
|
||||||
|
ticketLink = null;
|
||||||
|
if (relation?.Infos?.TryGetValue(key, out var configuredLink) != true || string.IsNullOrWhiteSpace(configuredLink))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!Uri.TryCreate(configuredLink, UriKind.Absolute, out var linkUri) ||
|
||||||
|
(linkUri.Scheme != Uri.UriSchemeHttp && linkUri.Scheme != Uri.UriSchemeHttps))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ticketLink = linkUri.AbsoluteUri;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetActivityType(cF4sdApiSearchResultRelation relation)
|
||||||
|
{
|
||||||
|
if (relation?.Infos?.TryGetValue("ActivityType", out var activityType) == true && !string.IsNullOrWhiteSpace(activityType))
|
||||||
|
return activityType.Trim();
|
||||||
|
|
||||||
|
if (relation?.Infos?.TryGetValue("TicketType", out var ticketTypeValue) == true &&
|
||||||
|
Enum.TryParse(ticketTypeValue, true, out enumTicketType ticketType))
|
||||||
|
{
|
||||||
|
switch (ticketType)
|
||||||
|
{
|
||||||
|
case enumTicketType.Incident:
|
||||||
|
return "SPSActivityTypeIncident";
|
||||||
|
case enumTicketType.ServiceRequest:
|
||||||
|
return "SPSActivityTypeServiceRequest";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DefaultTicketActivityType;
|
||||||
|
}
|
||||||
|
|
||||||
private static enumTicketType GetTicketType(cF4sdApiSearchResultRelation relation)
|
private static enumTicketType GetTicketType(cF4sdApiSearchResultRelation relation)
|
||||||
{
|
{
|
||||||
if (relation?.Infos != null && relation.Infos.TryGetValue("TicketType", out var ticketTypeValue))
|
if (relation?.Infos != null && relation.Infos.TryGetValue("TicketType", out var ticketTypeValue))
|
||||||
|
|||||||
Reference in New Issue
Block a user