Rename WebApi activity filters to ticket filters

This commit is contained in:
Drechsler, Meik
2026-07-23 12:47:28 +02:00
parent 0af8981323
commit 60e2651641
12 changed files with 148 additions and 148 deletions

View File

@@ -91,13 +91,13 @@
<ItemGroup> <ItemGroup>
<Compile Include="cM42LogEntry.cs" /> <Compile Include="cM42LogEntry.cs" />
<Compile Include="ActivityFilterService.cs" /> <Compile Include="TicketFilterService.cs" />
<Compile Include="F4SDM42DependencyRegistrator.cs" /> <Compile Include="F4SDM42DependencyRegistrator.cs" />
<Compile Include="F4SDHelperService.cs" /> <Compile Include="F4SDHelperService.cs" />
<Compile Include="F4SDHelperService.UserId.cs" /> <Compile Include="F4SDHelperService.UserId.cs" />
<Compile Include="F4SDM42WebApiController.cs" /> <Compile Include="F4SDM42WebApiController.cs" />
<Compile Include="..\Shared\ActivityFilterCompiler.cs"> <Compile Include="..\Shared\TicketFilterCompiler.cs">
<Link>Shared\ActivityFilterCompiler.cs</Link> <Link>Shared\TicketFilterCompiler.cs</Link>
</Compile> </Compile>
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="..\SharedAssemblyInfo.cs"> <Compile Include="..\SharedAssemblyInfo.cs">

View File

@@ -23,7 +23,7 @@ namespace C4IT.F4SD
int hours, int hours,
int queueoption, int queueoption,
List<cApiM42TicketQueueInfo> queues, List<cApiM42TicketQueueInfo> queues,
cActivityFilterPolicy filters = null) cTicketFilterPolicy filters = null)
{ {
var method = MethodBase.GetCurrentMethod(); var method = MethodBase.GetCurrentMethod();
LogMethodBegin(method); LogMethodBegin(method);
@@ -34,7 +34,7 @@ namespace C4IT.F4SD
return new List<cF4SDTicketSummary>(); return new List<cF4SDTicketSummary>();
var activityFilter = GetActivityFilter(userId, hours, ticketAndServiceRequestEnabled(), queueoption, queues); var activityFilter = GetActivityFilter(userId, hours, ticketAndServiceRequestEnabled(), queueoption, queues);
activityFilter = await ApplyActivityFiltersAsync(activityFilter, filters); activityFilter = await ApplyTicketFiltersAsync(activityFilter, filters);
if (string.IsNullOrWhiteSpace(activityFilter)) if (string.IsNullOrWhiteSpace(activityFilter))
return new List<cF4SDTicketSummary>(); return new List<cF4SDTicketSummary>();
LogEntry($"Generating ticket list for userId '{userId}'. ASQL filter: {activityFilter}", LogLevels.Debug); LogEntry($"Generating ticket list for userId '{userId}'. ASQL filter: {activityFilter}", LogLevels.Debug);
@@ -96,7 +96,7 @@ namespace C4IT.F4SD
IEnumerable<string> keys, IEnumerable<string> keys,
int queueoption, int queueoption,
List<cApiM42TicketQueueInfo> queues, List<cApiM42TicketQueueInfo> queues,
cActivityFilterPolicy filters = null) cTicketFilterPolicy filters = null)
{ {
var method = MethodBase.GetCurrentMethod(); var method = MethodBase.GetCurrentMethod();
LogMethodBegin(method); LogMethodBegin(method);
@@ -144,7 +144,7 @@ namespace C4IT.F4SD
IEnumerable<string> keys, IEnumerable<string> keys,
int queueoption, int queueoption,
List<cApiM42TicketQueueInfo> queues, List<cApiM42TicketQueueInfo> queues,
cActivityFilterPolicy filters = null) cTicketFilterPolicy filters = null)
{ {
var roleIds = await ResolveTicketOverviewRoleIdsAsync(userId, roleGuids); var roleIds = await ResolveTicketOverviewRoleIdsAsync(userId, roleGuids);
return await getTicketOverviewCountsByRoles(null, roleIds, keys, queueoption, queues, filters); return await getTicketOverviewCountsByRoles(null, roleIds, keys, queueoption, queues, filters);
@@ -157,7 +157,7 @@ namespace C4IT.F4SD
int count, int count,
int queueoption, int queueoption,
List<cApiM42TicketQueueInfo> queues, List<cApiM42TicketQueueInfo> queues,
cActivityFilterPolicy filters = null) cTicketFilterPolicy filters = null)
{ {
var method = MethodBase.GetCurrentMethod(); var method = MethodBase.GetCurrentMethod();
LogMethodBegin(method); LogMethodBegin(method);
@@ -220,7 +220,7 @@ namespace C4IT.F4SD
bool useRoleScope, bool useRoleScope,
int queueoption, int queueoption,
List<cApiM42TicketQueueInfo> queues, List<cApiM42TicketQueueInfo> queues,
cActivityFilterPolicy filters = null) cTicketFilterPolicy filters = null)
{ {
if (userId == Guid.Empty) if (userId == Guid.Empty)
return new List<TicketOverviewEntry>(); return new List<TicketOverviewEntry>();
@@ -233,14 +233,14 @@ namespace C4IT.F4SD
Guid userId, Guid userId,
int queueoption, int queueoption,
List<cApiM42TicketQueueInfo> queues, List<cApiM42TicketQueueInfo> queues,
cActivityFilterPolicy filters = null) cTicketFilterPolicy filters = null)
{ {
if (userId == Guid.Empty) if (userId == Guid.Empty)
return new List<TicketOverviewEntry>(); return new List<TicketOverviewEntry>();
var roleIds = await ResolveTicketOverviewRoleIdsAsync(userId, null); var roleIds = await ResolveTicketOverviewRoleIdsAsync(userId, null);
var filter = BuildTicketOverviewFilterForRoleIds(roleIds, null, queueoption, queues); var filter = BuildTicketOverviewFilterForRoleIds(roleIds, null, queueoption, queues);
filter = await ApplyActivityFiltersAsync(filter, filters); filter = await ApplyTicketFiltersAsync(filter, filters);
if (string.IsNullOrWhiteSpace(filter)) if (string.IsNullOrWhiteSpace(filter))
return new List<TicketOverviewEntry>(); return new List<TicketOverviewEntry>();
@@ -252,15 +252,15 @@ namespace C4IT.F4SD
bool useRoleScope, bool useRoleScope,
int queueoption, int queueoption,
List<cApiM42TicketQueueInfo> queues, List<cApiM42TicketQueueInfo> queues,
cActivityFilterPolicy filters = null) cTicketFilterPolicy filters = null)
{ {
var filter = BuildTicketOverviewBaseFilter(queueoption, queues); var filter = BuildTicketOverviewBaseFilter(queueoption, queues);
if (!useRoleScope) if (!useRoleScope)
return await ApplyActivityFiltersAsync(filter + $" AND (Recipient = '{Escape(userId.ToString("D"))}')", filters); return await ApplyTicketFiltersAsync(filter + $" AND (Recipient = '{Escape(userId.ToString("D"))}')", filters);
var roleIds = await ResolveTicketOverviewRoleIdsAsync(userId, null); var roleIds = await ResolveTicketOverviewRoleIdsAsync(userId, null);
filter = BuildTicketOverviewFilterForRoleIds(roleIds, filter); filter = BuildTicketOverviewFilterForRoleIds(roleIds, filter);
return await ApplyActivityFiltersAsync(filter, filters); return await ApplyTicketFiltersAsync(filter, filters);
} }
private async Task<List<Guid>> ResolveTicketOverviewRoleIdsAsync(Guid userId, IEnumerable<Guid> roleGuids) private async Task<List<Guid>> ResolveTicketOverviewRoleIdsAsync(Guid userId, IEnumerable<Guid> roleGuids)

