using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Net; 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; 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; 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 { 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() where T : class { var service = _resolver.TryGet(); if (service != null) return service; throw new InvalidOperationException($"Required Matrix42 service is not registered: {typeof(T).FullName}"); } internal IJournalService GetJournalService() { return GetRequiredService(); } [Route("getDirectLinkCreateTicket/{sid}/{assetname}"), HttpGet] public async Task getDirectLinkCreateTicket(string sid = "", string assetname = "") { await Task.Delay(0); return await _f4stHelperService.getDirectLinkCreateTicket(sid, assetname) ?? new F4SDHelperService.DirectLink(); } [Route("getDirectLinkF4SD/{eoid}/{type}"), HttpGet] public async Task getDirectLinkF4SD(Guid eoid, string type) { return await _f4stHelperService.getDirectLinkF4SD(eoid, type) ?? string.Empty; } [Route("getTicketList/{sid}/{hours}/{queueoption}/{queues}"), HttpGet] public async Task> 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 ) ?? new List(); } [Route("getTicketDetails"), HttpGet] public async Task getTicketDetails(Guid objectId) { var tickets = await _f4stHelperService.getTicketDetails(new List() { objectId }); if (tickets?.Count > 0) return tickets[0]; return new cF4SDTicket { TicketObjectId = objectId }; } [Route("getTicketHistory"), HttpGet] public async Task> getTicketHistory(Guid objectId) { return await _f4stHelperService.GetJournalEntries(objectId) ?? new List(); } [Route("getTicketOverviewCounts"), HttpGet] public async Task 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) ?? new F4SDHelperService.TicketOverviewCountsResult(); } [Route("getTicketOverviewCountsByRoles"), HttpPost] public async Task getTicketOverviewCountsByRoles([FromBody] TicketOverviewCountsByRolesRequest request) { var parsedKeys = (request?.Keys ?? new List()) .Where(key => !string.IsNullOrWhiteSpace(key)) .Select(key => key.Trim()) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList(); var roleGuids = (request?.RoleGuids ?? new List()) .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 ) ?? new F4SDHelperService.TicketOverviewCountsByRoleResult(); } [Route("getTicketOverviewRelations"), HttpGet] public async Task> 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) ?? new List(); } /* [Route("updateActivitySolution/{objectId}"), HttpPost] public async Task 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 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 enumeration; } [Route("getMyRoleMemberships"), HttpGet] public async Task 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 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) ?? new UserPermissionsInfo(); } return new UserPermissionsInfo(); } public class TicketOverviewCountsByRolesRequest { public string Sid { get; set; } public List RoleGuids { get; set; } = new List(); public List Keys { get; set; } = new List(); 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() .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() .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() .FirstOrDefault(column => string.Equals(column.ColumnName, columnName, StringComparison.OrdinalIgnoreCase)) ?.ColumnName; } private static string FindNumericColumn(DataTable dataTable) { var excludedNames = new HashSet(StringComparer.OrdinalIgnoreCase) { "Hidden", "Position", "StateGroup" }; return dataTable.Columns.Cast() .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 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 IHttpActionResult isAlive() { return new StatusCodeResult(HttpStatusCode.NoContent); } [Route("loglevel"), HttpGet] public async Task 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 string.Empty; } finally { LogMethodEnd(CM); } } [Route("log"), HttpGet] public IHttpActionResult getLog(string download = "0", int count = 50, string filter = "") { try { var response = _f4stHelperService.privGetLog(download, count, Request, filter); if (response == null) return new StatusCodeResult(HttpStatusCode.NoContent); return new ResponseMessageResult(response); } catch (Exception E) { LogException(E); return new StatusCodeResult(HttpStatusCode.InternalServerError); } } } [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 getLog2(ODataQueryOptions queryOptions) { try { return ApplyLogFilter(_f4stHelperService.privGetLog2(), queryOptions); } catch (Exception E) { LogException(E); return Enumerable.Empty(); } } [Route("$count")] [HttpGet] public int Log2Count(ODataQueryOptions 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 ApplyLogFilter(IEnumerable entries, ODataQueryOptions queryOptions) { var result = entries ?? Enumerable.Empty(); 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 Columns { get; set; } = new List(); public cGetPropertyBody() { } } }