859 lines
34 KiB
C#
859 lines
34 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Net.Http;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
using Matrix42.Common;
|
|
using Matrix42.Contracts.Common.Security;
|
|
using Matrix42.Contracts.ServiceManagement.ServiceContracts;
|
|
using Matrix42.Hosting.Contracts;
|
|
using Matrix42.Pandora.Contracts;
|
|
using Matrix42.Persistence.Contracts;
|
|
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")]
|
|
public partial class F4SDM42WebApiController : ApiController
|
|
{
|
|
public static bool IsInitialized { get; private set; } = false;
|
|
public static F4SDM42WebApiController defaultInstance;
|
|
//private readonly IIncidentService _incidentService;
|
|
internal readonly GlobalConfigurationProvider _globalConfigurationProvider;
|
|
//public readonly IObjectService _objectService;
|
|
//public readonly IFragmentService _fragmentService;
|
|
private readonly IDependencyResolver _resolver;
|
|
private readonly IEnumerationProvider _enumerationProvider;
|
|
|
|
|
|
private readonly F4SDHelperService _f4stHelperService;
|
|
private const string TeamsNotificationServiceTypeName = "Matrix42.Contracts.Platform.MsTeams.ITeamsNotificationService";
|
|
private const string StorageServiceTypeName = "Matrix42.StorageService.Contracts.IStorageService";
|
|
private const int JournalStart = 0;
|
|
private const int JournalCount = 50;
|
|
private const int JournalTimeOffset = 120;
|
|
private const string JournalObjectLinkTemplate = "<a href=\"#\" class=\"mx-object-journal--link {0} {1}\">{2}</a>";
|
|
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));
|
|
_enumerationProvider = enumerationProvider ?? throw new ArgumentNullException(nameof(enumerationProvider));
|
|
defaultInstance = this;
|
|
//_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()
|
|
{
|
|
try
|
|
{
|
|
//System.Diagnostics.Debugger.Launch();
|
|
lock (initLock)
|
|
{
|
|
if (IsInitialized || F4SDM42LogsWebApiController.IsInitialized)
|
|
return;
|
|
var Ass = Assembly.GetExecutingAssembly();
|
|
var LM = cLogManagerFile.CreateInstance(LocalMachine: true, A: Ass);
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
cLogManager.DefaultLogger.LogAssemblyInfo(Ass);
|
|
IsInitialized = true;
|
|
LogMethodEnd(CM);
|
|
}
|
|
}
|
|
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>();
|
|
}
|
|
|
|
internal object GetJournalServiceInstance()
|
|
{
|
|
try
|
|
{
|
|
return GetRequiredService<IJournalService>();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogEntry($"IJournalService could not be resolved by the Matrix42 container. Falling back to direct JournalService construction. {ex.GetType().FullName}: {ex.Message}", LogLevels.Warning);
|
|
return CreateJournalServiceInstance();
|
|
}
|
|
}
|
|
|
|
private object CreateJournalServiceInstance()
|
|
{
|
|
var journalServiceType = FindLoadedType("Matrix42.ServiceManager.BizLogic.Services.JournalService")
|
|
?? Type.GetType("Matrix42.ServiceManager.BizLogic.Services.JournalService, Matrix42.ServiceManager.BizLogic", true);
|
|
var constructor = journalServiceType
|
|
.GetConstructors()
|
|
.OrderByDescending(item => item.GetParameters().Length)
|
|
.FirstOrDefault();
|
|
|
|
if (constructor == null)
|
|
throw new InvalidOperationException($"No public constructor was found for {journalServiceType.FullName}.");
|
|
|
|
var parameters = constructor.GetParameters();
|
|
var arguments = new object[parameters.Length];
|
|
for (int i = 0; i < parameters.Length; i++)
|
|
arguments[i] = ResolveJournalServiceConstructorParameter(parameters[i]);
|
|
|
|
return constructor.Invoke(arguments);
|
|
}
|
|
|
|
private object ResolveJournalServiceConstructorParameter(System.Reflection.ParameterInfo parameter)
|
|
{
|
|
if (parameter.ParameterType == typeof(IDependencyResolver))
|
|
return CreateJournalDependencyResolver(_resolver);
|
|
|
|
if (parameter.ParameterType.FullName == TeamsNotificationServiceTypeName || parameter.ParameterType.FullName == StorageServiceTypeName)
|
|
return CreateNoOpInterfaceProxy(parameter.ParameterType);
|
|
|
|
var service = _resolver.TryGet(parameter.ParameterType);
|
|
if (service != null)
|
|
return service;
|
|
|
|
throw new InvalidOperationException($"Required JournalService constructor dependency is not registered: {parameter.ParameterType.FullName} ({parameter.Name}).");
|
|
}
|
|
|
|
private static IDependencyResolver CreateJournalDependencyResolver(IDependencyResolver resolver)
|
|
{
|
|
var proxy = DispatchProxy.Create<IDependencyResolver, JournalDependencyResolverProxy>();
|
|
((JournalDependencyResolverProxy)(object)proxy).Inner = resolver;
|
|
return proxy;
|
|
}
|
|
|
|
private static Type FindLoadedType(string fullName)
|
|
{
|
|
return AppDomain.CurrentDomain
|
|
.GetAssemblies()
|
|
.Select(assembly => assembly.GetType(fullName, false))
|
|
.FirstOrDefault(type => type != null);
|
|
}
|
|
|
|
private static object CreateNoOpInterfaceProxy(Type interfaceType)
|
|
{
|
|
var createMethod = typeof(DispatchProxy)
|
|
.GetMethods(BindingFlags.Public | BindingFlags.Static)
|
|
.Single(method => method.Name == nameof(DispatchProxy.Create) && method.IsGenericMethodDefinition);
|
|
|
|
return createMethod
|
|
.MakeGenericMethod(interfaceType, typeof(NoOpInterfaceProxy))
|
|
.Invoke(null, null);
|
|
}
|
|
|
|
public class JournalDependencyResolverProxy : DispatchProxy
|
|
{
|
|
public IDependencyResolver Inner { get; set; }
|
|
|
|
protected override object Invoke(MethodInfo targetMethod, object[] args)
|
|
{
|
|
var requestedType = GetRequestedServiceType(targetMethod, args);
|
|
if (requestedType?.FullName == StorageServiceTypeName)
|
|
return CreateResolverResultForStorageService(targetMethod, requestedType);
|
|
|
|
try
|
|
{
|
|
return targetMethod.Invoke(Inner, args);
|
|
}
|
|
catch (TargetInvocationException ex) when (ex.InnerException != null)
|
|
{
|
|
throw ex.InnerException;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static Type GetRequestedServiceType(MethodInfo targetMethod, object[] args)
|
|
{
|
|
if (targetMethod.IsGenericMethod && targetMethod.GetGenericArguments().Length > 0)
|
|
return targetMethod.GetGenericArguments()[0];
|
|
|
|
if (args?.Length > 0 && args[0] is Type type)
|
|
return type;
|
|
|
|
return null;
|
|
}
|
|
|
|
private static object CreateResolverResultForStorageService(MethodInfo targetMethod, Type requestedType)
|
|
{
|
|
if (targetMethod.Name.StartsWith("IsRegistered", StringComparison.Ordinal))
|
|
return true;
|
|
|
|
if (targetMethod.Name.Contains("All"))
|
|
return CreateEmptyEnumerable(targetMethod.ReturnType, requestedType);
|
|
|
|
return CreateNoOpInterfaceProxy(requestedType);
|
|
}
|
|
|
|
private static object CreateEmptyEnumerable(Type returnType, Type itemType)
|
|
{
|
|
if (returnType.IsGenericType)
|
|
return Array.CreateInstance(returnType.GetGenericArguments()[0], 0);
|
|
|
|
return Array.CreateInstance(itemType ?? typeof(object), 0);
|
|
}
|
|
|
|
public class NoOpInterfaceProxy : DispatchProxy
|
|
{
|
|
public NoOpInterfaceProxy()
|
|
{
|
|
}
|
|
|
|
protected override object Invoke(MethodInfo targetMethod, object[] args)
|
|
{
|
|
return GetDefaultValue(targetMethod?.ReturnType);
|
|
}
|
|
}
|
|
|
|
private static object GetDefaultValue(Type returnType)
|
|
{
|
|
if (returnType == null || returnType == typeof(void))
|
|
return null;
|
|
|
|
if (returnType == typeof(Task))
|
|
return Task.CompletedTask;
|
|
|
|
if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
|
|
{
|
|
var resultType = returnType.GetGenericArguments()[0];
|
|
var result = resultType.IsValueType ? Activator.CreateInstance(resultType) : null;
|
|
return typeof(Task)
|
|
.GetMethods(BindingFlags.Public | BindingFlags.Static)
|
|
.Single(method => method.Name == nameof(Task.FromResult) && method.IsGenericMethodDefinition)
|
|
.MakeGenericMethod(resultType)
|
|
.Invoke(null, new[] { result });
|
|
}
|
|
|
|
return returnType.IsValueType ? Activator.CreateInstance(returnType) : null;
|
|
}
|
|
|
|
[Route("getDirectLinkCreateTicket"), HttpGet]
|
|
public async Task<F4SDHelperService.DirectLink> getDirectLinkCreateTicket(string sid = "", string assetname = "")
|
|
{
|
|
await Task.Delay(0);
|
|
return await _f4stHelperService.getDirectLinkCreateTicket(sid, assetname);
|
|
}
|
|
[Route("getDirectLinkF4SD"), HttpGet]
|
|
public async Task<string> getDirectLinkF4SD(Guid EOID, string Type)
|
|
{
|
|
return await _f4stHelperService.getDirectLinkF4SD(EOID, Type);
|
|
}
|
|
|
|
[Route("getTicketList"), HttpGet]
|
|
public async Task<List<cF4SDTicketSummary>> getTicketList(
|
|
string sid,
|
|
int hours,
|
|
int queueoption = 0,
|
|
string queues = ""
|
|
)
|
|
{
|
|
var decodedPairs = ParseQueues(queues);
|
|
|
|
// Nun weiterreichen an Service
|
|
return await _f4stHelperService.getTicketListByUser(
|
|
sid,
|
|
hours,
|
|
queueoption,
|
|
decodedPairs
|
|
);
|
|
}
|
|
|
|
|
|
[Route("getTicketDetails"), HttpGet]
|
|
public async Task<cF4SDTicket> getTicketDetails(Guid objectId)
|
|
{
|
|
var tickets = await _f4stHelperService.getTicketDetails(new List<Guid>() { objectId });
|
|
if (tickets.Count > 0)
|
|
return tickets[0];
|
|
else
|
|
return null;
|
|
}
|
|
|
|
[Route("getTicketHistory"), HttpGet]
|
|
public async Task<List<cTicketJournalItem>> getTicketHistory(Guid objectId)
|
|
{
|
|
try
|
|
{
|
|
var journalPortalEntries = await TryGetJournalPortalEntries(objectId);
|
|
if (journalPortalEntries != null)
|
|
{
|
|
LogEntry($"{journalPortalEntries.Count} Journal entries loaded from Matrix42 JournalPortalController for ObjectID={objectId}", LogLevels.Debug);
|
|
return F4SDHelperService.CreateTicketJournalItems(objectId, journalPortalEntries);
|
|
}
|
|
|
|
return await _f4stHelperService.GetJournalEntries(objectId);
|
|
}
|
|
catch (MissingMethodException ex)
|
|
{
|
|
return CreateMissingMethodDiagnostics("getTicketHistory controller", objectId, ex);
|
|
}
|
|
}
|
|
|
|
private async Task<IReadOnlyList<Matrix42.Contracts.Platform.Data.JournalEntryInfo>> TryGetJournalPortalEntries(Guid objectId)
|
|
{
|
|
if (Request?.RequestUri == null)
|
|
return null;
|
|
|
|
foreach (var requestUri in BuildJournalPortalUris(objectId))
|
|
{
|
|
try
|
|
{
|
|
using (var handler = new HttpClientHandler { UseDefaultCredentials = true, AutomaticDecompression = DecompressionMethods.All })
|
|
using (var client = new HttpClient(handler))
|
|
using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri))
|
|
{
|
|
client.Timeout = TimeSpan.FromSeconds(15);
|
|
CopyIncomingHeaders(request);
|
|
using (var response = await client.SendAsync(request))
|
|
{
|
|
var responseText = await response.Content.ReadAsStringAsync();
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
LogEntry($"Matrix42 JournalPortalController returned {(int)response.StatusCode} {response.ReasonPhrase} for {requestUri}. {responseText}", LogLevels.Warning);
|
|
continue;
|
|
}
|
|
|
|
var entries = DeserializeJournalPortalEntries(responseText);
|
|
if (entries != null)
|
|
return entries;
|
|
|
|
LogEntry($"Matrix42 JournalPortalController response could not be deserialized for {requestUri}. {responseText}", LogLevels.Warning);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogEntry($"Matrix42 JournalPortalController request failed for {requestUri}. {ex.GetType().FullName}: {ex.Message}", LogLevels.Warning);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private IEnumerable<Uri> BuildJournalPortalUris(Guid objectId)
|
|
{
|
|
var query = $"objectId={Uri.EscapeDataString(objectId.ToString())}&start={JournalStart}&count={JournalCount}&objectLinkTemplate={Uri.EscapeDataString(JournalObjectLinkTemplate)}&timeOffset={JournalTimeOffset}";
|
|
yield return new Uri($"{BaseUrl}/m42Services/api/journalPortal?{query}");
|
|
yield return new Uri($"{BaseUrl}/api/journalPortal?{query}");
|
|
}
|
|
|
|
private void CopyIncomingHeaders(HttpRequestMessage request)
|
|
{
|
|
foreach (var header in Request.Headers)
|
|
{
|
|
if (string.Equals(header.Key, "Host", StringComparison.OrdinalIgnoreCase)
|
|
|| string.Equals(header.Key, "Connection", StringComparison.OrdinalIgnoreCase)
|
|
|| string.Equals(header.Key, "Accept-Encoding", StringComparison.OrdinalIgnoreCase))
|
|
continue;
|
|
|
|
request.Headers.TryAddWithoutValidation(header.Key, header.Value);
|
|
}
|
|
}
|
|
|
|
private static Matrix42.Contracts.Platform.Data.JournalEntryInfo[] DeserializeJournalPortalEntries(string responseText)
|
|
{
|
|
try
|
|
{
|
|
return Newtonsoft.Json.JsonConvert.DeserializeObject<Matrix42.Contracts.Platform.Data.JournalEntryInfo[]>(responseText);
|
|
}
|
|
catch
|
|
{
|
|
var token = Newtonsoft.Json.Linq.JToken.Parse(responseText);
|
|
if (token.Type == Newtonsoft.Json.Linq.JTokenType.Array)
|
|
return token.ToObject<Matrix42.Contracts.Platform.Data.JournalEntryInfo[]>();
|
|
|
|
foreach (var propertyName in new[] { "result", "Result", "value", "Value" })
|
|
{
|
|
var resultToken = token[propertyName];
|
|
if (resultToken != null && resultToken.Type != Newtonsoft.Json.Linq.JTokenType.Null)
|
|
return resultToken.ToObject<Matrix42.Contracts.Platform.Data.JournalEntryInfo[]>();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
internal static List<cTicketJournalItem> CreateMissingMethodDiagnostics(string stage, Guid objectId, MissingMethodException ex)
|
|
{
|
|
var details = BuildMissingMethodDiagnostic(stage, objectId, ex);
|
|
LogEntry(details, LogLevels.Warning);
|
|
|
|
return new List<cTicketJournalItem>
|
|
{
|
|
new cTicketJournalItem
|
|
{
|
|
ActivityObjectId = objectId,
|
|
CreatedBy = "C4ITF4SDM42WebApi",
|
|
CreationDate = DateTime.Now,
|
|
Header = "MissingMethodException diagnostic",
|
|
Description = details,
|
|
DescriptionHtml = WebUtility.HtmlEncode(details).Replace(Environment.NewLine, "<br />"),
|
|
IsVisibleForUser = false
|
|
}
|
|
};
|
|
}
|
|
|
|
private static string BuildMissingMethodDiagnostic(string stage, Guid objectId, MissingMethodException ex)
|
|
{
|
|
var builder = new StringBuilder();
|
|
builder.AppendLine($"Stage: {stage}");
|
|
builder.AppendLine($"ObjectId: {objectId}");
|
|
builder.AppendLine(ex.ToString());
|
|
builder.AppendLine("Loaded assemblies:");
|
|
|
|
var assemblyNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
|
{
|
|
"C4ITF4SDM42WebApi",
|
|
"C4ITF4SDM42WebApiHelper",
|
|
"Matrix42.Common",
|
|
"Matrix42.Common.Html",
|
|
"Matrix42.Contracts.Platform",
|
|
"Matrix42.Contracts.ServiceManagement",
|
|
"Matrix42.ServiceManager.BizLogic",
|
|
"Matrix42.BizLogic.Journal",
|
|
"Newtonsoft.Json",
|
|
"System.Net.Http.Formatting",
|
|
"update4u.SPS.DataLayer",
|
|
"update4u.SPS.Security"
|
|
};
|
|
|
|
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()
|
|
.Where(assembly => assemblyNames.Contains(assembly.GetName().Name))
|
|
.OrderBy(assembly => assembly.GetName().Name))
|
|
{
|
|
builder.AppendLine($"{assembly.GetName().Name}, Version={assembly.GetName().Version}, Location={GetAssemblyLocation(assembly)}");
|
|
}
|
|
|
|
return builder.ToString();
|
|
}
|
|
|
|
private static string GetAssemblyLocation(Assembly assembly)
|
|
{
|
|
try
|
|
{
|
|
return assembly.Location;
|
|
}
|
|
catch
|
|
{
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
[Route("getTicketOverviewCounts"), HttpGet]
|
|
public async Task<F4SDHelperService.TicketOverviewCountsResult> getTicketOverviewCounts(
|
|
string sid,
|
|
string scope = "personal",
|
|
string keys = "",
|
|
int queueoption = 0,
|
|
string queues = ""
|
|
)
|
|
{
|
|
var parsedKeys = (keys ?? string.Empty)
|
|
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
|
.Select(key => key.Trim())
|
|
.Where(key => !string.IsNullOrWhiteSpace(key))
|
|
.ToList();
|
|
|
|
var decodedQueues = ParseQueues(queues);
|
|
return await _f4stHelperService.getTicketOverviewCounts(sid, scope, parsedKeys, queueoption, decodedQueues);
|
|
}
|
|
|
|
[Route("getTicketOverviewCountsByRoles"), HttpPost]
|
|
public async Task<F4SDHelperService.TicketOverviewCountsByRoleResult> getTicketOverviewCountsByRoles([FromBody] TicketOverviewCountsByRolesRequest 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();
|
|
|
|
var decodedQueues = ParseQueues(request?.Queues ?? string.Empty);
|
|
return await _f4stHelperService.getTicketOverviewCountsByRoles(
|
|
request?.Sid,
|
|
roleGuids,
|
|
parsedKeys,
|
|
request?.QueueOption ?? 0,
|
|
decodedQueues
|
|
);
|
|
}
|
|
|
|
[Route("getTicketOverviewRelations"), HttpGet]
|
|
public async Task<List<F4SDHelperService.TicketOverviewRelationDto>> getTicketOverviewRelations(
|
|
string sid,
|
|
string scope = "personal",
|
|
string key = "",
|
|
int count = 0,
|
|
int queueoption = 0,
|
|
string queues = ""
|
|
)
|
|
{
|
|
var decodedQueues = ParseQueues(queues);
|
|
return await _f4stHelperService.getTicketOverviewRelations(sid, scope, key, count, queueoption, decodedQueues);
|
|
}
|
|
/*
|
|
[Route("updateActivitySolution/{objectId}"), HttpPost]
|
|
public async Task<HttpResponseMessage> updateActivitySolution(Guid objectId, [FromBody] string SolutionHtml)
|
|
{
|
|
return new HttpResponseMessage
|
|
{
|
|
StatusCode = await _f4stHelperService.updateActivitySolution(objectId, SolutionHtml) ? HttpStatusCode.NoContent : HttpStatusCode.BadRequest,
|
|
};
|
|
}
|
|
*/
|
|
[Route("getPickup/{name}"), HttpGet]
|
|
//[CacheOutput(UseETAG = true)]
|
|
public async Task<HttpResponseMessage> getPickup(string name, EntityEnumerationVisibilityMode mode = EntityEnumerationVisibilityMode.None, Int32 group = -1)
|
|
{
|
|
await Task.Delay(0);
|
|
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,
|
|
Values = vals.ToArray()
|
|
};
|
|
//CacheOutputAttribute.RegisterResponseEtag($"enum_{enumeration.Name}_{(int)mode}", $"{enumeration.Name}_{(int)mode}", cultureInvariant: false, userInvariant: true, val);
|
|
return Request.CreateResponse(HttpStatusCode.OK, 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);
|
|
}
|
|
[HttpGet]
|
|
[Route("getRoleMemberships")]
|
|
public async Task<object> getRoleMemberships(string sid = "", string upn = "", Guid? id = null)
|
|
{
|
|
var filter = "";
|
|
|
|
if (id != null && id.Value != Guid.Empty)
|
|
{
|
|
filter = AsqlHelper.BuildInCondition("ID", new Guid[] { id.Value });
|
|
}
|
|
else if (!string.IsNullOrEmpty(sid))
|
|
{
|
|
filter = AsqlHelper.BuildInCondition("Accounts.T(SPSAccountClassAD).Sid", new string[] { sid });
|
|
}
|
|
else if (!string.IsNullOrEmpty(upn))
|
|
{
|
|
filter = AsqlHelper.BuildInCondition("Accounts.T(SPSAccountClassAD).UserPrincipalName", new string[] { upn });
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(filter))
|
|
{
|
|
return await _f4stHelperService.UserPermissionsInfo(filter);
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
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; }
|
|
}
|
|
|
|
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
|
|
{
|
|
Value = ConvertHelper.ParseInt(row[valueColumn], 0),
|
|
DisplayString = Convert.ToString(row[displayColumn]),
|
|
Hidden = hiddenColumn != null && ConvertHelper.ParseInt(row[hiddenColumn], 0) == 1,
|
|
Extentions = dataTable.Columns.Cast<DataColumn>()
|
|
.ToDictionary(column => column.ColumnName, column => row[column])
|
|
})
|
|
.ToArray();
|
|
|
|
return new EntityEnumeration
|
|
{
|
|
Name = name,
|
|
Values = values
|
|
};
|
|
}
|
|
|
|
private static bool? GetVisibilityFilter(EntityEnumerationVisibilityMode mode)
|
|
{
|
|
switch (mode)
|
|
{
|
|
case EntityEnumerationVisibilityMode.Visible:
|
|
return true;
|
|
case EntityEnumerationVisibilityMode.Hidden:
|
|
return false;
|
|
default:
|
|
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)
|
|
{
|
|
"Hidden",
|
|
"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)
|
|
|| type == typeof(short)
|
|
|| type == typeof(int)
|
|
|| type == typeof(long)
|
|
|| type == typeof(sbyte)
|
|
|| type == typeof(ushort)
|
|
|| type == typeof(uint)
|
|
|| type == typeof(ulong);
|
|
}
|
|
|
|
private static Guid GetCurrentUserId()
|
|
{
|
|
var principal = Thread.CurrentPrincipal as IM42Principal;
|
|
return principal?.InteractivePrincipal?.M42Identity?.UserFragmentID
|
|
?? principal?.M42Identity?.UserFragmentID
|
|
?? Guid.Empty;
|
|
}
|
|
|
|
private static List<cApiM42TicketQueueInfo> ParseQueues(string queues)
|
|
{
|
|
return (queues ?? string.Empty)
|
|
.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)
|
|
.Select(part =>
|
|
{
|
|
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;
|
|
})
|
|
.Where(q => q != null)
|
|
.ToList();
|
|
}
|
|
|
|
[Route("isAlive"), HttpGet]
|
|
public HttpResponseMessage isAlive()
|
|
{
|
|
return new HttpResponseMessage(HttpStatusCode.NoContent);
|
|
}
|
|
|
|
[Route("loglevel"), HttpGet]
|
|
public async Task<string> setDebugMode(string debug = "0")
|
|
{
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
try
|
|
{
|
|
await Task.Delay(0);
|
|
DefaultLogger.Manager.Level = debug == "1" || debug.Equals("true", StringComparison.OrdinalIgnoreCase) ? LogLevels.Debug : LogLevels.Info;
|
|
return DefaultLogger.Manager.Level.ToString();
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return null;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
[Route("log"), HttpGet]
|
|
public HttpResponseMessage getLog(string download = "0", int count = 50, string filter = "")
|
|
{
|
|
try
|
|
{
|
|
return _f4stHelperService.privGetLog(download, count, Request, filter);
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
[RoutePrefix("api/C4ITF4SDWebApi/Logs")]
|
|
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()
|
|
{
|
|
try
|
|
{
|
|
lock (initLock)
|
|
{
|
|
if (IsInitialized || F4SDM42WebApiController.IsInitialized)
|
|
return;
|
|
var Ass = Assembly.GetExecutingAssembly();
|
|
var LM = cLogManagerFile.CreateInstance(LocalMachine: true, A: Ass);
|
|
var CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
cLogManager.DefaultLogger.LogAssemblyInfo(Ass);
|
|
IsInitialized = true;
|
|
LogMethodEnd(CM);
|
|
}
|
|
}
|
|
catch { };
|
|
}
|
|
|
|
|
|
|
|
public F4SDM42LogsWebApiController()
|
|
{
|
|
_f4stHelperService = new F4SDHelperService();
|
|
EnsureInitialized();
|
|
}
|
|
|
|
[Route(""), HttpGet]
|
|
public IEnumerable<cM42LogEntry> getLog2(ODataQueryOptions<cM42LogEntry> queryOptions)
|
|
{
|
|
try
|
|
{
|
|
return ApplyLogFilter(_f4stHelperService.privGetLog2(), queryOptions);
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
[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);
|
|
}
|
|
|
|
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 =>
|
|
(entry.Message?.IndexOf(filter, StringComparison.OrdinalIgnoreCase) ?? -1) >= 0 ||
|
|
(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() { }
|
|
|
|
}
|
|
}
|