View File

@@ -186,7 +186,7 @@ namespace C4IT.F4SD
} }
internal async Task<List<cF4SDTicketSummary>> getTicketListByUser(string userSid, int hours, int queueoption, List<cApiM42TicketQueueInfo> queues, cActivityFilterPolicy filters = null) internal async Task<List<cF4SDTicketSummary>> getTicketListByUser(string userSid, int hours, int queueoption, List<cApiM42TicketQueueInfo> queues, cTicketFilterPolicy filters = null)
{ {
var CM = MethodBase.GetCurrentMethod(); var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM); LogMethodBegin(CM);
@@ -197,7 +197,7 @@ namespace C4IT.F4SD
var tickets = new List<cF4SDTicketSummary>(); var tickets = new List<cF4SDTicketSummary>();
var activityFilter = GetActivityFilter(userSid, hours, ticketAndServiceRequestEnabled(), queueoption, queues); var activityFilter = GetActivityFilter(userSid, hours, ticketAndServiceRequestEnabled(), queueoption, queues);
activityFilter = await ApplyActivityFiltersAsync(activityFilter, filters); activityFilter = await ApplyTicketFiltersAsync(activityFilter, filters);
if (string.IsNullOrWhiteSpace(activityFilter)) if (string.IsNullOrWhiteSpace(activityFilter))
return new List<cF4SDTicketSummary>(); return new List<cF4SDTicketSummary>();
LogEntry($"ASql Filter: {activityFilter}"); LogEntry($"ASql Filter: {activityFilter}");
@@ -383,7 +383,7 @@ namespace C4IT.F4SD
IEnumerable<string> keys, IEnumerable<string> keys,
int queueoption, int queueoption,
List<cApiM42TicketQueueInfo> queues, List<cApiM42TicketQueueInfo> queues,
cActivityFilterPolicy filters = null) cTicketFilterPolicy filters = null)
{ {
var CM = MethodBase.GetCurrentMethod(); var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM); LogMethodBegin(CM);
@@ -440,7 +440,7 @@ namespace C4IT.F4SD
IEnumerable<string> keys, IEnumerable<string> keys,
int queueoption, int queueoption,
List<cApiM42TicketQueueInfo> queues, List<cApiM42TicketQueueInfo> queues,
cActivityFilterPolicy filters = null) cTicketFilterPolicy filters = null)
{ {
var CM = MethodBase.GetCurrentMethod(); var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM); LogMethodBegin(CM);
@@ -505,7 +505,7 @@ namespace C4IT.F4SD
int count, int count,
int queueoption, int queueoption,
List<cApiM42TicketQueueInfo> queues, List<cApiM42TicketQueueInfo> queues,
cActivityFilterPolicy filters = null) cTicketFilterPolicy filters = null)
{ {
var CM = MethodBase.GetCurrentMethod(); var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM); LogMethodBegin(CM);
@@ -583,7 +583,7 @@ namespace C4IT.F4SD
bool useRoleScope, bool useRoleScope,
int queueoption, int queueoption,
List<cApiM42TicketQueueInfo> queues, List<cApiM42TicketQueueInfo> queues,
cActivityFilterPolicy filters = null) cTicketFilterPolicy filters = null)
{ {
var CM = MethodBase.GetCurrentMethod(); var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM); LogMethodBegin(CM);
@@ -612,7 +612,7 @@ namespace C4IT.F4SD
string sid, string sid,
int queueoption, int queueoption,
List<cApiM42TicketQueueInfo> queues, List<cApiM42TicketQueueInfo> queues,
cActivityFilterPolicy filters = null) cTicketFilterPolicy filters = null)
{ {
var CM = MethodBase.GetCurrentMethod(); var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM); LogMethodBegin(CM);
@@ -625,7 +625,7 @@ namespace C4IT.F4SD
var roleIds = await ResolveTicketOverviewRoleIdsAsync(sid, null); var roleIds = await ResolveTicketOverviewRoleIdsAsync(sid, null);
var filter = BuildTicketOverviewFilterForRoleIds(roleIds, null, queueoption, queues); var filter = BuildTicketOverviewFilterForRoleIds(roleIds, null, queueoption, queues);
filter = await ApplyActivityFiltersAsync(filter, filters); filter = await ApplyTicketFiltersAsync(filter, filters);
if (string.IsNullOrWhiteSpace(filter)) if (string.IsNullOrWhiteSpace(filter))
return new List<TicketOverviewEntry>(); return new List<TicketOverviewEntry>();
@@ -647,7 +647,7 @@ namespace C4IT.F4SD
IEnumerable<Guid> roleIds, IEnumerable<Guid> roleIds,
int queueoption, int queueoption,
List<cApiM42TicketQueueInfo> queues, List<cApiM42TicketQueueInfo> queues,
cActivityFilterPolicy filters = null) cTicketFilterPolicy filters = null)
{ {
var CM = MethodBase.GetCurrentMethod(); var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM); LogMethodBegin(CM);
@@ -656,7 +656,7 @@ namespace C4IT.F4SD
await Task.Delay(0); await Task.Delay(0);
var filter = BuildTicketOverviewFilterForRoleIds(roleIds, null, queueoption, queues); var filter = BuildTicketOverviewFilterForRoleIds(roleIds, null, queueoption, queues);
filter = await ApplyActivityFiltersAsync(filter, filters); filter = await ApplyTicketFiltersAsync(filter, filters);
return await LoadTicketOverviewEntriesByFilter(filter); return await LoadTicketOverviewEntriesByFilter(filter);
} }
catch (Exception E) catch (Exception E)
@@ -800,7 +800,7 @@ namespace C4IT.F4SD
bool useRoleScope, bool useRoleScope,
int queueoption, int queueoption,
List<cApiM42TicketQueueInfo> queues, List<cApiM42TicketQueueInfo> queues,
cActivityFilterPolicy filters = null) cTicketFilterPolicy filters = null)
{ {
var filter = BuildTicketOverviewBaseFilter(queueoption, queues); var filter = BuildTicketOverviewBaseFilter(queueoption, queues);
@@ -808,12 +808,12 @@ namespace C4IT.F4SD
{ {
var recipientFilter = $"Recipient.Accounts.T(SPSAccountClassAd).Sid = '{Escape(sid)}'"; var recipientFilter = $"Recipient.Accounts.T(SPSAccountClassAd).Sid = '{Escape(sid)}'";
filter += $" AND ({recipientFilter})"; filter += $" AND ({recipientFilter})";
return await ApplyActivityFiltersAsync(filter, filters); return await ApplyTicketFiltersAsync(filter, filters);
} }
var roleIds = await ResolveTicketOverviewRoleIdsAsync(sid, null); var roleIds = await ResolveTicketOverviewRoleIdsAsync(sid, null);
filter = BuildTicketOverviewFilterForRoleIds(roleIds, filter); filter = BuildTicketOverviewFilterForRoleIds(roleIds, filter);
return await ApplyActivityFiltersAsync(filter, filters); return await ApplyTicketFiltersAsync(filter, filters);
} }
private string BuildTicketOverviewBaseFilter(int queueoption, List<cApiM42TicketQueueInfo> queues) private string BuildTicketOverviewBaseFilter(int queueoption, List<cApiM42TicketQueueInfo> queues)

