feat: support parallel legacy and sandbox extensions
This commit is contained in:
@@ -40,7 +40,7 @@ if (-not (Test-Path -LiteralPath (Join-Path $templateDirFull 'package.json'))) {
|
||||
throw "Package template not found: $templateDirFull"
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath (Join-Path $assembliesDirFull 'C4ITF4SDM42WebApi.dll'))) {
|
||||
if (-not (Get-ChildItem -LiteralPath $assembliesDirFull -Filter 'C4ITF4SDM42WebApi.dll' -File -Recurse | Select-Object -First 1)) {
|
||||
throw "Package assemblies not found: $assembliesDirFull"
|
||||
}
|
||||
|
||||
@@ -53,8 +53,12 @@ if (Test-Path -LiteralPath $zipPath) {
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Path $packageDir -Force | Out-Null
|
||||
Copy-Item -Path (Join-Path $templateDirFull '*') -Destination $packageDir -Recurse -Force
|
||||
Copy-Item -Path $assembliesDirFull -Destination (Join-Path $packageDir 'Assemblies') -Recurse -Force
|
||||
Copy-Item -Path (Join-Path $templateDirFull '*') -Destination $packageDir -Recurse -Force
|
||||
$packageAssembliesPath = Join-Path $packageDir 'Assemblies'
|
||||
if (Test-Path -LiteralPath $packageAssembliesPath) {
|
||||
Remove-Item -LiteralPath $packageAssembliesPath -Recurse -Force
|
||||
}
|
||||
Copy-Item -Path $assembliesDirFull -Destination $packageAssembliesPath -Recurse -Force
|
||||
|
||||
$packageJsonPath = Join-Path $packageDir 'package.json'
|
||||
$packageJson = [System.IO.File]::ReadAllText($packageJsonPath)
|
||||
@@ -62,24 +66,22 @@ $packageJson = [regex]::Replace($packageJson, '"Version"\s*:\s*"[^"]+"', "`"Vers
|
||||
$packageJson = [regex]::Replace($packageJson, '"LastUpdatedDate"\s*:\s*"[^"]+"', "`"LastUpdatedDate`": `"$(Get-Date -Format 'yyyy-MM-ddTHH:mm:ss')`"")
|
||||
[System.IO.File]::WriteAllText($packageJsonPath, $packageJson, [System.Text.UTF8Encoding]::new($true))
|
||||
|
||||
$configDataPath = Join-Path $packageDir 'install\1010_Config_Data\02-01-0080 C4IT_F4SDConfigurationType.dat'
|
||||
if (-not (Test-Path -LiteralPath $configDataPath)) {
|
||||
throw "Configuration data file not found: $configDataPath"
|
||||
}
|
||||
|
||||
$configData = [System.IO.File]::ReadAllText($configDataPath)
|
||||
$configData = [regex]::Replace(
|
||||
$configData,
|
||||
'(<C4IT_AddonConfigClassBase>[\s\S]*?<Version>)[^<]*(</Version>)',
|
||||
"`${1}$PackageVersion`${2}",
|
||||
[System.Text.RegularExpressions.RegexOptions]::Singleline
|
||||
)
|
||||
|
||||
if ($configData -notmatch "<Version>$([regex]::Escape($PackageVersion))</Version>") {
|
||||
throw "Could not update C4IT_F4SDConfigurationType Version to $PackageVersion in $configDataPath"
|
||||
}
|
||||
|
||||
[System.IO.File]::WriteAllText($configDataPath, $configData, [System.Text.UTF8Encoding]::new($true))
|
||||
$configDataPath = Join-Path $packageDir 'install\1010_Config_Data\02-01-0080 C4IT_F4SDConfigurationType.dat'
|
||||
if (Test-Path -LiteralPath $configDataPath) {
|
||||
$configData = [System.IO.File]::ReadAllText($configDataPath)
|
||||
$configData = [regex]::Replace(
|
||||
$configData,
|
||||
'(<C4IT_AddonConfigClassBase>[\s\S]*?<Version>)[^<]*(</Version>)',
|
||||
"`${1}$PackageVersion`${2}",
|
||||
[System.Text.RegularExpressions.RegexOptions]::Singleline
|
||||
)
|
||||
|
||||
if ($configData -notmatch "<Version>$([regex]::Escape($PackageVersion))</Version>") {
|
||||
throw "Could not update C4IT_F4SDConfigurationType Version to $PackageVersion in $configDataPath"
|
||||
}
|
||||
|
||||
[System.IO.File]::WriteAllText($configDataPath, $configData, [System.Text.UTF8Encoding]::new($true))
|
||||
}
|
||||
|
||||
$textFileExtensions = @('.json', '.xml', '.dat', '.type', '.class', '.config', '.host')
|
||||
Get-ChildItem -LiteralPath $packageDir -Recurse -File |
|
||||
|
||||
@@ -92,7 +92,8 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="cM42LogEntry.cs" />
|
||||
<Compile Include="F4SDM42DependencyRegistrator.cs" />
|
||||
<Compile Include="F4SDHelperService.cs" />
|
||||
<Compile Include="F4SDHelperService.cs" />
|
||||
<Compile Include="F4SDHelperService.UserId.cs" />
|
||||
<Compile Include="F4SDM42WebApiController.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="..\SharedAssemblyInfo.cs">
|
||||
|
||||
298
F4SDM42WebApi/F4SDHelperService.UserId.cs
Normal file
298
F4SDM42WebApi/F4SDHelperService.UserId.cs
Normal file
@@ -0,0 +1,298 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.Logging;
|
||||
|
||||
using Matrix42.Common;
|
||||
|
||||
using update4u.SPS.DataLayer;
|
||||
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace C4IT.F4SD
|
||||
{
|
||||
public partial class F4SDHelperService
|
||||
{
|
||||
internal async Task<List<cF4SDTicketSummary>> getTicketListByUser(
|
||||
Guid userId,
|
||||
int hours,
|
||||
int queueoption,
|
||||
List<cApiM42TicketQueueInfo> queues)
|
||||
{
|
||||
var method = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(method);
|
||||
try
|
||||
{
|
||||
await Task.Delay(0);
|
||||
if (userId == Guid.Empty)
|
||||
return new List<cF4SDTicketSummary>();
|
||||
|
||||
var activityFilter = GetActivityFilter(userId, hours, ticketAndServiceRequestEnabled(), queueoption, queues);
|
||||
LogEntry($"Generating ticket list for userId '{userId}'. ASQL filter: {activityFilter}", LogLevels.Debug);
|
||||
|
||||
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)
|
||||
return new List<cF4SDTicketSummary>();
|
||||
|
||||
var tickets = new List<cF4SDTicketSummary>(activityTable.Rows.Count);
|
||||
foreach (DataRow entry in activityTable.Rows)
|
||||
{
|
||||
var activityId = getGuidFromObject(entry["EOID"]);
|
||||
var ticketNumber = getStringFromObject(entry["TicketNumber"]);
|
||||
var subject = getStringFromObject(entry["Subject"]);
|
||||
if (string.IsNullOrEmpty(ticketNumber) || string.IsNullOrEmpty(subject))
|
||||
continue;
|
||||
|
||||
var state = GetActivityState(activityId);
|
||||
tickets.Add(new cF4SDTicketSummary
|
||||
{
|
||||
TicketObjectId = activityId,
|
||||
Name = ticketNumber,
|
||||
ActivityType = getStringFromObject(entry["ActivityType"]),
|
||||
Summary = subject,
|
||||
StatusId = state.Item1,
|
||||
Status = state.Item2,
|
||||
AssetCIName = getStringFromObject(entry["AssetCIName"]),
|
||||
AssetName = getStringFromObject(entry["AssetName"]),
|
||||
ServiceId = getGuidFromObject(entry["ServiceId"]),
|
||||
ServiceName = getStringFromObject(entry["ServiceName"]),
|
||||
UserId = userId,
|
||||
IsPrimaryAccount = true
|
||||
});
|
||||
}
|
||||
|
||||
return tickets.OrderByDescending(ticket => ticket.Name).ToList();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LogException(exception);
|
||||
return new List<cF4SDTicketSummary>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(method);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<TicketOverviewCountsResult> getTicketOverviewCounts(
|
||||
Guid userId,
|
||||
string scope,
|
||||
IEnumerable<string> keys,
|
||||
int queueoption,
|
||||
List<cApiM42TicketQueueInfo> queues)
|
||||
{
|
||||
var method = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(method);
|
||||
try
|
||||
{
|
||||
var useRoleScope = string.Equals(scope, "role", StringComparison.OrdinalIgnoreCase);
|
||||
var normalizedKeys = (keys ?? Array.Empty<string>())
|
||||
.Where(key => !string.IsNullOrWhiteSpace(key))
|
||||
.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)
|
||||
{
|
||||
var source = !useRoleScope && IsUnassignedOverviewKey(key)
|
||||
? unassignedEntries ?? new List<TicketOverviewEntry>()
|
||||
: entries;
|
||||
counts[key] = source.Count(entry => MatchesTicketOverviewKey(entry, key));
|
||||
}
|
||||
|
||||
return new TicketOverviewCountsResult { Counts = counts };
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LogException(exception);
|
||||
return new TicketOverviewCountsResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(method);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<TicketOverviewCountsByRoleResult> getTicketOverviewCountsByRoles(
|
||||
Guid userId,
|
||||
IEnumerable<Guid> roleGuids,
|
||||
IEnumerable<string> keys,
|
||||
int queueoption,
|
||||
List<cApiM42TicketQueueInfo> queues)
|
||||
{
|
||||
var roleIds = await ResolveTicketOverviewRoleIdsAsync(userId, roleGuids);
|
||||
return await getTicketOverviewCountsByRoles(null, roleIds, keys, queueoption, queues);
|
||||
}
|
||||
|
||||
internal async Task<List<TicketOverviewRelationDto>> getTicketOverviewRelations(
|
||||
Guid userId,
|
||||
string scope,
|
||||
string key,
|
||||
int count,
|
||||
int queueoption,
|
||||
List<cApiM42TicketQueueInfo> queues)
|
||||
{
|
||||
var method = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(method);
|
||||
try
|
||||
{
|
||||
if (userId == Guid.Empty || string.IsNullOrWhiteSpace(key))
|
||||
return new List<TicketOverviewRelationDto>();
|
||||
|
||||
var useRoleScope = string.Equals(scope, "role", StringComparison.OrdinalIgnoreCase);
|
||||
var entries = !useRoleScope && IsUnassignedOverviewKey(key)
|
||||
? await LoadTicketOverviewUnassignedEntriesForPersonalScope(userId, queueoption, queues)
|
||||
: await LoadTicketOverviewEntries(userId, useRoleScope, queueoption, queues);
|
||||
|
||||
var filtered = entries
|
||||
.Where(entry => MatchesTicketOverviewKey(entry, key))
|
||||
.OrderByDescending(entry => entry.CreatedDate);
|
||||
if (count > 0)
|
||||
filtered = filtered.Take(count).OrderByDescending(entry => entry.CreatedDate);
|
||||
|
||||
return filtered.Select(entry => new TicketOverviewRelationDto
|
||||
{
|
||||
Type = enumF4sdSearchResultClass.Ticket,
|
||||
Name = entry.TicketNumber ?? string.Empty,
|
||||
DisplayName = 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 ? string.Empty : entry.InitiatorId.ToString(),
|
||||
["UserGuid"] = entry.InitiatorId == Guid.Empty ? string.Empty : entry.InitiatorId.ToString()
|
||||
},
|
||||
Identities = new List<cF4sdIdentityEntry>
|
||||
{
|
||||
new cF4sdIdentityEntry { Class = enumFasdInformationClass.Ticket, Id = entry.TicketId },
|
||||
new cF4sdIdentityEntry { Class = enumFasdInformationClass.User, Id = entry.InitiatorId }
|
||||
}
|
||||
}).ToList();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LogException(exception);
|
||||
return new List<TicketOverviewRelationDto>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(method);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<List<TicketOverviewEntry>> LoadTicketOverviewEntries(
|
||||
Guid userId,
|
||||
bool useRoleScope,
|
||||
int queueoption,
|
||||
List<cApiM42TicketQueueInfo> queues)
|
||||
{
|
||||
if (userId == Guid.Empty)
|
||||
return new List<TicketOverviewEntry>();
|
||||
|
||||
var filter = await BuildTicketOverviewFilterAsync(userId, useRoleScope, queueoption, queues);
|
||||
return await LoadTicketOverviewEntriesByFilter(filter);
|
||||
}
|
||||
|
||||
private async Task<List<TicketOverviewEntry>> LoadTicketOverviewUnassignedEntriesForPersonalScope(
|
||||
Guid userId,
|
||||
int queueoption,
|
||||
List<cApiM42TicketQueueInfo> queues)
|
||||
{
|
||||
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>();
|
||||
|
||||
return await LoadTicketOverviewEntriesByFilter(filter + " AND Recipient IS NULL");
|
||||
}
|
||||
|
||||
private async Task<string> BuildTicketOverviewFilterAsync(
|
||||
Guid userId,
|
||||
bool useRoleScope,
|
||||
int queueoption,
|
||||
List<cApiM42TicketQueueInfo> queues)
|
||||
{
|
||||
var filter = BuildTicketOverviewBaseFilter(queueoption, queues);
|
||||
if (!useRoleScope)
|
||||
return filter + $" AND (Recipient = '{Escape(userId.ToString("D"))}')";
|
||||
|
||||
var roleIds = await ResolveTicketOverviewRoleIdsAsync(userId, null);
|
||||
return BuildTicketOverviewFilterForRoleIds(roleIds, filter);
|
||||
}
|
||||
|
||||
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 || userId == Guid.Empty)
|
||||
return roleIds;
|
||||
|
||||
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 string GetActivityFilter(
|
||||
Guid userId,
|
||||
int hours,
|
||||
bool ticketAndServiceRequestEnabled,
|
||||
int queueoption,
|
||||
List<cApiM42TicketQueueInfo> queues)
|
||||
{
|
||||
var filter = $"Initiator = '{Escape(userId.ToString("D"))}'";
|
||||
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";
|
||||
}
|
||||
|
||||
var startDate = AsqlHelper.PrepareDateTime(DateTime.UtcNow.AddHours(-hours), true);
|
||||
var endDate = AsqlHelper.PrepareDateTime(DateTime.UtcNow, true);
|
||||
filter += " AND (T(SPSCommonClassBase).State <> 204" +
|
||||
$" OR (ClosedDate > {startDate} AND ClosedDate < {endDate}))";
|
||||
|
||||
return AppendQueueFilter(filter, queueoption, queues);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace C4IT.F4SD
|
||||
{
|
||||
public class F4SDHelperService
|
||||
public partial class F4SDHelperService
|
||||
{
|
||||
private static Guid SPSUserClassBaseID = SPSDataEngineSchemaReader.ClassGetIDFromName("SPSUserClassBase");
|
||||
private static Guid SPSAccountClassBaseID = SPSDataEngineSchemaReader.ClassGetIDFromName("SPSAccountClassBase");
|
||||
|
||||
@@ -7,7 +7,7 @@ using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using Matrix42.Common;
|
||||
using Matrix42.Contracts.Common.Security;
|
||||
using Matrix42.Contracts.ServiceManagement.ServiceContracts;
|
||||
@@ -18,14 +18,14 @@ using Matrix42.Services.Description.Contracts;
|
||||
using Matrix42.WebApi.Contracts;
|
||||
using Matrix42.WebApi.Contracts.OData;
|
||||
using update4u.SPS.Utility.GlobalConfiguration;
|
||||
|
||||
|
||||
using C4IT.F4SDM;
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.Logging;
|
||||
|
||||
|
||||
using static C4IT.FASD.Base.cF4SDTicket;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
|
||||
namespace C4IT.F4SD
|
||||
{
|
||||
[RoutePrefix("api/C4ITF4SDWebApi")]
|
||||
@@ -39,12 +39,12 @@ namespace C4IT.F4SD
|
||||
//public readonly IFragmentService _fragmentService;
|
||||
private readonly IDependencyResolver _resolver;
|
||||
private readonly IEnumerationProvider _enumerationProvider;
|
||||
|
||||
|
||||
|
||||
private readonly F4SDHelperService _f4stHelperService;
|
||||
public string BaseUrl => Request?.RequestUri == null ? string.Empty : $"{Request.RequestUri.Scheme}://{Request.RequestUri.Host}";
|
||||
public string EndpointBaseUrl => $"{BaseUrl}/m42Services/api/c4itf4sdwebapi";
|
||||
|
||||
|
||||
public F4SDM42WebApiController(IDependencyResolver resolver, IEnumerationProvider enumerationProvider)
|
||||
{
|
||||
_resolver = resolver ?? throw new ArgumentNullException(nameof(resolver));
|
||||
@@ -53,12 +53,12 @@ namespace C4IT.F4SD
|
||||
//_objectService = objectService;
|
||||
//_fragmentService = fragmentService;
|
||||
//_incidentService = Guard.NullArgument(incidentService, "incidentService");
|
||||
|
||||
|
||||
_globalConfigurationProvider = GlobalConfigurationProvider.Instance;
|
||||
_f4stHelperService = new F4SDHelperService();
|
||||
EnsureInitialized();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static readonly object initLock = new object();
|
||||
private static void EnsureInitialized()
|
||||
{
|
||||
@@ -78,22 +78,22 @@ namespace C4IT.F4SD
|
||||
}
|
||||
}
|
||||
catch { };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private T GetRequiredService<T>() where T : class
|
||||
{
|
||||
var service = _resolver.TryGet<T>();
|
||||
if (service != null)
|
||||
return service;
|
||||
|
||||
|
||||
throw new InvalidOperationException($"Required Matrix42 service is not registered: {typeof(T).FullName}");
|
||||
}
|
||||
|
||||
|
||||
internal IJournalService GetJournalService()
|
||||
{
|
||||
return GetRequiredService<IJournalService>();
|
||||
}
|
||||
|
||||
|
||||
[Route("getDirectLinkCreateTicket"), HttpGet]
|
||||
public async Task<F4SDHelperService.DirectLink> getDirectLinkCreateTicket([FromUri] string sid = "", [FromUri] string assetname = "")
|
||||
{
|
||||
@@ -110,8 +110,9 @@ namespace C4IT.F4SD
|
||||
type = QueryValue(type, nameof(type));
|
||||
return await _f4stHelperService.getDirectLinkF4SD(eoid, type) ?? string.Empty;
|
||||
}
|
||||
|
||||
[Route("getTicketList"), HttpGet]
|
||||
|
||||
[Obsolete("Use getTicketListForUser with a Matrix42 user ID.")]
|
||||
[Route("getTicketList"), HttpGet]
|
||||
public async Task<List<cF4SDTicketSummary>> getTicketList(
|
||||
[FromUri] string sid,
|
||||
[FromUri] int hours,
|
||||
@@ -124,7 +125,7 @@ namespace C4IT.F4SD
|
||||
queueoption = QueryValue(queueoption, nameof(queueoption));
|
||||
queues = QueryValue(queues, nameof(queues));
|
||||
var decodedPairs = ParseQueues(queues);
|
||||
|
||||
|
||||
// Nun weiterreichen an Service
|
||||
return await _f4stHelperService.getTicketListByUser(
|
||||
sid,
|
||||
@@ -132,8 +133,27 @@ namespace C4IT.F4SD
|
||||
queueoption,
|
||||
decodedPairs
|
||||
) ?? new List<cF4SDTicketSummary>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Route("getTicketListForUser"), HttpGet]
|
||||
public async Task<List<cF4SDTicketSummary>> getTicketListForUser(
|
||||
[FromUri] Guid userId,
|
||||
[FromUri] int hours,
|
||||
[FromUri] int queueoption = 0,
|
||||
[FromUri] string queues = "")
|
||||
{
|
||||
userId = QueryValue(userId, nameof(userId));
|
||||
hours = QueryValue(hours, nameof(hours));
|
||||
queueoption = QueryValue(queueoption, nameof(queueoption));
|
||||
queues = QueryValue(queues, nameof(queues));
|
||||
|
||||
return await _f4stHelperService.getTicketListByUser(
|
||||
userId,
|
||||
hours,
|
||||
queueoption,
|
||||
ParseQueues(queues)) ?? new List<cF4SDTicketSummary>();
|
||||
}
|
||||
|
||||
|
||||
[Route("getTicketDetails"), HttpGet]
|
||||
public async Task<cF4SDTicket> getTicketDetails([FromUri] Guid objectId)
|
||||
@@ -142,18 +162,19 @@ namespace C4IT.F4SD
|
||||
var tickets = await _f4stHelperService.getTicketDetails(new List<Guid>() { objectId });
|
||||
if (tickets?.Count > 0)
|
||||
return tickets[0];
|
||||
|
||||
|
||||
return new cF4SDTicket { TicketObjectId = objectId };
|
||||
}
|
||||
|
||||
|
||||
[Route("getTicketHistory"), HttpGet]
|
||||
public async Task<List<cTicketJournalItem>> getTicketHistory([FromUri] Guid objectId)
|
||||
{
|
||||
objectId = QueryValue(objectId, nameof(objectId));
|
||||
return await _f4stHelperService.GetJournalEntries(objectId) ?? new List<cTicketJournalItem>();
|
||||
}
|
||||
|
||||
[Route("getTicketOverviewCounts"), HttpGet]
|
||||
|
||||
[Obsolete("Use getTicketOverviewCountsForUser with a Matrix42 user ID.")]
|
||||
[Route("getTicketOverviewCounts"), HttpGet]
|
||||
public async Task<F4SDHelperService.TicketOverviewCountsResult> getTicketOverviewCounts(
|
||||
[FromUri] string sid,
|
||||
[FromUri] string scope = "personal",
|
||||
@@ -172,13 +193,42 @@ namespace C4IT.F4SD
|
||||
.Select(key => key.Trim())
|
||||
.Where(key => !string.IsNullOrWhiteSpace(key))
|
||||
.ToList();
|
||||
|
||||
|
||||
var decodedQueues = ParseQueues(queues);
|
||||
return await _f4stHelperService.getTicketOverviewCounts(sid, scope, parsedKeys, queueoption, decodedQueues)
|
||||
?? new F4SDHelperService.TicketOverviewCountsResult();
|
||||
}
|
||||
|
||||
[Route("getTicketOverviewCountsByRoles"), HttpPost]
|
||||
}
|
||||
|
||||
[Route("getTicketOverviewCountsForUser"), HttpGet]
|
||||
public async Task<F4SDHelperService.TicketOverviewCountsResult> getTicketOverviewCountsForUser(
|
||||
[FromUri] Guid userId,
|
||||
[FromUri] string scope = "personal",
|
||||
[FromUri] string keys = "",
|
||||
[FromUri] int queueoption = 0,
|
||||
[FromUri] string queues = "")
|
||||
{
|
||||
userId = QueryValue(userId, nameof(userId));
|
||||
scope = QueryValue(scope, nameof(scope));
|
||||
keys = QueryValue(keys, nameof(keys));
|
||||
queueoption = QueryValue(queueoption, nameof(queueoption));
|
||||
queues = QueryValue(queues, nameof(queues));
|
||||
|
||||
var parsedKeys = (keys ?? string.Empty)
|
||||
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(key => key.Trim())
|
||||
.Where(key => !string.IsNullOrWhiteSpace(key))
|
||||
.ToList();
|
||||
|
||||
return await _f4stHelperService.getTicketOverviewCounts(
|
||||
userId,
|
||||
scope,
|
||||
parsedKeys,
|
||||
queueoption,
|
||||
ParseQueues(queues)) ?? new F4SDHelperService.TicketOverviewCountsResult();
|
||||
}
|
||||
|
||||
[Obsolete("Use getTicketOverviewCountsByRolesForUser with a Matrix42 user ID.")]
|
||||
[Route("getTicketOverviewCountsByRoles"), HttpPost]
|
||||
public async Task<F4SDHelperService.TicketOverviewCountsByRoleResult> getTicketOverviewCountsByRoles([FromBody] TicketOverviewCountsByRolesRequest request)
|
||||
{
|
||||
var parsedKeys = (request?.Keys ?? new List<string>())
|
||||
@@ -186,12 +236,12 @@ namespace C4IT.F4SD
|
||||
.Select(key => key.Trim())
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
|
||||
var roleGuids = (request?.RoleGuids ?? new List<Guid>())
|
||||
.Where(roleId => roleId != Guid.Empty)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
|
||||
var decodedQueues = ParseQueues(request?.Queues ?? string.Empty);
|
||||
return await _f4stHelperService.getTicketOverviewCountsByRoles(
|
||||
request?.Sid,
|
||||
@@ -200,9 +250,34 @@ namespace C4IT.F4SD
|
||||
request?.QueueOption ?? 0,
|
||||
decodedQueues
|
||||
) ?? new F4SDHelperService.TicketOverviewCountsByRoleResult();
|
||||
}
|
||||
|
||||
[Route("getTicketOverviewRelations"), HttpGet]
|
||||
}
|
||||
|
||||
[Route("getTicketOverviewCountsByRolesForUser"), HttpPost]
|
||||
public async Task<F4SDHelperService.TicketOverviewCountsByRoleResult> getTicketOverviewCountsByRolesForUser(
|
||||
[FromBody] TicketOverviewCountsByRolesForUserRequest request)
|
||||
{
|
||||
var parsedKeys = (request?.Keys ?? new List<string>())
|
||||
.Where(key => !string.IsNullOrWhiteSpace(key))
|
||||
.Select(key => key.Trim())
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
var roleGuids = (request?.RoleGuids ?? new List<Guid>())
|
||||
.Where(roleId => roleId != Guid.Empty)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
return await _f4stHelperService.getTicketOverviewCountsByRoles(
|
||||
request?.userId ?? Guid.Empty,
|
||||
roleGuids,
|
||||
parsedKeys,
|
||||
request?.QueueOption ?? 0,
|
||||
ParseQueues(request?.Queues ?? string.Empty))
|
||||
?? new F4SDHelperService.TicketOverviewCountsByRoleResult();
|
||||
}
|
||||
|
||||
[Obsolete("Use getTicketOverviewRelationsForUser with a Matrix42 user ID.")]
|
||||
[Route("getTicketOverviewRelations"), HttpGet]
|
||||
public async Task<List<F4SDHelperService.TicketOverviewRelationDto>> getTicketOverviewRelations(
|
||||
[FromUri] string sid,
|
||||
[FromUri] string scope = "personal",
|
||||
@@ -221,7 +296,32 @@ namespace C4IT.F4SD
|
||||
var decodedQueues = ParseQueues(queues);
|
||||
return await _f4stHelperService.getTicketOverviewRelations(sid, scope, key, count, queueoption, decodedQueues)
|
||||
?? new List<F4SDHelperService.TicketOverviewRelationDto>();
|
||||
}
|
||||
}
|
||||
|
||||
[Route("getTicketOverviewRelationsForUser"), HttpGet]
|
||||
public async Task<List<F4SDHelperService.TicketOverviewRelationDto>> getTicketOverviewRelationsForUser(
|
||||
[FromUri] Guid userId,
|
||||
[FromUri] string scope = "personal",
|
||||
[FromUri] string key = "",
|
||||
[FromUri] int count = 0,
|
||||
[FromUri] int queueoption = 0,
|
||||
[FromUri] string queues = "")
|
||||
{
|
||||
userId = QueryValue(userId, nameof(userId));
|
||||
scope = QueryValue(scope, nameof(scope));
|
||||
key = QueryValue(key, nameof(key));
|
||||
count = QueryValue(count, nameof(count));
|
||||
queueoption = QueryValue(queueoption, nameof(queueoption));
|
||||
queues = QueryValue(queues, nameof(queues));
|
||||
|
||||
return await _f4stHelperService.getTicketOverviewRelations(
|
||||
userId,
|
||||
scope,
|
||||
key,
|
||||
count,
|
||||
queueoption,
|
||||
ParseQueues(queues)) ?? new List<F4SDHelperService.TicketOverviewRelationDto>();
|
||||
}
|
||||
/*
|
||||
[Route("updateActivitySolution/{objectId}"), HttpPost]
|
||||
public async Task<HttpResponseMessage> updateActivitySolution(Guid objectId, [FromBody] string SolutionHtml)
|
||||
@@ -242,18 +342,18 @@ namespace C4IT.F4SD
|
||||
group = QueryValue(group, nameof(group));
|
||||
EntityEnumeration enumerationTemp = GetEnumeration(name, mode);
|
||||
var vals = enumerationTemp.Values;
|
||||
|
||||
|
||||
if (group > -1)
|
||||
{
|
||||
vals = vals.Where(row => !row.Extentions.TryGetValue("StateGroup", out var stateGroup) || (ConvertHelper.ParseInt(stateGroup, 0) == group)).ToArray();
|
||||
}
|
||||
|
||||
|
||||
string[] columns = new string[] { "position" };
|
||||
foreach (var item in vals)
|
||||
{
|
||||
item.Extentions = item.Extentions.Where(x => columns.Contains(x.Key.ToLower())).ToDictionary(x => x.Key, x => x.Value);
|
||||
}
|
||||
|
||||
|
||||
EntityEnumeration enumeration = new EntityEnumeration
|
||||
{
|
||||
Name = enumerationTemp.Name,
|
||||
@@ -262,26 +362,26 @@ namespace C4IT.F4SD
|
||||
//CacheOutputAttribute.RegisterResponseEtag($"enum_{enumeration.Name}_{(int)mode}", $"{enumeration.Name}_{(int)mode}", cultureInvariant: false, userInvariant: true, val);
|
||||
return enumeration;
|
||||
}
|
||||
|
||||
|
||||
[Route("getMyRoleMemberships"), HttpGet]
|
||||
public async Task<object> getMyRoleMemberships()
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
if (userId == Guid.Empty)
|
||||
throw new UnauthorizedAccessException("Cannot determine the interactive Matrix42 user.");
|
||||
|
||||
|
||||
var filter = AsqlHelper.BuildInCondition("ID", new Guid[] { userId });
|
||||
return await _f4stHelperService.UserPermissionsInfo(filter) ?? new UserPermissionsInfo();
|
||||
}
|
||||
[HttpGet]
|
||||
[Route("getRoleMemberships")]
|
||||
public async Task<object> getRoleMemberships([FromUri] string sid = "", [FromUri] string upn = "", [FromUri] Guid? id = null)
|
||||
public async Task<object> getRoleMemberships([FromUri] string sid = "", [FromUri] string upn = "", [FromUri] Guid? id = null)
|
||||
{
|
||||
sid = QueryValue(sid, nameof(sid));
|
||||
upn = QueryValue(upn, nameof(upn));
|
||||
id = QueryValue(id, nameof(id));
|
||||
var filter = "";
|
||||
|
||||
|
||||
if (id != null && id.Value != Guid.Empty)
|
||||
{
|
||||
filter = AsqlHelper.BuildInCondition("ID", new Guid[] { id.Value });
|
||||
@@ -294,41 +394,58 @@ namespace C4IT.F4SD
|
||||
{
|
||||
filter = AsqlHelper.BuildInCondition("Accounts.T(SPSAccountClassAD).UserPrincipalName", new string[] { upn });
|
||||
}
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(filter))
|
||||
{
|
||||
return await _f4stHelperService.UserPermissionsInfo(filter) ?? new UserPermissionsInfo();
|
||||
}
|
||||
|
||||
return new UserPermissionsInfo();
|
||||
}
|
||||
|
||||
public class TicketOverviewCountsByRolesRequest
|
||||
|
||||
return new UserPermissionsInfo();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("getRoleMemberships/{userId}")]
|
||||
public async Task<object> getRoleMembershipForUser([FromUri] Guid userId)
|
||||
{
|
||||
return await _f4stHelperService.UserPermissionsInfo(
|
||||
AsqlHelper.BuildInCondition("ID", new[] { userId })) ?? new UserPermissionsInfo();
|
||||
}
|
||||
|
||||
public class TicketOverviewCountsByRolesRequest
|
||||
{
|
||||
public string Sid { get; set; }
|
||||
public List<Guid> RoleGuids { get; set; } = new List<Guid>();
|
||||
public List<string> Keys { get; set; } = new List<string>();
|
||||
public int? QueueOption { get; set; }
|
||||
public string Queues { get; set; }
|
||||
}
|
||||
|
||||
public string Queues { get; set; }
|
||||
}
|
||||
|
||||
public class TicketOverviewCountsByRolesForUserRequest
|
||||
{
|
||||
public Guid userId { get; set; }
|
||||
public List<Guid> RoleGuids { get; set; } = new List<Guid>();
|
||||
public List<string> Keys { get; set; } = new List<string>();
|
||||
public int? QueueOption { get; set; }
|
||||
public string Queues { get; set; }
|
||||
}
|
||||
|
||||
private EntityEnumeration GetEnumeration(string name, EntityEnumerationVisibilityMode mode)
|
||||
{
|
||||
name = name?.Trim();
|
||||
var dataTable = _enumerationProvider.GetEnumeration(name, GetVisibilityFilter(mode));
|
||||
if (dataTable == null)
|
||||
throw new InvalidOperationException($"Enumeration '{name}' was not found.");
|
||||
|
||||
|
||||
var valueColumn = FindColumn(dataTable, "Value") ?? FindNumericColumn(dataTable);
|
||||
if (string.IsNullOrEmpty(valueColumn))
|
||||
throw new InvalidOperationException($"Enumeration '{name}' does not contain a numeric value column.");
|
||||
|
||||
|
||||
var displayColumn = FindColumn(dataTable, "DisplayString")
|
||||
?? FindColumn(dataTable, "DisplayExpression")
|
||||
?? FindColumn(dataTable, "Name")
|
||||
?? valueColumn;
|
||||
var hiddenColumn = FindColumn(dataTable, "Hidden");
|
||||
|
||||
|
||||
var values = dataTable.Rows.Cast<DataRow>()
|
||||
.Select(row => new EntityEnumerationValue
|
||||
{
|
||||
@@ -339,14 +456,14 @@ namespace C4IT.F4SD
|
||||
.ToDictionary(column => column.ColumnName, column => row[column])
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
|
||||
return new EntityEnumeration
|
||||
{
|
||||
Name = name,
|
||||
Values = values
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private static bool? GetVisibilityFilter(EntityEnumerationVisibilityMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
@@ -359,14 +476,14 @@ namespace C4IT.F4SD
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static string FindColumn(DataTable dataTable, string columnName)
|
||||
{
|
||||
return dataTable.Columns.Cast<DataColumn>()
|
||||
.FirstOrDefault(column => string.Equals(column.ColumnName, columnName, StringComparison.OrdinalIgnoreCase))
|
||||
?.ColumnName;
|
||||
}
|
||||
|
||||
|
||||
private static string FindNumericColumn(DataTable dataTable)
|
||||
{
|
||||
var excludedNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||
@@ -375,12 +492,12 @@ namespace C4IT.F4SD
|
||||
"Position",
|
||||
"StateGroup"
|
||||
};
|
||||
|
||||
|
||||
return dataTable.Columns.Cast<DataColumn>()
|
||||
.FirstOrDefault(column => !excludedNames.Contains(column.ColumnName) && IsNumericType(column.DataType))
|
||||
?.ColumnName;
|
||||
}
|
||||
|
||||
|
||||
private static bool IsNumericType(Type type)
|
||||
{
|
||||
return type == typeof(byte)
|
||||
@@ -392,7 +509,7 @@ namespace C4IT.F4SD
|
||||
|| type == typeof(uint)
|
||||
|| type == typeof(ulong);
|
||||
}
|
||||
|
||||
|
||||
private static Guid GetCurrentUserId()
|
||||
{
|
||||
var principal = Thread.CurrentPrincipal as IM42Principal;
|
||||
@@ -400,39 +517,39 @@ namespace C4IT.F4SD
|
||||
?? principal?.M42Identity?.UserFragmentID
|
||||
?? Guid.Empty;
|
||||
}
|
||||
|
||||
|
||||
private string GetQueryValue(string name)
|
||||
{
|
||||
return Request?.GetQueryNameValuePairs()
|
||||
.FirstOrDefault(pair => string.Equals(pair.Key, name, StringComparison.OrdinalIgnoreCase))
|
||||
.Value;
|
||||
}
|
||||
|
||||
|
||||
private string QueryValue(string value, string name)
|
||||
{
|
||||
return GetQueryValue(name) ?? value ?? string.Empty;
|
||||
}
|
||||
|
||||
|
||||
private int QueryValue(int value, string name)
|
||||
{
|
||||
return int.TryParse(GetQueryValue(name), out var parsed) ? parsed : value;
|
||||
}
|
||||
|
||||
|
||||
private Guid QueryValue(Guid value, string name)
|
||||
{
|
||||
return Guid.TryParse(GetQueryValue(name), out var parsed) ? parsed : value;
|
||||
}
|
||||
|
||||
|
||||
private Guid? QueryValue(Guid? value, string name)
|
||||
{
|
||||
return Guid.TryParse(GetQueryValue(name), out var parsed) ? parsed : value;
|
||||
}
|
||||
|
||||
|
||||
private TEnum QueryValue<TEnum>(TEnum value, string name) where TEnum : struct
|
||||
{
|
||||
return Enum.TryParse<TEnum>(GetQueryValue(name), true, out var parsed) ? parsed : value;
|
||||
}
|
||||
|
||||
|
||||
private static List<cApiM42TicketQueueInfo> ParseQueues(string queues)
|
||||
{
|
||||
return (queues ?? string.Empty)
|
||||
@@ -442,10 +559,10 @@ namespace C4IT.F4SD
|
||||
var segments = part.Split(':');
|
||||
if (segments.Length != 2)
|
||||
return null;
|
||||
|
||||
|
||||
var name = WebUtility.UrlDecode(segments[0]);
|
||||
var idStr = WebUtility.UrlDecode(segments[1]);
|
||||
|
||||
|
||||
return Guid.TryParse(idStr, out var guid)
|
||||
? new cApiM42TicketQueueInfo { QueueName = name, QueueID = guid }
|
||||
: null;
|
||||
@@ -453,7 +570,7 @@ namespace C4IT.F4SD
|
||||
.Where(q => q != null)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
||||
[Route("isAlive"), HttpGet]
|
||||
public IHttpActionResult isAlive()
|
||||
{
|
||||
@@ -462,10 +579,10 @@ namespace C4IT.F4SD
|
||||
RequestMessage = Request
|
||||
};
|
||||
response.Headers.ConnectionClose = true;
|
||||
|
||||
|
||||
return ResponseMessage(response);
|
||||
}
|
||||
|
||||
|
||||
[Route("loglevel"), HttpGet]
|
||||
public async Task<string> setDebugMode([FromUri] string debug = "0")
|
||||
{
|
||||
@@ -488,7 +605,7 @@ namespace C4IT.F4SD
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Route("log"), HttpGet]
|
||||
public IHttpActionResult getLog([FromUri] string download = "0", [FromUri] int count = 50, [FromUri] string filter = "")
|
||||
{
|
||||
@@ -500,7 +617,7 @@ namespace C4IT.F4SD
|
||||
var response = _f4stHelperService.privGetLog(download, count, Request, filter);
|
||||
if (response == null)
|
||||
return new StatusCodeResult(HttpStatusCode.NoContent);
|
||||
|
||||
|
||||
return new ResponseMessageResult(response);
|
||||
}
|
||||
catch (Exception E)
|
||||
@@ -514,9 +631,9 @@ namespace C4IT.F4SD
|
||||
public partial class F4SDM42LogsWebApiController : ApiController
|
||||
{
|
||||
private readonly F4SDHelperService _f4stHelperService;
|
||||
|
||||
|
||||
public static bool IsInitialized { get; private set; } = false;
|
||||
|
||||
|
||||
private static readonly object initLock = new object();
|
||||
private static void EnsureInitialized()
|
||||
{
|
||||
@@ -537,15 +654,15 @@ namespace C4IT.F4SD
|
||||
}
|
||||
catch { };
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public F4SDM42LogsWebApiController()
|
||||
{
|
||||
_f4stHelperService = new F4SDHelperService();
|
||||
EnsureInitialized();
|
||||
}
|
||||
|
||||
|
||||
[Route(""), HttpGet]
|
||||
public IEnumerable<cM42LogEntry> getLog2(ODataQueryOptions<cM42LogEntry> queryOptions)
|
||||
{
|
||||
@@ -559,26 +676,26 @@ namespace C4IT.F4SD
|
||||
return Enumerable.Empty<cM42LogEntry>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Route("$count")]
|
||||
[HttpGet]
|
||||
public int Log2Count(ODataQueryOptions<cM42LogEntry> queryOptions)
|
||||
{
|
||||
return ApplyLogFilter(_f4stHelperService.privGetLog2(), queryOptions).Count();
|
||||
}
|
||||
|
||||
|
||||
[Route("{id}")]
|
||||
[OperationType(OperationType.GetObject)]
|
||||
public cM42LogEntry GetClass(int id)
|
||||
{
|
||||
return _f4stHelperService.privGetLog2(id) ?? new cM42LogEntry { LineNumber = id };
|
||||
}
|
||||
|
||||
|
||||
private static IEnumerable<cM42LogEntry> ApplyLogFilter(IEnumerable<cM42LogEntry> entries, ODataQueryOptions<cM42LogEntry> queryOptions)
|
||||
{
|
||||
var result = entries ?? Enumerable.Empty<cM42LogEntry>();
|
||||
var filter = queryOptions?.Filter;
|
||||
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter))
|
||||
{
|
||||
result = result.Where(entry =>
|
||||
@@ -586,16 +703,16 @@ namespace C4IT.F4SD
|
||||
(entry.logLvl?.IndexOf(filter, StringComparison.OrdinalIgnoreCase) ?? -1) >= 0 ||
|
||||
(entry.Theme?.IndexOf(filter, StringComparison.OrdinalIgnoreCase) ?? -1) >= 0);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class cGetPropertyBody
|
||||
{
|
||||
public string TableName { get; set; }
|
||||
public List<string> Columns { get; set; } = new List<string>();
|
||||
public cGetPropertyBody() { }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user