fix: restore 26eac54 behavior for 26.1 port
This commit is contained in:
@@ -1,6 +1,13 @@
|
||||
using System;
|
||||
using C4IT.F4SDM;
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.Logging;
|
||||
using Matrix42.Common;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using System.Dynamic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
@@ -13,18 +20,9 @@ using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Matrix42.Common;
|
||||
using Matrix42.WebApi.Contracts;
|
||||
using update4u.SPS.DataLayer;
|
||||
using update4u.SPS.DataLayer.Transaction;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using C4IT.F4SDM;
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.Logging;
|
||||
|
||||
using static C4IT.FASD.Base.cF4SDTicket;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace C4IT.F4SD
|
||||
@@ -52,11 +50,11 @@ namespace C4IT.F4SD
|
||||
|
||||
private const string placeHolderSubject = "PARAM_SUBJECT";
|
||||
private const string placeHolderDescription = "PARAM_DESCRIPTION";
|
||||
private static bool? ticketAndServiceRequestEnabledCache;
|
||||
private const string c4itf4sdmonLinkBase = "f4sdsend://localhost";
|
||||
|
||||
private const string F4SDTicketTableName = "M42WPM-TICKETS-INFOS";
|
||||
private const string F4SDTicketStatusColumnName = "STATUS";
|
||||
private static bool? ticketAndServiceRequestEnabledCache;
|
||||
|
||||
|
||||
public static IEnumerable<string> ReadLines(Func<Stream> streamProvider,
|
||||
@@ -73,6 +71,39 @@ namespace C4IT.F4SD
|
||||
}
|
||||
}
|
||||
|
||||
private static NameValueCollection ParseQueryString(string query)
|
||||
{
|
||||
var values = new NameValueCollection();
|
||||
query = (query ?? string.Empty).TrimStart('?');
|
||||
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
return values;
|
||||
|
||||
foreach (var pair in query.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var parts = pair.Split(new[] { '=' }, 2);
|
||||
var key = WebUtility.UrlDecode(parts[0]);
|
||||
var value = parts.Length > 1 ? WebUtility.UrlDecode(parts[1]) : string.Empty;
|
||||
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
values.Add(key, value);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
private static string ToQueryString(NameValueCollection queryString)
|
||||
{
|
||||
if (queryString == null || queryString.Count == 0)
|
||||
return string.Empty;
|
||||
|
||||
return string.Join("&",
|
||||
queryString.AllKeys
|
||||
.Where(key => !string.IsNullOrEmpty(key))
|
||||
.SelectMany(key => (queryString.GetValues(key) ?? new[] { string.Empty })
|
||||
.Select(value => $"{WebUtility.UrlEncode(key)}={WebUtility.UrlEncode(value)}")));
|
||||
}
|
||||
|
||||
internal async Task<string> getDirectLinkF4SD(Guid EOID, string type)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
@@ -81,7 +112,7 @@ namespace C4IT.F4SD
|
||||
{
|
||||
LogEntry($"Generating F4SD URI for type: '{type}', GUID: '{EOID}'", LogLevels.Debug);
|
||||
var builder = new UriBuilder(c4itf4sdmonLinkBase);
|
||||
var queryString = UrlQueryBuilder.Parse(builder.Query);
|
||||
var queryString = ParseQueryString(builder.Query);
|
||||
|
||||
switch (type.ToLowerInvariant().Split('.').Last())
|
||||
{
|
||||
@@ -140,7 +171,7 @@ namespace C4IT.F4SD
|
||||
break;
|
||||
}
|
||||
|
||||
builder.Query = queryString.ToString();
|
||||
builder.Query = ToQueryString(queryString);
|
||||
return string.IsNullOrEmpty(builder.Query) ? null : builder.ToString();
|
||||
}
|
||||
catch (Exception E)
|
||||
@@ -155,7 +186,6 @@ namespace C4IT.F4SD
|
||||
}
|
||||
|
||||
|
||||
[Obsolete]
|
||||
internal async Task<List<cF4SDTicketSummary>> getTicketListByUser(string userSid, int hours, int queueoption, List<cApiM42TicketQueueInfo> queues)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
@@ -269,116 +299,6 @@ namespace C4IT.F4SD
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<List<cF4SDTicketSummary>> getTicketListByUser(Guid userId, int hours, int queueoption, List<cApiM42TicketQueueInfo> queues)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
LogEntry($"Generating ticket list for userId: '{userId}', {hours} hours", LogLevels.Debug);
|
||||
await Task.Delay(0);
|
||||
|
||||
var tickets = new List<cF4SDTicketSummary>();
|
||||
var activityFilter = GetActivityFilter(userId, hours, ticketAndServiceRequestEnabled(), queueoption, queues);
|
||||
LogEntry($"ASql Filter: {activityFilter}");
|
||||
|
||||
var activityTable = FragmentRequestBase.SimpleLoad(SPSActivityClassBaseID,
|
||||
"[Expression-ObjectID] as EOID, TicketNumber, Subject, Service.ID as ServiceId, Service.Name as ServiceName, SUBQUERY(BasicSchemaObjectType as bso, bso.Name, bso.id = base.T(SPSCommonClassBase).TypeID) as ActivityType" +
|
||||
", COALESCE(T(SPSActivityClassIncident).Asset.T(SPSComputerClassBase).Name, T(SPSActivityClassIncident).Asset.T(SPSAssetClassSIMCard).PhoneNumber, T(SPSActivityClassIncident).Asset.Name, T(SPSActivityClassIncident).Asset.objectid) as AssetName" +
|
||||
", SUBQUERY(BasicSchemaObjectType AS t, t.Name, t.ID=base.T(SPSActivityClassIncident).Asset.T(SPSCommonClassBase).TypeID) as AssetCIName",
|
||||
activityFilter);
|
||||
|
||||
if (activityTable?.Rows == null || activityTable.Rows.Count == 0)
|
||||
{
|
||||
LogEntry($"No activity entries found for userId: '{userId}'", LogLevels.Warning);
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < activityTable.Rows.Count; i++)
|
||||
{
|
||||
DataRow entry = activityTable.Rows[i];
|
||||
var activityEOId = getGuidFromObject(entry["EOID"]);
|
||||
var ticketNumber = getStringFromObject(entry["TicketNumber"]);
|
||||
var activityType = getStringFromObject(entry["ActivityType"]);
|
||||
var assetName = getStringFromObject(entry["AssetName"]);
|
||||
var ServiceName = getStringFromObject(entry["ServiceName"]);
|
||||
var assetCIName = getStringFromObject(entry["AssetCIName"]);
|
||||
var subject = getStringFromObject(entry["Subject"]);
|
||||
|
||||
var stateData = GetActivityState(activityEOId);
|
||||
var state = stateData.Item1;
|
||||
var stateDisp = stateData.Item2;
|
||||
|
||||
LogEntry($"Activity found {i + 1}/{activityTable.Rows.Count}: ObjectID={activityEOId}, TicketNumber={ticketNumber}, Subject={subject}, State={state}", LogLevels.Debug);
|
||||
|
||||
if (string.IsNullOrEmpty(ticketNumber))
|
||||
{
|
||||
LogEntry($"No TicketNumber found for activity entry", LogLevels.Warning);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(assetName))
|
||||
{
|
||||
LogEntry($"No AssetName found for activity entry", LogLevels.Debug);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(assetCIName))
|
||||
{
|
||||
LogEntry($"No AssetCIName found for activity entry", LogLevels.Debug);
|
||||
}
|
||||
var ServiceId = getGuidFromObject(entry["ServiceId"]);
|
||||
if (ServiceId == Guid.Empty)
|
||||
{
|
||||
LogEntry($"no ServiceId found for activity entry", LogLevels.Debug);
|
||||
}
|
||||
var AssetCIName = getStringFromObject(entry["AssetCIName"]);
|
||||
if (AssetCIName == string.Empty)
|
||||
{
|
||||
LogEntry($"no AssetCIName found for activity entry", LogLevels.Debug);
|
||||
}
|
||||
var Subject = getStringFromObject(entry["Subject"]);
|
||||
if (Subject == string.Empty)
|
||||
{
|
||||
LogEntry($"no Subject found for activity entry", LogLevels.Warning);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(subject))
|
||||
{
|
||||
LogEntry($"No Subject found for activity entry", LogLevels.Warning);
|
||||
continue;
|
||||
}
|
||||
|
||||
tickets.Add(new cF4SDTicketSummary()
|
||||
{
|
||||
TicketObjectId = activityEOId,
|
||||
Name = ticketNumber,
|
||||
ActivityType = activityType,
|
||||
AssetCIName = assetCIName,
|
||||
AssetName = assetName,
|
||||
ServiceId = ServiceId,
|
||||
ServiceName = ServiceName,
|
||||
StatusId = state,
|
||||
Status = stateDisp,
|
||||
Summary = subject,
|
||||
IsPrimaryAccount = true
|
||||
});
|
||||
}
|
||||
|
||||
tickets = tickets.OrderByDescending(x => x.Name).ToList();
|
||||
return tickets;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly string[] TicketOverviewKeys = new[]
|
||||
{
|
||||
"TicketsNew",
|
||||
@@ -393,62 +313,6 @@ namespace C4IT.F4SD
|
||||
"UnassignedTicketsCritical"
|
||||
};
|
||||
|
||||
public class cF4SDTicket : cF4SDTicketSummary
|
||||
{
|
||||
public enum enumTicketCreationSource
|
||||
{
|
||||
Unknown = 0,
|
||||
Mail = 1,
|
||||
Phone = 2,
|
||||
F4SD = 3
|
||||
}
|
||||
|
||||
public class cTicketJournalItem
|
||||
{
|
||||
public DateTime CreationDate { get; set; }
|
||||
public string Header { get; set; }
|
||||
public string CreatedBy { get; set; }
|
||||
public string DescriptionHtml { get; set; }
|
||||
public string Description { get; set; }
|
||||
public bool IsVisibleForUser { get; set; }
|
||||
public Guid ActivityObjectId { get; set; }
|
||||
public Guid JournalId { get; set; }
|
||||
}
|
||||
|
||||
public Guid AffectedUserId { get; set; }
|
||||
public Guid AssetId { get; set; }
|
||||
public DateTime CreationDate { get; set; }
|
||||
public DateTime? ClosingDate { get; set; }
|
||||
public int CreationSourceId { get; set; }
|
||||
public string CreationSource { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
public string DescriptionHtml { get; set; }
|
||||
public int PriorityId { get; set; }
|
||||
public string Priority { get; set; }
|
||||
public Guid CategoryId { get; set; }
|
||||
public string Category { get; set; }
|
||||
public string CategoryHierarchical { get; set; }
|
||||
public string CIName { get; set; }
|
||||
public string DirectLinkEdit { get; set; }
|
||||
public Guid AssetCIId { get; set; }
|
||||
public int AssetSKUAssetGroupId { get; set; }
|
||||
public string AssetSKUAssetGroup { get; set; }
|
||||
public int AssetSKUTypeId { get; set; }
|
||||
public string AssetSKUType { get; set; }
|
||||
public string DirectLinkPreview { get; set; }
|
||||
public string DirectLinkClose { get; set; }
|
||||
public string AffectedUser { get; set; }
|
||||
public string SolutionHtml { get; set; }
|
||||
public string Solution { get; set; }
|
||||
public string AssetDomain { get; set; }
|
||||
public string Urgency { get; set; }
|
||||
public int UrgencyId { get; set; }
|
||||
public string Impact { get; set; }
|
||||
public int ImpactId { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class TicketOverviewCountsResult
|
||||
{
|
||||
[JsonProperty("counts")]
|
||||
@@ -497,7 +361,6 @@ namespace C4IT.F4SD
|
||||
public string ActivityType { get; set; }
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
internal async Task<TicketOverviewCountsResult> getTicketOverviewCounts(
|
||||
string sid,
|
||||
string scope,
|
||||
@@ -555,64 +418,6 @@ namespace C4IT.F4SD
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<TicketOverviewCountsResult> getTicketOverviewCounts(
|
||||
Guid userId,
|
||||
string scope,
|
||||
IEnumerable<string> keys,
|
||||
int queueoption,
|
||||
List<cApiM42TicketQueueInfo> queues)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
var useRoleScope = string.Equals(scope, "role", StringComparison.OrdinalIgnoreCase);
|
||||
var normalizedKeys = (keys ?? Array.Empty<string>())
|
||||
.Where(k => !string.IsNullOrWhiteSpace(k))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
if (normalizedKeys.Count == 0)
|
||||
{
|
||||
normalizedKeys.AddRange(TicketOverviewKeys);
|
||||
}
|
||||
|
||||
var entries = await LoadTicketOverviewEntries(userId, useRoleScope, queueoption, queues);
|
||||
List<TicketOverviewEntry> unassignedEntries = null;
|
||||
if (!useRoleScope && normalizedKeys.Any(IsUnassignedOverviewKey))
|
||||
{
|
||||
unassignedEntries = await LoadTicketOverviewUnassignedEntriesForPersonalScope(userId, queueoption, queues);
|
||||
}
|
||||
|
||||
var counts = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (var key in normalizedKeys)
|
||||
{
|
||||
if (!useRoleScope && IsUnassignedOverviewKey(key))
|
||||
{
|
||||
counts[key] = (unassignedEntries ?? new List<TicketOverviewEntry>())
|
||||
.Count(entry => MatchesTicketOverviewKey(entry, key));
|
||||
}
|
||||
else
|
||||
{
|
||||
counts[key] = entries.Count(entry => MatchesTicketOverviewKey(entry, key));
|
||||
}
|
||||
}
|
||||
|
||||
return new TicketOverviewCountsResult { Counts = counts };
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return new TicketOverviewCountsResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
internal async Task<TicketOverviewCountsByRoleResult> getTicketOverviewCountsByRoles(
|
||||
string sid,
|
||||
IEnumerable<Guid> roleGuids,
|
||||
@@ -676,70 +481,6 @@ namespace C4IT.F4SD
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<TicketOverviewCountsByRoleResult> getTicketOverviewCountsByRoles(
|
||||
Guid userId,
|
||||
IEnumerable<Guid> roleGuids,
|
||||
IEnumerable<string> keys,
|
||||
int queueoption,
|
||||
List<cApiM42TicketQueueInfo> queues)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
var normalizedKeys = (keys ?? Array.Empty<string>())
|
||||
.Where(k => !string.IsNullOrWhiteSpace(k))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
if (normalizedKeys.Count == 0)
|
||||
{
|
||||
normalizedKeys.AddRange(TicketOverviewKeys);
|
||||
}
|
||||
|
||||
var roleIds = await ResolveTicketOverviewRoleIdsAsync(userId, roleGuids);
|
||||
if (roleIds.Count == 0)
|
||||
return new TicketOverviewCountsByRoleResult();
|
||||
|
||||
var entries = await LoadTicketOverviewEntriesByRoleIds(roleIds, queueoption, queues);
|
||||
var entriesByRole = entries
|
||||
.GroupBy(entry => entry.RecipientRoleId)
|
||||
.ToDictionary(group => group.Key, group => group.ToList());
|
||||
|
||||
var countsByRole = new Dictionary<string, Dictionary<string, int>>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var roleId in roleIds)
|
||||
{
|
||||
var roleEntries = entriesByRole.TryGetValue(roleId, out var list)
|
||||
? list
|
||||
: new List<TicketOverviewEntry>();
|
||||
|
||||
var counts = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var key in normalizedKeys)
|
||||
{
|
||||
counts[key] = roleEntries.Count(entry => MatchesTicketOverviewKey(entry, key));
|
||||
}
|
||||
|
||||
countsByRole[roleId.ToString()] = counts;
|
||||
}
|
||||
|
||||
return new TicketOverviewCountsByRoleResult
|
||||
{
|
||||
GeneratedAtUtc = DateTime.UtcNow,
|
||||
CountsByRole = countsByRole
|
||||
};
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return new TicketOverviewCountsByRoleResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
internal async Task<List<TicketOverviewRelationDto>> getTicketOverviewRelations(
|
||||
string sid,
|
||||
string scope,
|
||||
@@ -819,86 +560,6 @@ namespace C4IT.F4SD
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<List<TicketOverviewRelationDto>> getTicketOverviewRelations(
|
||||
Guid userId,
|
||||
string scope,
|
||||
string key,
|
||||
int count,
|
||||
int queueoption,
|
||||
List<cApiM42TicketQueueInfo> queues)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(key))
|
||||
return new List<TicketOverviewRelationDto>();
|
||||
|
||||
var useRoleScope = string.Equals(scope, "role", StringComparison.OrdinalIgnoreCase);
|
||||
List<TicketOverviewEntry> entries;
|
||||
if (!useRoleScope && IsUnassignedOverviewKey(key))
|
||||
{
|
||||
entries = await LoadTicketOverviewUnassignedEntriesForPersonalScope(userId, queueoption, queues);
|
||||
}
|
||||
else
|
||||
{
|
||||
entries = await LoadTicketOverviewEntries(userId, useRoleScope, queueoption, queues);
|
||||
}
|
||||
|
||||
var filtered = entries
|
||||
.Where(entry => MatchesTicketOverviewKey(entry, key))
|
||||
.OrderByDescending(entry => entry.CreatedDate)
|
||||
.ToList();
|
||||
|
||||
if (count > 0)
|
||||
filtered = filtered.Take(count).ToList();
|
||||
|
||||
var relations = new List<TicketOverviewRelationDto>(filtered.Count);
|
||||
foreach (var entry in filtered)
|
||||
{
|
||||
var relation = new TicketOverviewRelationDto
|
||||
{
|
||||
Type = enumF4sdSearchResultClass.Ticket,
|
||||
DisplayName = entry.TicketNumber ?? string.Empty,
|
||||
Name = entry.TicketNumber ?? string.Empty,
|
||||
id = entry.TicketId,
|
||||
Status = enumF4sdSearchResultStatus.Active,
|
||||
Infos = new Dictionary<string, string>
|
||||
{
|
||||
["Summary"] = entry.Summary ?? string.Empty,
|
||||
["StatusId"] = ConvertM42State(entry.State),
|
||||
["ActivityType"] = entry.ActivityType ?? string.Empty,
|
||||
["UserDisplayName"] = entry.InitiatorDisplayName ?? string.Empty,
|
||||
["UserAccount"] = entry.InitiatorAccount ?? string.Empty,
|
||||
["UserDomain"] = entry.InitiatorDomain ?? string.Empty,
|
||||
["UserSid"] = entry.InitiatorSid ?? string.Empty,
|
||||
["Sids"] = entry.InitiatorSid ?? string.Empty,
|
||||
["UserId"] = entry.InitiatorId != Guid.Empty ? entry.InitiatorId.ToString() : string.Empty,
|
||||
["UserGuid"] = entry.InitiatorId != Guid.Empty ? entry.InitiatorId.ToString() : string.Empty
|
||||
},
|
||||
Identities = new List<cF4sdIdentityEntry>
|
||||
{
|
||||
new cF4sdIdentityEntry { Class = enumFasdInformationClass.Ticket, Id = entry.TicketId },
|
||||
new cF4sdIdentityEntry { Class = enumFasdInformationClass.User, Id = entry.InitiatorId }
|
||||
}
|
||||
};
|
||||
relations.Add(relation);
|
||||
}
|
||||
|
||||
return relations;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return new List<TicketOverviewRelationDto>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
private async Task<List<TicketOverviewEntry>> LoadTicketOverviewEntries(
|
||||
string sid,
|
||||
bool useRoleScope,
|
||||
@@ -928,34 +589,6 @@ namespace C4IT.F4SD
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<List<TicketOverviewEntry>> LoadTicketOverviewEntries(
|
||||
Guid userId,
|
||||
bool useRoleScope,
|
||||
int queueoption,
|
||||
List<cApiM42TicketQueueInfo> queues)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
if (userId == Guid.Empty)
|
||||
return new List<TicketOverviewEntry>();
|
||||
|
||||
var filter = await BuildTicketOverviewFilterAsync(userId, useRoleScope, queueoption, queues);
|
||||
return await LoadTicketOverviewEntriesByFilter(filter);
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return new List<TicketOverviewEntry>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
private async Task<List<TicketOverviewEntry>> LoadTicketOverviewUnassignedEntriesForPersonalScope(
|
||||
string sid,
|
||||
int queueoption,
|
||||
@@ -989,39 +622,6 @@ namespace C4IT.F4SD
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<List<TicketOverviewEntry>> LoadTicketOverviewUnassignedEntriesForPersonalScope(
|
||||
Guid userId,
|
||||
int queueoption,
|
||||
List<cApiM42TicketQueueInfo> queues)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
await Task.Delay(0);
|
||||
|
||||
if (userId == Guid.Empty)
|
||||
return new List<TicketOverviewEntry>();
|
||||
|
||||
var roleIds = await ResolveTicketOverviewRoleIdsAsync(userId, null);
|
||||
var filter = BuildTicketOverviewFilterForRoleIds(roleIds, null, queueoption, queues);
|
||||
if (string.IsNullOrWhiteSpace(filter))
|
||||
return new List<TicketOverviewEntry>();
|
||||
|
||||
filter += " AND Recipient IS NULL";
|
||||
return await LoadTicketOverviewEntriesByFilter(filter);
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return new List<TicketOverviewEntry>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<List<TicketOverviewEntry>> LoadTicketOverviewEntriesByRoleIds(
|
||||
IEnumerable<Guid> roleIds,
|
||||
int queueoption,
|
||||
@@ -1172,7 +772,6 @@ namespace C4IT.F4SD
|
||||
return null;
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
private async Task<string> BuildTicketOverviewFilterAsync(
|
||||
string sid,
|
||||
bool useRoleScope,
|
||||
@@ -1192,25 +791,6 @@ namespace C4IT.F4SD
|
||||
return BuildTicketOverviewFilterForRoleIds(roleIds, filter);
|
||||
}
|
||||
|
||||
private async Task<string> BuildTicketOverviewFilterAsync(
|
||||
Guid userId,
|
||||
bool useRoleScope,
|
||||
int queueoption,
|
||||
List<cApiM42TicketQueueInfo> queues)
|
||||
{
|
||||
var filter = BuildTicketOverviewBaseFilter(queueoption, queues);
|
||||
|
||||
if (!useRoleScope)
|
||||
{
|
||||
var recipientFilter = $"Recipient = '{Escape(userId.ToString("D"))}'";
|
||||
filter += $" AND ({recipientFilter})";
|
||||
return filter;
|
||||
}
|
||||
|
||||
var roleIds = await ResolveTicketOverviewRoleIdsAsync(userId, null);
|
||||
return BuildTicketOverviewFilterForRoleIds(roleIds, filter);
|
||||
}
|
||||
|
||||
private string BuildTicketOverviewBaseFilter(int queueoption, List<cApiM42TicketQueueInfo> queues)
|
||||
{
|
||||
var filter = "T(SPSCommonClassBase).State <> 204";
|
||||
@@ -1309,7 +889,6 @@ namespace C4IT.F4SD
|
||||
return filter;
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
private async Task<List<Guid>> ResolveTicketOverviewRoleIdsAsync(string sid, IEnumerable<Guid> roleGuids)
|
||||
{
|
||||
var roleIds = (roleGuids ?? Enumerable.Empty<Guid>())
|
||||
@@ -1335,26 +914,6 @@ namespace C4IT.F4SD
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private async Task<List<Guid>> ResolveTicketOverviewRoleIdsAsync(Guid userId, IEnumerable<Guid> roleGuids)
|
||||
{
|
||||
var roleIds = (roleGuids ?? Enumerable.Empty<Guid>())
|
||||
.Where(id => id != Guid.Empty)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
if (roleIds.Count > 0)
|
||||
return roleIds;
|
||||
|
||||
if (userId == Guid.Empty)
|
||||
return new List<Guid>();
|
||||
|
||||
var roles = await getRoleMembershipById(userId) ?? new List<M42Role>();
|
||||
return roles
|
||||
.Where(role => role != null && role.Id != Guid.Empty)
|
||||
.Select(role => role.Id)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
}
|
||||
private static bool IsUnassignedOverviewKey(string key)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(key))
|
||||
@@ -1462,8 +1021,6 @@ namespace C4IT.F4SD
|
||||
{
|
||||
return input?.Replace("'", "''");
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
private string GetActivityFilter(
|
||||
string userSid,
|
||||
int hours,
|
||||
@@ -1551,92 +1108,6 @@ namespace C4IT.F4SD
|
||||
return filter;
|
||||
}
|
||||
|
||||
private string GetActivityFilter(
|
||||
Guid userId,
|
||||
int hours,
|
||||
bool ticketAndServiceRequestEnabled,
|
||||
int queueoption,
|
||||
List<cApiM42TicketQueueInfo> queues
|
||||
)
|
||||
{
|
||||
// Baseline-Filter auf User und Datum
|
||||
var filter = $"Initiator = '{Escape(userId.ToString("D"))}'";
|
||||
|
||||
string fStartDate = AsqlHelper.PrepareDateTime(DateTime.UtcNow.AddHours(-hours), true);
|
||||
string fEndDate = AsqlHelper.PrepareDateTime(DateTime.UtcNow, true);
|
||||
|
||||
// Incident vs. Ticket/ServiceRequest
|
||||
if (ticketAndServiceRequestEnabled)
|
||||
{
|
||||
filter +=
|
||||
" AND (UsedInTypeSPSActivityTypeIncident IS NOT NULL" +
|
||||
" OR UsedInTypeSPSActivityTypeTicket IS NOT NULL" +
|
||||
" OR UsedInTypeSPSActivityTypeServiceRequest IS NOT NULL)";
|
||||
}
|
||||
else
|
||||
{
|
||||
filter += " AND (UsedInTypeSPSActivityTypeIncident IS NOT NULL)";
|
||||
}
|
||||
|
||||
// Offene bzw. kürzlich geschlossene Objekte
|
||||
filter +=
|
||||
" AND (T(SPSCommonClassBase).State <> 204" +
|
||||
$" OR (ClosedDate > {fStartDate} AND ClosedDate < {fEndDate}))";
|
||||
|
||||
// Queue-Filter nur, wenn tatsächlich Queues übergeben wurden
|
||||
if (queues != null && queues.Count > 0)
|
||||
{
|
||||
// URL-escaping für Name und ID
|
||||
var escapedNames = queues
|
||||
.Select(q => $"'{Escape(q.QueueName)}'")
|
||||
.ToList();
|
||||
var escapedIds = queues
|
||||
.Select(q => $"'{Escape(q.QueueID.ToString())}'")
|
||||
.ToList();
|
||||
|
||||
string nameList = string.Join(", ", escapedNames);
|
||||
string idList = string.Join(", ", escapedIds);
|
||||
|
||||
switch (queueoption)
|
||||
{
|
||||
// 1 = entweder keine Queue oder eine der übergebenen Queues (Name oder ID)
|
||||
case 1:
|
||||
filter +=
|
||||
$" AND (" +
|
||||
"Queue IS NULL" +
|
||||
$" OR Queue.Name IN ({nameList})" +
|
||||
$" OR Queue.ID IN ({idList})" +
|
||||
")";
|
||||
break;
|
||||
|
||||
// 2 = nur die übergebenen Queues (Name oder ID)
|
||||
case 2:
|
||||
filter +=
|
||||
$" AND (" +
|
||||
"Queue IS NOT NULL" +
|
||||
$" AND (Queue.Name IN ({nameList})" +
|
||||
$" OR Queue.ID IN ({idList}))" +
|
||||
")";
|
||||
break;
|
||||
|
||||
// 3 = nur Objekte ohne Queue
|
||||
case 3:
|
||||
filter += " AND Queue IS NULL";
|
||||
break;
|
||||
|
||||
// 0 oder andere = keine zusätzliche Einschränkung
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (queueoption == 3)
|
||||
{
|
||||
// Ausnahme: wenn keine Queues übergeben, aber Option 3 = nur ohne Queue
|
||||
filter += " AND Queue IS NULL";
|
||||
}
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
internal async Task<DirectLink> getDirectLinkCreateTicket(string sid, string assetname)
|
||||
{
|
||||
@@ -1929,21 +1400,21 @@ namespace C4IT.F4SD
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<List<cF4SDTicket.cTicketJournalItem>> GetJournalEntries(Guid activityEOID)
|
||||
internal async Task<List<cTicketJournalItem>> GetJournalEntries(Guid activityEOID)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
await Task.Delay(0);
|
||||
List<cF4SDTicket.cTicketJournalItem> journalEntries = new List<cF4SDTicket.cTicketJournalItem>();
|
||||
List<cTicketJournalItem> journalEntries = new List<cTicketJournalItem>();
|
||||
var entries = F4SDM42WebApiController.defaultInstance.GetJournalService().GetJournalList(activityEOID, false, 0, 50, "<a href=\"#\" class=\"mx-object-journal--link {0} {1}\">{2}</a>", 120);
|
||||
LogEntry($"{entries.Length} Journal entries found for ObjectID={activityEOID}", LogLevels.Debug);
|
||||
for (int i = 0; i < entries.Length; i++)
|
||||
{
|
||||
Matrix42.Contracts.Platform.Data.JournalEntryInfo item = entries[i];
|
||||
LogEntry($"Journal entry {i + 1}/{entries.Length}: ID={item.Id}, CreatedDate={item.CreatedDate}, CreatedBy={item.Creator}, Header={item.Header}", LogLevels.Debug);
|
||||
journalEntries.Add(new cF4SDTicket.cTicketJournalItem()
|
||||
journalEntries.Add(new cTicketJournalItem()
|
||||
{
|
||||
JournalId = item.Id,
|
||||
ActivityObjectId = activityEOID,
|
||||
@@ -2311,7 +1782,7 @@ namespace C4IT.F4SD
|
||||
}
|
||||
zipArchive.Dispose();
|
||||
memoryStream.Position = 0L;
|
||||
HttpResponseMessage httpResponseMessage = HttpResponseExtensions.CreateResponse(request, HttpStatusCode.OK);
|
||||
HttpResponseMessage httpResponseMessage = request.CreateResponse(HttpStatusCode.OK);
|
||||
httpResponseMessage.Content = new StreamContent(memoryStream);
|
||||
httpResponseMessage.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
|
||||
{
|
||||
@@ -2500,7 +1971,7 @@ namespace C4IT.F4SD
|
||||
try
|
||||
{
|
||||
await Task.Delay(0);
|
||||
var asqlFilter = string.Format("Members.Id = '{0}'", UserId.ToString("D"));
|
||||
var asqlFilter = string.Format("Members.Id = '{0}'", UserId.ToString());
|
||||
LogEntry($"ASql Filter: {asqlFilter}");
|
||||
|
||||
FragmentRequestBase fragmentRequestBase = new FragmentRequestBase(SPSSecurityClassRole, ColumnSelectOption.List, "Id as Id" +
|
||||
@@ -2721,41 +2192,4 @@ namespace C4IT.F4SD
|
||||
Roles = new List<M42Role>();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class UrlQueryBuilder
|
||||
{
|
||||
private readonly List<KeyValuePair<string, string>> _values = new List<KeyValuePair<string, string>>();
|
||||
|
||||
private UrlQueryBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
public static UrlQueryBuilder Parse(string query)
|
||||
{
|
||||
var builder = new UrlQueryBuilder();
|
||||
var normalizedQuery = (query ?? string.Empty).TrimStart('?');
|
||||
|
||||
foreach (var pair in normalizedQuery.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var separatorIndex = pair.IndexOf('=');
|
||||
var key = separatorIndex >= 0 ? pair.Substring(0, separatorIndex) : pair;
|
||||
var value = separatorIndex >= 0 ? pair.Substring(separatorIndex + 1) : string.Empty;
|
||||
|
||||
builder.Add(WebUtility.UrlDecode(key), WebUtility.UrlDecode(value));
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public void Add(string key, string value)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
_values.Add(new KeyValuePair<string, string>(key, value ?? string.Empty));
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Join("&", _values.Select(pair => $"{WebUtility.UrlEncode(pair.Key)}={WebUtility.UrlEncode(pair.Value)}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user