View File

@@ -155,7 +155,7 @@ namespace C4IT.F4SD
} }
[Route("v2/getTicketList"), HttpPost] [Route("v2/getTicketList"), HttpPost]
public async Task<List<cF4SDTicketSummary>> getTicketListV2([FromBody] cTicketActivityListRequest request) public async Task<List<cF4SDTicketSummary>> getTicketListV2([FromBody] cTicketListFilterRequest request)
{ {
if (request?.UserId != Guid.Empty) if (request?.UserId != Guid.Empty)
return await _f4stHelperService.getTicketListByUser( return await _f4stHelperService.getTicketListByUser(
@@ -388,10 +388,10 @@ namespace C4IT.F4SD
request?.Filters) ?? new List<F4SDHelperService.TicketOverviewRelationDto>(); request?.Filters) ?? new List<F4SDHelperService.TicketOverviewRelationDto>();
} }
[Route("v2/getActivityFilterCapabilities"), HttpGet] [Route("v2/getTicketFilterCapabilities"), HttpGet]
public cTicketActivityFilterCapabilities getActivityFilterCapabilitiesV2() public cTicketFilterCapabilities getTicketFilterCapabilitiesV2()
{ {
return _f4stHelperService.GetActivityFilterCapabilities(); return _f4stHelperService.GetTicketFilterCapabilities();
} }
/* /*
[Route("updateActivitySolution/{objectId}"), HttpPost] [Route("updateActivitySolution/{objectId}"), HttpPost]

View File

@@ -25,12 +25,12 @@ namespace C4IT.F4SD
private static readonly Dictionary<string, WorkspaceRoleCacheEntry> workspaceRoleCache = private static readonly Dictionary<string, WorkspaceRoleCacheEntry> workspaceRoleCache =
new Dictionary<string, WorkspaceRoleCacheEntry>(StringComparer.OrdinalIgnoreCase); new Dictionary<string, WorkspaceRoleCacheEntry>(StringComparer.OrdinalIgnoreCase);
internal async Task<string> ApplyActivityFiltersAsync(string baseFilter, cActivityFilterPolicy policy) internal async Task<string> ApplyTicketFiltersAsync(string baseFilter, cTicketFilterPolicy policy)
{ {
var result = await ActivityFilterCompiler.CompileAsync(policy, ResolveWorkspaceRolesAsync); var result = await TicketFilterCompiler.CompileAsync(policy, ResolveWorkspaceRolesAsync);
if (!result.Success) if (!result.Success)
{ {
LogEntry($"Activity filter rejected (fail closed): {result.Error}", LogLevels.Error); LogEntry($"Ticket filter rejected (fail closed): {result.Error}", LogLevels.Error);
return null; return null;
} }
@@ -39,22 +39,22 @@ namespace C4IT.F4SD
: $"({baseFilter}) AND ({result.Clause})"; : $"({baseFilter}) AND ({result.Clause})";
} }
internal cTicketActivityFilterCapabilities GetActivityFilterCapabilities() internal cTicketFilterCapabilities GetTicketFilterCapabilities()
{ {
var capabilities = new cTicketActivityFilterCapabilities var capabilities = new cTicketFilterCapabilities
{ {
Provider = ActivityFilterCompiler.ProviderName, Provider = TicketFilterCompiler.ProviderName,
CommonFields = new List<string> { ActivityFilterCompiler.AssignmentGroupField }, CommonFields = new List<string> { TicketFilterCompiler.AssignmentGroupField },
ProviderFields = new List<string> { ActivityFilterCompiler.QueueField } ProviderFields = new List<string> { TicketFilterCompiler.QueueField }
}; };
if (SPSDataEngineSchemaReader.ClassGetIDFromName("ESMWorkspaceClassBase") != Guid.Empty) if (SPSDataEngineSchemaReader.ClassGetIDFromName("ESMWorkspaceClassBase") != Guid.Empty)
capabilities.ProviderFields.Add(ActivityFilterCompiler.WorkspaceField); capabilities.ProviderFields.Add(TicketFilterCompiler.WorkspaceField);
return capabilities; return capabilities;
} }
private async Task<ActivityFilterResolution> ResolveWorkspaceRolesAsync(cActivityFilter filter) private async Task<TicketFilterResolution> ResolveWorkspaceRolesAsync(cTicketFilter filter)
{ {
await Task.Delay(0); await Task.Delay(0);
var workspaceClassId = SPSDataEngineSchemaReader.ClassGetIDFromName("ESMWorkspaceClassBase"); var workspaceClassId = SPSDataEngineSchemaReader.ClassGetIDFromName("ESMWorkspaceClassBase");
@@ -62,7 +62,7 @@ namespace C4IT.F4SD
return WorkspaceFailure("ESMWorkspaceClassBase is not available."); return WorkspaceFailure("ESMWorkspaceClassBase is not available.");
var roleIds = new HashSet<Guid>(); var roleIds = new HashSet<Guid>();
foreach (var value in filter?.Values ?? new List<cActivityFilterValue>()) foreach (var value in filter?.Values ?? new List<cTicketFilterValue>())
{ {
var key = !string.IsNullOrWhiteSpace(value?.ID) var key = !string.IsNullOrWhiteSpace(value?.ID)
? "id:" + value.ID.Trim() ? "id:" + value.ID.Trim()
@@ -125,7 +125,7 @@ namespace C4IT.F4SD
roleIds.UnionWith(resolved); roleIds.UnionWith(resolved);
} }
return new ActivityFilterResolution return new TicketFilterResolution
{ {
Success = true, Success = true,
RoleIds = roleIds.ToList() RoleIds = roleIds.ToList()
@@ -167,9 +167,9 @@ namespace C4IT.F4SD
} }
} }
private static ActivityFilterResolution WorkspaceFailure(string error) private static TicketFilterResolution WorkspaceFailure(string error)
{ {
return new ActivityFilterResolution return new TicketFilterResolution
{ {
Success = false, Success = false,
Error = error Error = error

View File

@@ -1,63 +0,0 @@
using System.Collections.Generic;
using System;
using System.Threading;
using System.Threading.Tasks;
using C4IT.FASD.Base;
using C4IT.Logging;
using static C4IT.Logging.cLogManager;
namespace C4IT.F4SD
{
public partial class F4SDHelperService
{
private static readonly AsyncLocal<cActivityFilterPolicy> currentActivityFilters =
new AsyncLocal<cActivityFilterPolicy>();
private sealed class ActivityFilterScope : IDisposable
{
private readonly cActivityFilterPolicy previous;
public ActivityFilterScope(cActivityFilterPolicy filters)
{
previous = currentActivityFilters.Value;
currentActivityFilters.Value = filters;
}
public void Dispose()
{
currentActivityFilters.Value = previous;
}
}
internal IDisposable BeginActivityFilterScope(cActivityFilterPolicy filters)
{
return new ActivityFilterScope(filters);
}
internal async Task<string> ApplyActivityFiltersAsync(string baseFilter, cActivityFilterPolicy policy)
{
var result = await ActivityFilterCompiler.CompileAsync(policy ?? currentActivityFilters.Value, null);
if (!result.Success)
{
LogEntry($"Activity filter rejected (fail closed): {result.Error}", LogLevels.Error);
return null;
}
return string.IsNullOrWhiteSpace(result.Clause)
? baseFilter
: $"({baseFilter}) AND ({result.Clause})";
}
internal cTicketActivityFilterCapabilities GetActivityFilterCapabilities()
{
return new cTicketActivityFilterCapabilities
{
Provider = ActivityFilterCompiler.ProviderName,
CommonFields = new List<string> { ActivityFilterCompiler.AssignmentGroupField },
ProviderFields = new List<string> { ActivityFilterCompiler.QueueField }
};
}
}
}

View File

@@ -54,10 +54,10 @@
<ItemGroup> <ItemGroup>
<Compile Include="cM42LogEntry.cs" /> <Compile Include="cM42LogEntry.cs" />
<Compile Include="ActivityFilterService.cs" /> <Compile Include="TicketFilterService.cs" />
<Compile Include="F4SDHelperService.cs" /> <Compile Include="F4SDHelperService.cs" />
<Compile Include="F4SDM42WebApiController.cs" /> <Compile Include="F4SDM42WebApiController.cs" />
<Compile Include="..\..\Shared\ActivityFilterCompiler.cs"><Link>Shared\ActivityFilterCompiler.cs</Link></Compile> <Compile Include="..\..\Shared\TicketFilterCompiler.cs"><Link>Shared\TicketFilterCompiler.cs</Link></Compile>
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="..\..\SharedAssemblyInfo.cs"><Link>Properties\SharedAssemblyInfo.cs</Link></Compile> <Compile Include="..\..\SharedAssemblyInfo.cs"><Link>Properties\SharedAssemblyInfo.cs</Link></Compile>
</ItemGroup> </ItemGroup>

View File

@@ -166,7 +166,7 @@ namespace C4IT.F4SD
var tickets = new List<cF4SDTicketSummary>(); var tickets = new List<cF4SDTicketSummary>();
var activityFilter = GetActivityFilter(userSid, hours, ticketAndServiceRequestEnabled(), queueoption, queues); var activityFilter = GetActivityFilter(userSid, hours, ticketAndServiceRequestEnabled(), queueoption, queues);
activityFilter = await ApplyActivityFiltersAsync(activityFilter, null); activityFilter = await ApplyTicketFiltersAsync(activityFilter, null);
if (string.IsNullOrWhiteSpace(activityFilter)) if (string.IsNullOrWhiteSpace(activityFilter))
return new List<cF4SDTicketSummary>(); return new List<cF4SDTicketSummary>();
LogEntry($"ASql Filter: {activityFilter}"); LogEntry($"ASql Filter: {activityFilter}");
@@ -282,7 +282,7 @@ namespace C4IT.F4SD
var tickets = new List<cF4SDTicketSummary>(); var tickets = new List<cF4SDTicketSummary>();
var activityFilter = GetActivityFilter(userId, hours, ticketAndServiceRequestEnabled(), queueoption, queues); var activityFilter = GetActivityFilter(userId, hours, ticketAndServiceRequestEnabled(), queueoption, queues);
activityFilter = await ApplyActivityFiltersAsync(activityFilter, null); activityFilter = await ApplyTicketFiltersAsync(activityFilter, null);
if (string.IsNullOrWhiteSpace(activityFilter)) if (string.IsNullOrWhiteSpace(activityFilter))
return new List<cF4SDTicketSummary>(); return new List<cF4SDTicketSummary>();
LogEntry($"ASql Filter: {activityFilter}"); LogEntry($"ASql Filter: {activityFilter}");
@@ -988,7 +988,7 @@ namespace C4IT.F4SD
var roleIds = await ResolveTicketOverviewRoleIdsAsync(sid, null); var roleIds = await ResolveTicketOverviewRoleIdsAsync(sid, null);
var filter = BuildTicketOverviewFilterForRoleIds(roleIds, null, queueoption, queues); var filter = BuildTicketOverviewFilterForRoleIds(roleIds, null, queueoption, queues);
filter = await ApplyActivityFiltersAsync(filter, null); filter = await ApplyTicketFiltersAsync(filter, null);
if (string.IsNullOrWhiteSpace(filter)) if (string.IsNullOrWhiteSpace(filter))
return new List<TicketOverviewEntry>(); return new List<TicketOverviewEntry>();
@@ -1022,7 +1022,7 @@ namespace C4IT.F4SD
var roleIds = await ResolveTicketOverviewRoleIdsAsync(userId, null); var roleIds = await ResolveTicketOverviewRoleIdsAsync(userId, null);
var filter = BuildTicketOverviewFilterForRoleIds(roleIds, null, queueoption, queues); var filter = BuildTicketOverviewFilterForRoleIds(roleIds, null, queueoption, queues);
filter = await ApplyActivityFiltersAsync(filter, null); filter = await ApplyTicketFiltersAsync(filter, null);
if (string.IsNullOrWhiteSpace(filter)) if (string.IsNullOrWhiteSpace(filter))
return new List<TicketOverviewEntry>(); return new List<TicketOverviewEntry>();
@@ -1052,7 +1052,7 @@ namespace C4IT.F4SD
await Task.Delay(0); await Task.Delay(0);
var filter = BuildTicketOverviewFilterForRoleIds(roleIds, null, queueoption, queues); var filter = BuildTicketOverviewFilterForRoleIds(roleIds, null, queueoption, queues);
filter = await ApplyActivityFiltersAsync(filter, null); filter = await ApplyTicketFiltersAsync(filter, null);
return await LoadTicketOverviewEntriesByFilter(filter); return await LoadTicketOverviewEntriesByFilter(filter);
} }
catch (Exception E) catch (Exception E)
@@ -1204,12 +1204,12 @@ namespace C4IT.F4SD
{ {
var recipientFilter = $"Recipient.Accounts.T(SPSAccountClassAd).Sid = '{Escape(sid)}'"; var recipientFilter = $"Recipient.Accounts.T(SPSAccountClassAd).Sid = '{Escape(sid)}'";
filter += $" AND ({recipientFilter})"; filter += $" AND ({recipientFilter})";
return await ApplyActivityFiltersAsync(filter, null); return await ApplyTicketFiltersAsync(filter, null);
} }
var roleIds = await ResolveTicketOverviewRoleIdsAsync(sid, null); var roleIds = await ResolveTicketOverviewRoleIdsAsync(sid, null);
filter = BuildTicketOverviewFilterForRoleIds(roleIds, filter); filter = BuildTicketOverviewFilterForRoleIds(roleIds, filter);
return await ApplyActivityFiltersAsync(filter, null); return await ApplyTicketFiltersAsync(filter, null);
} }
private async Task<string> BuildTicketOverviewFilterAsync( private async Task<string> BuildTicketOverviewFilterAsync(
@@ -1224,12 +1224,12 @@ namespace C4IT.F4SD
{ {
var recipientFilter = $"Recipient = '{Escape(userId.ToString("D"))}'"; var recipientFilter = $"Recipient = '{Escape(userId.ToString("D"))}'";
filter += $" AND ({recipientFilter})"; filter += $" AND ({recipientFilter})";
return await ApplyActivityFiltersAsync(filter, null); return await ApplyTicketFiltersAsync(filter, null);
} }
var roleIds = await ResolveTicketOverviewRoleIdsAsync(userId, null); var roleIds = await ResolveTicketOverviewRoleIdsAsync(userId, null);
filter = BuildTicketOverviewFilterForRoleIds(roleIds, filter); filter = BuildTicketOverviewFilterForRoleIds(roleIds, filter);
return await ApplyActivityFiltersAsync(filter, null); return await ApplyTicketFiltersAsync(filter, null);
} }
private string BuildTicketOverviewBaseFilter(int queueoption, List<cApiM42TicketQueueInfo> queues) private string BuildTicketOverviewBaseFilter(int queueoption, List<cApiM42TicketQueueInfo> queues)

View File

@@ -139,9 +139,9 @@ namespace C4IT.F4SD
} }
[Route("v2/getTicketList"), HttpPost] [Route("v2/getTicketList"), HttpPost]
public async Task<List<cF4SDTicketSummary>> getTicketListV2([FromBody] cTicketActivityListRequest request) public async Task<List<cF4SDTicketSummary>> getTicketListV2([FromBody] cTicketListFilterRequest request)
{ {
using (_f4stHelperService.BeginActivityFilterScope(request?.Filters)) using (_f4stHelperService.BeginTicketFilterScope(request?.Filters))
{ {
if (request?.UserId != Guid.Empty) if (request?.UserId != Guid.Empty)
return await _f4stHelperService.getTicketListByUser( return await _f4stHelperService.getTicketListByUser(
@@ -217,7 +217,7 @@ namespace C4IT.F4SD
public async Task<F4SDHelperService.TicketOverviewCountsResult> getTicketOverviewCountsV2( public async Task<F4SDHelperService.TicketOverviewCountsResult> getTicketOverviewCountsV2(
[FromBody] cTicketOverviewFilterRequest request) [FromBody] cTicketOverviewFilterRequest request)
{ {
using (_f4stHelperService.BeginActivityFilterScope(request?.Filters)) using (_f4stHelperService.BeginTicketFilterScope(request?.Filters))
{ {
if (request?.UserId != Guid.Empty) if (request?.UserId != Guid.Empty)
return await _f4stHelperService.getTicketOverviewCounts( return await _f4stHelperService.getTicketOverviewCounts(
@@ -316,7 +316,7 @@ namespace C4IT.F4SD
public async Task<List<F4SDHelperService.TicketOverviewRelationDto>> getTicketOverviewRelationsV2( public async Task<List<F4SDHelperService.TicketOverviewRelationDto>> getTicketOverviewRelationsV2(
[FromBody] cTicketOverviewFilterRequest request) [FromBody] cTicketOverviewFilterRequest request)
{ {
using (_f4stHelperService.BeginActivityFilterScope(request?.Filters)) using (_f4stHelperService.BeginTicketFilterScope(request?.Filters))
{ {
if (request?.UserId != Guid.Empty) if (request?.UserId != Guid.Empty)
return await _f4stHelperService.getTicketOverviewRelations( return await _f4stHelperService.getTicketOverviewRelations(
@@ -337,10 +337,10 @@ namespace C4IT.F4SD
} }
} }
[Route("v2/getActivityFilterCapabilities"), HttpGet] [Route("v2/getTicketFilterCapabilities"), HttpGet]
public cTicketActivityFilterCapabilities getActivityFilterCapabilitiesV2() public cTicketFilterCapabilities getTicketFilterCapabilitiesV2()
{ {
return _f4stHelperService.GetActivityFilterCapabilities(); return _f4stHelperService.GetTicketFilterCapabilities();
} }

View File

@@ -0,0 +1,63 @@
using System.Collections.Generic;
using System;
using System.Threading;
using System.Threading.Tasks;
using C4IT.FASD.Base;
using C4IT.Logging;
using static C4IT.Logging.cLogManager;
namespace C4IT.F4SD
{
public partial class F4SDHelperService
{
private static readonly AsyncLocal<cTicketFilterPolicy> currentTicketFilters =
new AsyncLocal<cTicketFilterPolicy>();
private sealed class TicketFilterScope : IDisposable
{
private readonly cTicketFilterPolicy previous;
public TicketFilterScope(cTicketFilterPolicy filters)
{
previous = currentTicketFilters.Value;
currentTicketFilters.Value = filters;
}
public void Dispose()
{
currentTicketFilters.Value = previous;
}
}
internal IDisposable BeginTicketFilterScope(cTicketFilterPolicy filters)
{
return new TicketFilterScope(filters);
}
internal async Task<string> ApplyTicketFiltersAsync(string baseFilter, cTicketFilterPolicy policy)
{
var result = await TicketFilterCompiler.CompileAsync(policy ?? currentTicketFilters.Value, null);
if (!result.Success)
{
LogEntry($"Ticket filter rejected (fail closed): {result.Error}", LogLevels.Error);
return null;
}
return string.IsNullOrWhiteSpace(result.Clause)
? baseFilter
: $"({baseFilter}) AND ({result.Clause})";
}
internal cTicketFilterCapabilities GetTicketFilterCapabilities()
{
return new cTicketFilterCapabilities
{
Provider = TicketFilterCompiler.ProviderName,
CommonFields = new List<string> { TicketFilterCompiler.AssignmentGroupField },
ProviderFields = new List<string> { TicketFilterCompiler.QueueField }
};
}
}
}

View File

@@ -7,40 +7,40 @@ using C4IT.FASD.Base;
namespace C4IT.F4SD namespace C4IT.F4SD
{ {
internal sealed class ActivityFilterResolution internal sealed class TicketFilterResolution
{ {
public bool Success { get; set; } public bool Success { get; set; }
public string Error { get; set; } public string Error { get; set; }
public List<Guid> RoleIds { get; set; } = new List<Guid>(); public List<Guid> RoleIds { get; set; } = new List<Guid>();
} }
internal sealed class ActivityFilterCompilationResult internal sealed class TicketFilterCompilationResult
{ {
public bool Success { get; set; } public bool Success { get; set; }
public string Clause { get; set; } public string Clause { get; set; }
public string Error { get; set; } public string Error { get; set; }
} }
internal static class ActivityFilterCompiler internal static class TicketFilterCompiler
{ {
internal const string ProviderName = "Matrix42"; internal const string ProviderName = "Matrix42";
internal const string AssignmentGroupField = "AssignmentGroup"; internal const string AssignmentGroupField = "AssignmentGroup";
internal const string QueueField = "Queue"; internal const string QueueField = "Queue";
internal const string WorkspaceField = "Workspace"; internal const string WorkspaceField = "Workspace";
internal static async Task<ActivityFilterCompilationResult> CompileAsync( internal static async Task<TicketFilterCompilationResult> CompileAsync(
cActivityFilterPolicy policy, cTicketFilterPolicy policy,
Func<cActivityFilter, Task<ActivityFilterResolution>> workspaceResolver) Func<cTicketFilter, Task<TicketFilterResolution>> workspaceResolver)
{ {
var clauses = new List<string>(); var clauses = new List<string>();
foreach (var filter in policy?.Filters ?? new List<cActivityFilter>()) foreach (var filter in policy?.Filters ?? new List<cTicketFilter>())
{ {
if (filter == null || !filter.Enabled) if (filter == null || !filter.Enabled)
continue; continue;
var providerSpecific = !string.IsNullOrWhiteSpace(filter.Provider); var providerSpecific = !string.IsNullOrWhiteSpace(filter.Provider);
if (providerSpecific && !string.Equals(filter.Provider, ProviderName, StringComparison.OrdinalIgnoreCase)) if (providerSpecific && !string.Equals(filter.Provider, ProviderName, StringComparison.OrdinalIgnoreCase))
return Fail($"Unsupported activity filter provider '{filter.Provider}'."); return Fail($"Unsupported ticket filter provider '{filter.Provider}'.");
var field = filter.Field?.Trim(); var field = filter.Field?.Trim();
string emptyClause; string emptyClause;
@@ -70,37 +70,37 @@ namespace C4IT.F4SD
} }
else else
{ {
return Fail($"Unsupported activity filter field '{filter.Provider}:{field}'."); return Fail($"Unsupported ticket filter field '{filter.Provider}:{field}'.");
} }
if (filter.EmptyHandling == enumActivityFilterEmptyHandling.only) if (filter.EmptyHandling == enumTicketFilterEmptyHandling.only)
{ {
clauses.Add($"({emptyClause})"); clauses.Add($"({emptyClause})");
continue; continue;
} }
if (string.IsNullOrWhiteSpace(valueClause)) if (string.IsNullOrWhiteSpace(valueClause))
return Fail($"Activity filter '{filter.Provider}:{field}' has no valid values."); return Fail($"Ticket filter '{filter.Provider}:{field}' has no valid values.");
var matchClause = filter.Match == enumActivityFilterMatch.exclude var matchClause = filter.Match == enumTicketFilterMatch.exclude
? $"NOT ({valueClause})" ? $"NOT ({valueClause})"
: $"({valueClause})"; : $"({valueClause})";
clauses.Add(filter.EmptyHandling == enumActivityFilterEmptyHandling.include clauses.Add(filter.EmptyHandling == enumTicketFilterEmptyHandling.include
? $"(({emptyClause}) OR ({matchClause}))" ? $"(({emptyClause}) OR ({matchClause}))"
: $"((NOT ({emptyClause})) AND ({matchClause}))"); : $"((NOT ({emptyClause})) AND ({matchClause}))");
} }
return new ActivityFilterCompilationResult return new TicketFilterCompilationResult
{ {
Success = true, Success = true,
Clause = string.Join(" AND ", clauses) Clause = string.Join(" AND ", clauses)
}; };
} }
private static string BuildValueClause(string idField, string nameField, IEnumerable<cActivityFilterValue> values) private static string BuildValueClause(string idField, string nameField, IEnumerable<cTicketFilterValue> values)
{ {
var items = (values ?? Enumerable.Empty<cActivityFilterValue>()) var items = (values ?? Enumerable.Empty<cTicketFilterValue>())
.Where(value => value != null) .Where(value => value != null)
.ToList(); .ToList();
var ids = items var ids = items
@@ -139,9 +139,9 @@ namespace C4IT.F4SD
return $"'{(value ?? string.Empty).Replace("'", "''")}'"; return $"'{(value ?? string.Empty).Replace("'", "''")}'";
} }
private static ActivityFilterCompilationResult Fail(string error) private static TicketFilterCompilationResult Fail(string error)
{ {
return new ActivityFilterCompilationResult return new TicketFilterCompilationResult
{ {
Success = false, Success = false,
Error = error Error = error

View File

@@ -1036,17 +1036,17 @@
] ]
}, },
{ {
"name": "06 Activity Filter APIs v2", "name": "06 Ticket Filter APIs v2",
"item": [ "item": [
{ {
"name": "get activity filter capabilities", "name": "get ticket filter capabilities",
"request": { "request": {
"method": "GET", "method": "GET",
"header": [{ "key": "Accept", "value": "application/json" }], "header": [{ "key": "Accept", "value": "application/json" }],
"url": { "url": {
"raw": "{{baseUrl}}/api/c4itf4sdwebapi/v2/getActivityFilterCapabilities", "raw": "{{baseUrl}}/api/c4itf4sdwebapi/v2/getTicketFilterCapabilities",
"host": ["{{baseUrl}}"], "host": ["{{baseUrl}}"],
"path": ["api", "c4itf4sdwebapi", "v2", "getActivityFilterCapabilities"] "path": ["api", "c4itf4sdwebapi", "v2", "getTicketFilterCapabilities"]
} }
} }
}, },