diff --git a/C4IT.API.Contracts/C4IT.API.Contracts.csproj b/C4IT.API.Contracts/C4IT.API.Contracts.csproj new file mode 100644 index 0000000..370aacc --- /dev/null +++ b/C4IT.API.Contracts/C4IT.API.Contracts.csproj @@ -0,0 +1,57 @@ + + + + + Debug + AnyCPU + {6CF1365B-C5BC-479C-B7BF-9229DEC98988} + Library + Properties + C4IT.API.Contracts + C4IT.API.Contracts + v4.7.2 + 512 + true + + SAK + SAK + SAK + SAK + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + Properties\CommonAssembyInfo.cs + + + + + + \ No newline at end of file diff --git a/C4IT.API.Contracts/Contracts.cs b/C4IT.API.Contracts/Contracts.cs new file mode 100644 index 0000000..8a0df67 --- /dev/null +++ b/C4IT.API.Contracts/Contracts.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Windows.Media; + +namespace C4IT.API.Contracts +{ + public class Announcement + { + public string _message = String.Empty; + public string _subject = String.Empty; + public int Type = 0; + public DateTime _createdDate; + public DateTime? _visibleFrom; + public Guid _objectID; + public string _prioColor; + public int _priority = 0; + public bool _isAdhoc = false; + + public SolidColorBrush getPrioColorBrush() + { + if (!string.IsNullOrEmpty(_prioColor)) + { + if (_prioColor.StartsWith("0x")) + { + return new SolidColorBrush((Color)ColorConverter.ConvertFromString(_prioColor.Replace("0xFF", "#"))); + } + return new SolidColorBrush((Color)ColorConverter.ConvertFromString(_prioColor)); + } + + return null; + } + } + + public class Ticket + { + public string _ticketNumber; + public string _subject; + public string _state; + public DateTime _createdDate; + public Int32 _lastJournalEntryAction; + public DateTime _lastJournalEntryDate; + public Guid _objectID; + public string _sysEntity; + public Int32 _stateValue; + public bool _newInformation; + public string _lastJournalEntryActionText; + public string _ticketType; + public Ticket() + { + _lastJournalEntryAction = 0; + _stateValue = 0; + } + } + + public enum enumMainFunctions { Announcement = 0, Information, Ssp, Incident, CustomLinks }; + public class CustomerPanelConfig + { + public string _remoteAppPath = String.Empty; + public bool _disableClosing = false; + public int _iconColor = 10; + public int _mainIconTextColor = 10; + public Version _ServerVersion; + public bool _isStartApplicationMinimized; + public string _logoUrl = null; + public string _trayIconUrl = null; + public Dictionary _uiColors = new Dictionary(); + public bool _isDraggable = false; + public Dictionary _linkList = new Dictionary(); + public int _timerIntervalTicket = 10; + public int _timerIntervalAdHocAnnouncements = 2; + public int _timerIntervalRegularAnnouncements = 10; + public string _createNewTicketDirectLink = String.Empty; + public bool _isUUX = true; + public string _encryptedApiToken = String.Empty; + public int _reloginIntervalDays = 14; + public Dictionary MainFunctionActivation = new Dictionary() + { + {enumMainFunctions.Announcement, false }, + {enumMainFunctions.Incident, false }, + {enumMainFunctions.Ssp, false }, + {enumMainFunctions.Information, true }, + {enumMainFunctions.CustomLinks, false } + }; + + public CustomerPanelConfig() + { + _uiColors["activeButtonColor"] = "#186292"; + _uiColors["inactiveButtonColor"] = "#186292"; + _uiColors["backgroundColor"] = "#FFCDC9C9"; + _uiColors["headerColor"] = "#FFCDC9C9"; + } + } + + public enum announcementType + { + Adhoc = 1, + Regular = 2 + } + +} diff --git a/C4IT.API.Contracts/Properties/AssemblyInfo.cs b/C4IT.API.Contracts/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d26e83a --- /dev/null +++ b/C4IT.API.Contracts/Properties/AssemblyInfo.cs @@ -0,0 +1,11 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die einer Assembly zugeordnet sind. +[assembly: AssemblyTitle("C4IT.API.Contracts")] +[assembly: ComVisible(false)] +[assembly: Guid("6cf1365b-c5bc-479c-b7bf-9229dec98988")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/C4IT.API.CustomerPanelTests/C4IT.API.CustomerPanelTests.csproj b/C4IT.API.CustomerPanelTests/C4IT.API.CustomerPanelTests.csproj new file mode 100644 index 0000000..16c654f --- /dev/null +++ b/C4IT.API.CustomerPanelTests/C4IT.API.CustomerPanelTests.csproj @@ -0,0 +1,52 @@ + + + + SAK + SAK + SAK + SAK + + + + net6.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + ..\lib\Matrix42.Contracts.Common.dll + + + ..\lib\Matrix42.Pandora.Contracts.dll + + + ..\..\..\Users\OT202\source\repos\FleetMarketTestWebService\FleetMarketTestWebService\lib\System.Web.Http.dll + + + ..\lib\update4u.SPS.DataLayer.dll + + + + + + + + diff --git a/C4IT.API.CustomerPanelTests/CustomerPanelControllerTest.cs b/C4IT.API.CustomerPanelTests/CustomerPanelControllerTest.cs new file mode 100644 index 0000000..0473fea --- /dev/null +++ b/C4IT.API.CustomerPanelTests/CustomerPanelControllerTest.cs @@ -0,0 +1,41 @@ +using C4IT.API.Contracts; +using Matrix42.Pandora.Contracts; +using Matrix42.Pandora.Contracts.Internationalization; +using Moq; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using update4u.SPS.DataLayer; +using System.Net.Http.Formatting; + +namespace C4IT.API.CustomerPanelTests +{ + public class CustomerPanelControllerTest + { + + [Test] + public void GetVersion_ShouldReturnDefaultVersion_WhenDataIsInvalid() + { + // Arrange + var expectedDefaultVersion = new Version(0, 0, 0, 0); + + // Act + CustomerPanelHelper customerPanelHelper = new CustomerPanelHelper(); + customerPanelHelper.getVersion(); + + // Assert + Assert.That(customerPanelHelper.getVersion(), Is.EqualTo(expectedDefaultVersion)); + } + + // Tests + + // GetVersion_HandlesExceptions + // GetVersion_ReturnsDefaultVersion_WhenDataTableIsNull + // GetVersion_ReturnsDefaultVersion_WhenDataTableIsEmpty + // GetVersion_ReturnsDefaultVersion_WhenDatabaseQueryFails + // GetVersion_ReturnsCorrectVersion_WhenDatabaseQuerySucceeds + } +} diff --git a/C4IT.API.Helper/C4IT.API.Helper.csproj b/C4IT.API.Helper/C4IT.API.Helper.csproj new file mode 100644 index 0000000..0283821 --- /dev/null +++ b/C4IT.API.Helper/C4IT.API.Helper.csproj @@ -0,0 +1,85 @@ + + + + + Debug + AnyCPU + {68000E96-161F-42E4-81C1-552EC2B00BD9} + Library + Properties + C4IT.API.Helper + C4IT.API.Helper + v4.7.2 + 512 + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\lib\log4net.dll + + + ..\..\..\Users\OT202\source\repos\FleetMarketTestWebService\FleetMarketTestWebService\lib\Matrix42.Common.dll + + + + ..\lib\Microsoft.Net.Http.Headers.dll + + + + + ..\lib\QRCoder.dll + + + + + + + + + + ..\..\..\Users\OT202\source\repos\FleetMarketTestWebService\FleetMarketTestWebService\lib\System.Web.Http.dll + + + + + + + + + ..\lib\update4u.SPS.DatabaseFileStorage.dll + + + ..\..\..\Users\OT202\source\repos\FleetMarketTestWebService\FleetMarketTestWebService\lib\update4u.SPS.DataLayer.dll + + + + + + Properties\CommonAssembyInfo.cs + + + + + + + + + + \ No newline at end of file diff --git a/C4IT.API.Helper/HelperController.cs b/C4IT.API.Helper/HelperController.cs new file mode 100644 index 0000000..ff8d34e --- /dev/null +++ b/C4IT.API.Helper/HelperController.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web.Http; +using update4u.SPS.DataLayer; +using update4u.SPS.DatabaseFileStorage; +using update4u.SPS.DataLayer.Schema.Internal; +using QRCoder; +using System.Drawing; +using System.IO; +using System.Net.Http; +using System.Net; + +namespace C4IT.API.Helper +{ + [RoutePrefix("api/c4it/helper")] + public class HelperController : ApiController + { + + + [Route("copyFiles"), HttpGet] + public string copyFiles(Guid sourceEOID, Guid targetEOID) + { + StorageService storageService = new StorageService(); + if (!sourceEOID.Equals(Guid.Empty) && !targetEOID.Equals(Guid.Empty)) + { + + try + { + Guid sourceTypeID = new Guid(FragmentRequestBase.SimpleLoad(SPSDataEngineSchemaReader.ClassGetIDFromName("SPSCommonClassBase"), "typeid", "[expression-objectid]='" + sourceEOID.ToString() + "'").Rows[0]["typeid"].ToString()); + Guid targetTypeID = new Guid(FragmentRequestBase.SimpleLoad(SPSDataEngineSchemaReader.ClassGetIDFromName("SPSCommonClassBase"), "typeid", "[expression-objectid]='" + targetEOID.ToString() + "'").Rows[0]["typeid"].ToString()); + + string targetFolder = StorageService.GetFolderName(targetTypeID, targetEOID); + string sourceFolder = StorageService.GetFolderName(sourceTypeID, sourceEOID); + List dbFiles = storageService.ListFiles(sourceFolder); + + List copyFileGuids = new List(); + foreach (DatabaseFile dbFile in dbFiles) + { + copyFileGuids.Add(dbFile.FileGuid); + + } + storageService.CopyFiles(copyFileGuids, targetFolder); + + + } + catch (Exception e) + { + return e.Message; + } + } + return "ok"; + + } + + + [Route("moveFiles"), HttpGet] + public string moveFiles(Guid sourceEOID, Guid targetEOID) + { + StorageService storageService = new StorageService(); + if (!sourceEOID.Equals(Guid.Empty) && !targetEOID.Equals(Guid.Empty)) { + + try{ + Guid sourceTypeID = new Guid(FragmentRequestBase.SimpleLoad(SPSDataEngineSchemaReader.ClassGetIDFromName("SPSCommonClassBase"), "typeid", "[expression-objectid]='" + sourceEOID.ToString() + "'").Rows[0]["typeid"].ToString()); + Guid targetTypeID = new Guid(FragmentRequestBase.SimpleLoad(SPSDataEngineSchemaReader.ClassGetIDFromName("SPSCommonClassBase"), "typeid", "[expression-objectid]='" + targetEOID.ToString() + "'").Rows[0]["typeid"].ToString()); + + string targetFolder = StorageService.GetFolderName(targetTypeID, targetEOID); + string sourceFolder = StorageService.GetFolderName(sourceTypeID, sourceEOID); + + + storageService.RenameFolder(sourceFolder, targetFolder); + + + } + catch (Exception e) + { + return e.Message; + } + } + return "ok"; + } + + [Route("unreadActivity"), HttpPost] + public string unreadActivity(Guid[] activiesEOID) + { + string log = activiesEOID.Length.ToString(); + if (activiesEOID.Length > 0) + { + try + { + foreach (Guid activityEOID in activiesEOID) + { + + Guid typeId = new Guid(FragmentRequestBase.SimpleLoad(SPSDataEngineSchemaReader.ClassGetIDFromName("SPSCommonClassBase"), "typeid", "[expression-objectid]='" + activityEOID.ToString() + "'").Rows[0]["typeid"].ToString()); + SPSObject activity = ObjectRequest.GetSPSObject(typeId, activityEOID); + log += " / " + activity.GetAttribute("SPSActivityClassBase", "TicketNumber"); + activity.UpdateAttribute("SPSActivityClassBase","NewInformationReceived",DBNull.Value); + activity.Update(); + + } + }catch(Exception e){ + return log + " / " + e.Message; + } + } + return log; + } + + [Route("genQrCode"),HttpGet] + public HttpResponseMessage genQRCode(string qrText) + { + QRCodeGenerator qrGenerator = new QRCodeGenerator(); + QRCodeData qrCodeData = qrGenerator.CreateQrCode(qrText, + QRCodeGenerator.ECCLevel.Q); + QRCode qrCode = new QRCode(qrCodeData); + Bitmap qrCodeImage = qrCode.GetGraphic(20); + var dataStream = new MemoryStream(BitmapToBytes(qrCodeImage)); + var fileName = Path.GetInvalidFileNameChars().Aggregate(qrText.Substring(0, 10), (current, c) => current.Replace(c.ToString(), string.Empty)); + if (String.IsNullOrEmpty(fileName)) + { + fileName = "dummy"; + } + HttpResponseMessage httpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK); + httpResponseMessage.Content = new StreamContent(dataStream); + httpResponseMessage.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment"); + httpResponseMessage.Content.Headers.ContentDisposition.FileName = fileName+".png"; + httpResponseMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/png"); + + return httpResponseMessage; + } + // This method is for converting bitmap into a byte array + private static byte[] BitmapToBytes(Bitmap img) + { + using (MemoryStream stream = new MemoryStream()) + { + img.Save(stream, System.Drawing.Imaging.ImageFormat.Png); + return stream.ToArray(); + } + } + + + [Route("copyObject"), HttpGet] + + public string copyObject(Guid objectToCopy) + { + string log = ""; + try + { + Guid sourceTypeID = new Guid(FragmentRequestBase.SimpleLoad(SPSDataEngineSchemaReader.ClassGetIDFromName("SPSCommonClassBase"), "typeid", "[expression-objectid]='" + objectToCopy.ToString() + "'").Rows[0]["typeid"].ToString()); + SPSObject oldObject = ObjectRequest.GetSPSObject(sourceTypeID, objectToCopy); + SPSObject newObject = (SPSObject)oldObject.CreateCopy(true); + + IAttribute k = newObject.ConfigurationItem.AutoNumberAttribute; + string attrib = k.DbColumnName; + IDataDefinition dd = k.BelongsToSchemaObjectClass; + newObject.UpdateAttribute(dd.Name, attrib, DBNull.Value); + log = attrib + " / " + dd.Name; + + + newObject.Update(); + }catch(Exception e) + { + return e.Message; + } + + return log; + } + + + + [Route("createUninstall"), HttpPost] + public bool createUninstall(Guid[] installBookings) + { + return true; + } + } +} diff --git a/C4IT.API.Helper/Properties/AssemblyInfo.cs b/C4IT.API.Helper/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..6f642ff --- /dev/null +++ b/C4IT.API.Helper/Properties/AssemblyInfo.cs @@ -0,0 +1,11 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die einer Assembly zugeordnet sind. +[assembly: AssemblyTitle("C4IT.API.Helper")] +[assembly: ComVisible(false)] +[assembly: Guid("68000e96-161f-42e4-81c1-552ec2b00bd9")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/C4IT.API.Helper/app.config b/C4IT.API.Helper/app.config new file mode 100644 index 0000000..996f4bc --- /dev/null +++ b/C4IT.API.Helper/app.config @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/C4IT.API.Helper/packages.config b/C4IT.API.Helper/packages.config new file mode 100644 index 0000000..7eae6bf --- /dev/null +++ b/C4IT.API.Helper/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/C4IT.API.sln b/C4IT.API.sln new file mode 100644 index 0000000..8476e7a --- /dev/null +++ b/C4IT.API.sln @@ -0,0 +1,57 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.10.35122.118 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C4IT.API.CustomerPanel", "C4IT.API\C4IT.API.CustomerPanel.csproj", "{C965495D-D326-4521-9B6A-668227ED0651}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C4IT.API.Contracts", "C4IT.API.Contracts\C4IT.API.Contracts.csproj", "{6CF1365B-C5BC-479C-B7BF-9229DEC98988}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Common", "_Common", "{2C8DF0C0-0FB7-4E67-8AC4-7C0D368410CE}" + ProjectSection(SolutionItems) = preProject + CommonAssembyInfo.cs = CommonAssembyInfo.cs + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C4IT.API.CustomerPanelTests", "C4IT.API.CustomerPanelTests\C4IT.API.CustomerPanelTests.csproj", "{ECE98C21-EF8F-442B-BA98-8DB8E848D906}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C965495D-D326-4521-9B6A-668227ED0651}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C965495D-D326-4521-9B6A-668227ED0651}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C965495D-D326-4521-9B6A-668227ED0651}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C965495D-D326-4521-9B6A-668227ED0651}.Release|Any CPU.Build.0 = Release|Any CPU + {6CF1365B-C5BC-479C-B7BF-9229DEC98988}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6CF1365B-C5BC-479C-B7BF-9229DEC98988}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6CF1365B-C5BC-479C-B7BF-9229DEC98988}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6CF1365B-C5BC-479C-B7BF-9229DEC98988}.Release|Any CPU.Build.0 = Release|Any CPU + {ECE98C21-EF8F-442B-BA98-8DB8E848D906}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ECE98C21-EF8F-442B-BA98-8DB8E848D906}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ECE98C21-EF8F-442B-BA98-8DB8E848D906}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ECE98C21-EF8F-442B-BA98-8DB8E848D906}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4E72DDDF-0E9A-4BA8-B27B-3C86DBE20A7F} + EndGlobalSection + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 4 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = https://consulting4it.visualstudio.com/ + SccLocalPath0 = . + SccProjectUniqueName1 = C4IT.API.Contracts\\C4IT.API.Contracts.csproj + SccProjectName1 = C4IT.API.Contracts + SccLocalPath1 = C4IT.API.Contracts + SccProjectUniqueName2 = C4IT.API\\C4IT.API.CustomerPanel.csproj + SccProjectName2 = C4IT.API + SccLocalPath2 = C4IT.API + SccProjectUniqueName3 = C4IT.API.CustomerPanelTests\\C4IT.API.CustomerPanelTests.csproj + SccProjectName3 = C4IT.API.CustomerPanelTests + SccLocalPath3 = C4IT.API.CustomerPanelTests + EndGlobalSection +EndGlobal diff --git a/C4IT.API/ApiCache.cs b/C4IT.API/ApiCache.cs new file mode 100644 index 0000000..385c434 --- /dev/null +++ b/C4IT.API/ApiCache.cs @@ -0,0 +1,60 @@ +using System; +using System.Runtime.Caching; +using System.Linq; +using System.Collections.Generic; + +namespace C4IT.API +{ + class ApiCache + { + public static object GetValue(string key) + { + MemoryCache memoryCache = MemoryCache.Default; + + return memoryCache.Get(key); + } + + public static object AddOrGet(string key, object value, DateTimeOffset absExpiration) + { + MemoryCache memoryCache = MemoryCache.Default; + lock (memoryCache) + { + return memoryCache.AddOrGetExisting(key, value, absExpiration); + } + } + + public static bool Add(string key, object value, DateTimeOffset absExpiration) + { + + MemoryCache memoryCache = MemoryCache.Default; + lock (memoryCache) + { + return memoryCache.Add(key, value, absExpiration); + } + + } + + public static void Delete(string key) + { + MemoryCache memoryCache = MemoryCache.Default; + if (memoryCache.Contains(key)) + { + memoryCache.Remove(key); + } + } + + public static List GetAllKeysInCache() + { + MemoryCache memoryCache = MemoryCache.Default; + List cacheKeys = new List(); + var keys= memoryCache.Where(o => true).Select(o => o.Key); + + foreach (var key in keys) + { + cacheKeys.Add(key); + } + + return cacheKeys; + } + } +} diff --git a/C4IT.API/C4IT.API.CustomerPanel.csproj b/C4IT.API/C4IT.API.CustomerPanel.csproj new file mode 100644 index 0000000..8ecada6 --- /dev/null +++ b/C4IT.API/C4IT.API.CustomerPanel.csproj @@ -0,0 +1,170 @@ + + + + + Debug + AnyCPU + {C965495D-D326-4521-9B6A-668227ED0651} + Library + Properties + C4IT.API.CustomerPanel + C4IT.API.CustomerPanel + v4.7.2 + 512 + true + + SAK + SAK + SAK + SAK + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\SB_DLLs\Matrix42.Common.dll + + + ..\SB_DLLs\Matrix42.Contracts.Common.dll + + + ..\SB_DLLs\Matrix42.DataLayer.Common.dll + + + ..\SB_DLLs\Matrix42.Pandora.Contracts.dll + + + ..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + False + + + ..\packages\Microsoft.Extensions.Caching.Abstractions.8.0.0\lib\net462\Microsoft.Extensions.Caching.Abstractions.dll + False + + + ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.8.0.1\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll + False + + + ..\packages\Microsoft.Extensions.Logging.Abstractions.8.0.1\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll + False + + + ..\packages\Microsoft.Extensions.Options.8.0.2\lib\net462\Microsoft.Extensions.Options.dll + False + + + ..\packages\Microsoft.Extensions.Primitives.8.0.0\lib\net462\Microsoft.Extensions.Primitives.dll + False + + + ..\packages\Microsoft.Owin.4.2.2\lib\net45\Microsoft.Owin.dll + False + + + ..\packages\Microsoft.Owin.Host.SystemWeb.4.2.2\lib\net45\Microsoft.Owin.Host.SystemWeb.dll + False + + + ..\packages\Microsoft.Owin.Security.4.2.2\lib\net45\Microsoft.Owin.Security.dll + False + + + ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + + + + + + + ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll + False + + + + + ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + False + + + + ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + False + + + ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll + False + + + + ..\SB_DLLs\System.Web.Http.dll + + + + + + + + + ..\SB_DLLs\update4u.SPS.Config.dll + + + ..\SB_DLLs\update4u.SPS.DataLayer.dll + + + + + Common\C4IT.Logging.LogManager.cs + + + Common\C4IT.Security.SecurePassword.cs + + + Properties\CommonAssembyInfo.cs + + + + + + + + + + + + + + + + + + + + + + + {6cf1365b-c5bc-479c-b7bf-9229dec98988} + C4IT.API.Contracts + True + + + + + call "$(ProjectDir)PostBuildCopy.bat" "$(Configuration)" + + \ No newline at end of file diff --git a/C4IT.API/ConverterHelper.cs b/C4IT.API/ConverterHelper.cs new file mode 100644 index 0000000..cc26ce5 --- /dev/null +++ b/C4IT.API/ConverterHelper.cs @@ -0,0 +1,70 @@ +using System; +using System.Linq; +using System.Net; +using System.Text.RegularExpressions; + +namespace C4IT.API +{ + public static class ConverterHelper + { + public static string Html2Plaintext(string html) + { + if (string.IsNullOrWhiteSpace(html)) + return string.Empty; + + // 1. HTML‐Entities dekodieren (z.B. ü → ü) + string decoded = WebUtility.HtmlDecode(html); + + // 2.

und
durch Zeilenumbruch ersetzen + string withBreaks = Regex.Replace( + decoded, + @" # schließende Block-Tags + |<(?:br|hr)\b[^>]*> #
,
+ |<(?:ul|ol|table|thead|tbody|tfoot|article # öffnende Block-Container + |section|nav|aside|header|footer + |figure|figcaption|details|summary)[^>]*>", + " ", + RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase); + + // 3. Alle übrigen Tags entfernen + string noTags = Regex.Replace(withBreaks, @"<[^>]+>", string.Empty); + + return noTags.Trim(); + } + + public static bool ObjectToBoolConverter(object source) + { + try + { + if (source.Equals("1")) + { + source = 1; + } + return Convert.ToBoolean(source); + } + catch (Exception) + { + return false; + } + } + + public static int ObjectToIntConverter(object source) + { + try + { + return Convert.ToInt32(source); + } + catch (Exception) + { + return 0; + } + } + + public static string ObjectToStringConverter(this object value) + { + return (value ?? string.Empty).ToString(); + } + + + } +} diff --git a/C4IT.API/CustomerPanelController.cs b/C4IT.API/CustomerPanelController.cs new file mode 100644 index 0000000..55a38bb --- /dev/null +++ b/C4IT.API/CustomerPanelController.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using System.Web.Http; +using C4IT.API.Contracts; +using C4IT.Logging; +using System.Reflection; +using System.Web.Http.Controllers; +using Matrix42.Pandora.Contracts; +using static C4IT.Logging.cLogManager; +using Matrix42.Pandora.Contracts.Internationalization; +using System.Security.Principal; +using update4u.SPS.DataLayer.Query.FunctionExpression; +using System.Net.Http; +using System.Net; + +namespace C4IT.API +{ + [RoutePrefix("api/c4it/customerpanel")] + + public class CustomerPanelController : ApiController + { + private readonly CustomerPanelHelper _CPanelHelper = new CustomerPanelHelper(); + + public static bool IsInitialized { get; private set; } = false; + + public IPandoraUserProfile UserProfile => _userProfile; + + public ICultureConfuguration GlobalSettings => _globalSettings; + + public LanguageInfo[] Languages => _languages ?? (_languages = GlobalSettings.GetLanguages()); + + private static Object initLock = new object(); + internal static CustomerPanelController controller = null; + + private readonly IPandoraUserProfile _userProfile; + private readonly ICultureConfuguration _globalSettings; + private LanguageInfo[] _languages = null; + public CustomerPanelController(IPandoraUserProfile pandoraUserProfile, ICultureConfuguration globalSettings) + { + controller = this; + _userProfile = pandoraUserProfile; + _globalSettings = globalSettings; + } + + protected override void Initialize(HttpControllerContext controllerContext) + { + base.Initialize(controllerContext); + try + { + lock (initLock) + { + if (IsInitialized) + return; + + var Ass = Assembly.GetExecutingAssembly(); + var LM = cLogManagerFile.CreateInstance(LocalMachine: true, A: Ass); + var CM = MethodBase.GetCurrentMethod(); + LogMethodBegin(CM); + cLogManager.DefaultLogger.LogAssemblyInfo(Ass); + + CustomerPanelSecurePassword.Init(); + PrivateCustomerPanelSecurePassword.Init(); + + IsInitialized = true; + LogMethodEnd(CM); + } + } + catch { }; + } + + [Route("version"), HttpGet] + public Version GetVersion() + { + return _CPanelHelper.getVersion(); + } + + [Route("closeallclients"), HttpGet] + public bool GetCloseAllClients() + { + return _CPanelHelper.GetCloseAllClients(); + } + + [Route("config"), HttpGet] + public CustomerPanelConfig GetConfig(bool noCache = false) + { + return _CPanelHelper.GetConfig(noCache); + } + + [Route("tickets/{userid:guid}"), HttpGet] + public List GetTicketsByUserId(Guid userId) + { + return _CPanelHelper.GetTickets(userId); + } + [Route("tickets"), HttpGet] + public List GetTickets() + { + return _CPanelHelper.GetTickets(controller.UserProfile.UserId); + } + + [Route("resetCache"), HttpGet] + public bool ResetCache() + { + return this._CPanelHelper.ResetCache(); + } + + [Route("announcements/{userid:guid}"), HttpGet] + public List GetAnnouncementsByUserId(announcementType type, Guid userId, bool noCache = false) + { + return GetAnnouncementsInternal(type, userId, noCache); + } + + [Route("announcements"), HttpGet] + public List GetAnnouncements(announcementType type, bool noCache = false) + { + return GetAnnouncementsInternal(type, null, noCache); + } + + [Route("isalive"), HttpGet] + public HttpResponseMessage isAlive() + { + return new HttpResponseMessage(HttpStatusCode.NoContent); + } + + private List GetAnnouncementsInternal(announcementType type, Guid? userId, bool noCache) + { + switch (type) + { + case announcementType.Regular: + return userId.HasValue + ? this._CPanelHelper.GetRegularAnnouncements(userId.Value) + : this._CPanelHelper.GetRegularAnnouncements(controller.UserProfile.UserId); + case announcementType.Adhoc: + return this._CPanelHelper.GetAdHocAnnouncements(noCache); + default: + return null; + } + } + + [Route("Encode"), HttpPost] + public string Encode(string str) + { + return this._CPanelHelper.Encode(str); + } + + [Route("ApiCache"), HttpGet] + public Object GetApiCache() + { + return ApiCache.GetAllKeysInCache(); + } + + //[Route("JoinPool"), HttpGet] + //public void JoinHubPool() + //{ + //} + } +} diff --git a/C4IT.API/CustomerPanelHelper.cs b/C4IT.API/CustomerPanelHelper.cs new file mode 100644 index 0000000..6d63372 --- /dev/null +++ b/C4IT.API/CustomerPanelHelper.cs @@ -0,0 +1,1009 @@ +using C4IT.API.Contracts; +using C4IT.API.CustomerPanel; +using C4IT.Logging; +using Matrix42.Pandora.Contracts.Internationalization; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Web; +using System.Web.Caching; +using update4u.SPS.DataLayer; +using update4u.SPS.DataLayer.Command; +using update4u.SPS.DataLayer.DataReader; +using update4u.SPS.DataLayer.Transaction; +using static C4IT.Logging.cLogManager; + +namespace C4IT.API +{ + public class CustomerPanelHelper + { + #region SQLStatements + private const string ticketSQLStatement = @" + --DECLARE @user_id UNIQUEIDENTIFIER = '7edaa9c7-7b33-e511-80f6-0050562f9516', + --@LCID_long INT = 1031, + --@LCID_short INT = 7; + + SELECT + acb.NewInformationReceived, + acb.[Expression-ObjectID] AS eoid, + acb.Subject, + ccb.State AS stateValue, + ISNULL( + (SELECT TOP 1 cpo.DisplayString + FROM [SPSCommonPickupObjectStatus-CI] AS cpo WITH(NOLOCK) + WHERE scpo.ID = cpo.[Owner] AND cpo.LCID IN (@LCID_long, @LCID_short, 127) + ORDER BY CASE cpo.LCID + WHEN @LCID_long THEN 1 + WHEN @LCID_short THEN 2 + WHEN 127 THEN 3 + END ASC), + scpo.DisplayString) AS [state], + acb.CreatedDate, + lj2.CreatedDate as maxJournalDate, + lj2.ActivityAction AS journalAction, + sot.name AS sysentity, + acb.TicketNumber, + ISNULL( + (SELECT TOP 1 bso.DisplayName + FROM [BasicSchemaObjectType-CI] AS bso WITH(NOLOCK) + WHERE bso.Owner = sot.[ID] AND bso.LCID IN (@LCID_long, @LCID_short, 127) + ORDER BY CASE bso.LCID + WHEN @LCID_long THEN 1 + WHEN @LCID_short THEN 2 + WHEN 127 THEN 3 + END ASC), + sot.DisplayName) AS [TicketType] + FROM SPSActivityClassBase acb WITH(NOLOCK) + LEFT JOIN C4IT_CustomerPanelActivityClassAdditionalRelations a WITH(NOLOCK) on a.[Expression-ObjectID] = acb.[Expression-ObjectID] + LEFT JOIN SPSActivityClassUnitOfWork lj2 WITH(NOLOCK) on lj2.ID = a.LastJournalEntry + JOIN SPSCommonClassBase ccb WITH(NOLOCK) + ON ccb.[expression-objectid] = acb.[expression-objectid] + LEFT JOIN SPSCommonPickupObjectStatus scpo WITH(NOLOCK) + ON scpo.Value = ccb.State + LEFT JOIN SchemaObjectType sot WITH(NOLOCK) + ON sot.id = ccb.TypeID + LEFT JOIN [BasicSchemaObjectType-CI] AS bso + ON bso.Owner = sot.[ID] AND bso.LCID IN (@LCID_long, @LCID_short, 127) + LEFT JOIN [SPSCommonPickupObjectStatus-CI] AS cpo + ON scpo.ID = cpo.[Owner] AND cpo.LCID IN (@LCID_long, @LCID_short, 127) + WHERE + (ccb.[State] <> 204 OR GETUTCDATE() < DATEADD(WEEK, 1, acb.ClosedDate)) + AND ( + acb.[UsedInTypeSPSActivityTypeTicket] IS NOT NULL + OR acb.[UsedInTypeSPSActivityTypeServiceRequest] IS NOT NULL + OR acb.[UsedInTypeSPSActivityTypeIncident] IS NOT NULL + ) + AND acb.Initiator = @user_id + ORDER BY lj2.CreatedDate DESC, acb.CreatedDate DESC; + "; + private const string configSQLStatement = @" + SELECT + name, + version, + announcementEnabled, + incidentEnabled, + informationEnabled, + updateInterval, + UpdateIntervallRegularAnnouncements, + UpdateIntervalAdHocAnnouncements, + logoUrl, + startMinimized, + remoteApp, + trayIcon, + sspEnabled, + customLinks, + isDraggable, + activeButtonColor, + inactiveButtonColor, + backgroundColor, + headerColor, + iconColor, + mainIconTextColor, + disableClosing, + encryptedApiToken, + reloginIntervalDays + FROM + [C4IT_CustomerPanel_SetupClassBase] + WITH(NOLOCK)"; + private const string adHocAnnouncementsSQLStatement = @" + -- Get announcements (AdHoc) + DECLARE + @CurrentDate DATETIME = GETUTCDATE(); + + SELECT + sab.[Expression-ObjectID] as eoid, + COALESCE(als.Subject, sab.Subject) AS AnnouncementSubject, + sab.CreatedDate AS AnnouncementCreatedDate, + sab.VisibleFrom AS AnnouncementVisibleFrom, + sab.Visible AS AnnouncementVisibility, + COALESCE(amh.MessageHTML, sab.MessageHTML) AS [Message], + col.Color AS prioColor, + col.Priority as priority + FROM SVMAnnouncementClassBase AS sab WITH(NOLOCK) + LEFT JOIN C4it_CP_AnnouncementClassBase AS cpa WITH(NOLOCK) + ON sab.[Expression-ObjectID] = cpa.[Expression-ObjectID] + LEFT JOIN C4IT_CP_AnnouncementPriortyPickupType AS col WITH(NOLOCK) + ON cpa.[priority] = col.[Value] + OUTER APPLY ( + SELECT TOP 1 als.Subject + FROM [SVMAnnouncementClassBase-CI] AS als WITH(NOLOCK) + WHERE als.Owner = sab.ID + AND als.LCID IN (@LCID_long, @LCID_short, 127) + ORDER BY CASE als.LCID + WHEN @LCID_long THEN 1 + WHEN @LCID_short THEN 2 + WHEN 127 THEN 3 + END ASC + ) als + OUTER APPLY ( + SELECT TOP 1 amh.MessageHTML + FROM [SVMAnnouncementClassBase-CI] AS amh WITH(NOLOCK) + WHERE amh.Owner = sab.ID + AND amh.LCID IN (@LCID_long, @LCID_short, 127) + ORDER BY CASE amh.LCID + WHEN @LCID_long THEN 1 + WHEN @LCID_short THEN 2 + WHEN 127 THEN 3 + END ASC + ) amh + WHERE + (sab.Visible = 1 + OR (sab.Visible = 2 + AND (sab.VisibleFrom IS NULL OR sab.VisibleFrom < @CurrentDate) + AND (sab.VisibleUntil IS NULL OR sab.VisibleUntil > @CurrentDate)) + ) + AND (sab.Restricted IS NULL + OR sab.Restricted = 0 ) + + OPTION(OPTIMIZE FOR (@CurrentDate UNKNOWN, @LCID_long UNKNOWN,@LCID_short UNKNOWN)) + "; + private const string regularAnnouncementsSQLStatement = @" + --DECLARE @CurrentUserId UNIQUEIDENTIFIER = '7edaa9c7-7b33-e511-80f6-0050562f9516', + --@LCID_long INT = 1031, + --@LCID_short INT = 7, + --@RecursiveOU TINYINT = 1; + DECLARE @CurrentDate DATETIME = GETUTCDATE(); + + WITH RoleCTE AS ( + SELECT + ar.Roles + FROM [SchemaRelation-SVMAnnouncementClassBase2SPSSecurityClassRole] AS ar WITH(NOLOCK) + INNER JOIN [SchemaRelation-SPSSecurityClassRole2SPSUserClassBase] AS rr WITH(NOLOCK) + ON ar.RelatedAnnouncements = rr.Members + WHERE + rr.MemberOf = @CurrentUserId + ), + ParentOrgUnits AS ( + SELECT + IIF( @RecursiveOU = 1 , op.ID , uou.ID ) AS OrgUnitID + FROM SPSUserClassBase AS u WITH(NOLOCK) + INNER JOIN SPSCommonClassBase AS uc WITH(NOLOCK) + ON u.[Expression-ObjectID] = uc.[Expression-ObjectID] + INNER JOIN SPSOrgUnitClassBase AS uou WITH(NOLOCK) + ON uc.OU = uou.ID + LEFT JOIN [Schema-PC-SPSOrgUnitType-SPSCommonClassBase-OU] AS pcou WITH(NOLOCK) + ON uou.ID = pcou.Child + LEFT JOIN SPSOrgUnitClassBase AS op WITH(NOLOCK) + ON op.ID = pcou.Parent + WHERE + u.ID = @CurrentUserId + ) + -- Get announcements + SELECT + sab.[Expression-ObjectID] as eoid, + COALESCE(als.Subject, sab.Subject) AS AnnouncementSubject, + sab.CreatedDate AS AnnouncementCreatedDate, + sab.VisibleFrom AS AnnouncementVisibleFrom, + sab.Visible AS AnnouncementVisibility, + COALESCE(amh.MessageHTML, sab.MessageHTML) AS [Message], + col.Color AS prioColor, + col.Priority AS priority + FROM SVMAnnouncementClassBase AS sab WITH(NOLOCK) + LEFT JOIN C4it_CP_AnnouncementClassBase AS cpa WITH(NOLOCK) + ON sab.[Expression-ObjectID] = cpa.[Expression-ObjectID] + LEFT JOIN C4IT_CP_AnnouncementPriortyPickupType AS col WITH(NOLOCK) + ON cpa.[priority] = col.[Value] + LEFT JOIN [SchemaRelation-SVMAnnouncementClassBase2SPSUserClassBase] AS rel WITH(NOLOCK) + ON sab.ID = rel.UserS AND rel.Announcements = @CurrentUserId + LEFT JOIN RoleCTE AS rc ON sab.ID = rc.Roles + LEFT JOIN [SchemaRelation-SVMAnnouncementClassBase2SPSOrgUnitClassBase] AS ao WITH(NOLOCK) + ON ao.OrgUnits = sab.ID + LEFT JOIN SPSOrgUnitClassBase AS ou WITH(NOLOCK) + ON ou.ID = ao.Announcements + OUTER APPLY ( + SELECT TOP 1 als.Subject + FROM [SVMAnnouncementClassBase-CI] AS als WITH(NOLOCK) + WHERE als.Owner = sab.ID + AND als.LCID IN (@LCID_long, @LCID_short, 127) + ORDER BY CASE als.LCID + WHEN @LCID_long THEN 1 + WHEN @LCID_short THEN 2 + WHEN 127 THEN 3 + END ASC + ) als + OUTER APPLY ( + SELECT TOP 1 amh.MessageHTML + FROM [SVMAnnouncementClassBase-CI] AS amh WITH(NOLOCK) + WHERE amh.Owner = sab.ID + AND amh.LCID IN (@LCID_long, @LCID_short, 127) + ORDER BY CASE amh.LCID + WHEN @LCID_long THEN 1 + WHEN @LCID_short THEN 2 + WHEN 127 THEN 3 + END ASC + ) amh + WHERE + (sab.Visible = 1 + OR (sab.Visible = 2 + AND (sab.VisibleFrom IS NULL OR sab.VisibleFrom < @CurrentDate) + AND (sab.VisibleUntil IS NULL OR sab.VisibleUntil > @CurrentDate)) + ) + AND (sab.Restricted = 1 +     AND (rel.Users IS NOT NULL +       OR rc.Roles IS NOT NULL +       OR EXISTS (SELECT 1 FROM ParentOrgUnits AS pou WITH(NOLOCK) WHERE ou.ID = pou.OrgUnitID) +     ) + ) OPTION(OPTIMIZE FOR (@CurrentDate UNKNOWN, @CurrentUserId UNKNOWN, @LCID_long UNKNOWN,@LCID_short UNKNOWN,@RecursiveOU UNKNOWN )) + + "; + + #endregion + + + private readonly Guid CustomerPanelConfigID = new Guid("83F7BBCA-32FD-E811-CC82-000C29A7A20A"); + + public Version getVersion() + { + var CM = MethodBase.GetCurrentMethod(); + LogMethodBegin(CM); + + try + { + var classId = SPSDataEngineSchemaReader.ClassGetIDFromName("C4IT_CustomerPanel_SetupClassBase"); + DataTable dtCustomerPanelConfig = FragmentRequestBase.SimpleLoad(classId, "version", "id='" + CustomerPanelConfigID.ToString("D") + "'"); + + if (dtCustomerPanelConfig == null || dtCustomerPanelConfig.Rows.Count == 0) + { + LogEntry("No configuration found for CustomerPanelConfigID: " + CustomerPanelConfigID, LogLevels.Warning); + return new Version(0, 0, 0, 0); + } + + DataRow drCustomerPanelConfig = dtCustomerPanelConfig.Rows[0]; + string versionString = drCustomerPanelConfig["Version"]?.ToString() ?? "0.0.0.0"; + + if (Version.TryParse(versionString, out Version parsedVersion)) + { + return parsedVersion; + } + + return new Version(0, 0, 0, 0); + } + catch (Exception ex) + { + LogException(ex); + return new Version(0, 0, 0, 0); + } + finally + { + LogMethodEnd(CM); + } + } + + internal CustomerPanelConfig GetConfig(bool noCache) + { + var CM = MethodBase.GetCurrentMethod(); + LogMethodBegin(CM); + + CustomerPanelConfig cPconfig = new CustomerPanelConfig(); + + try + { + // Cache-Handling wie bisher + var _cacheConfig = ApiCache.GetValue("config") as CustomerPanelConfig; + if (noCache && _cacheConfig != null) + { + ApiCache.Delete("config"); + _cacheConfig = null; + } + + if (_cacheConfig != null) + { + return _cacheConfig; + } + + // Transaktion + Reader via neues Framework + using (var sPSTransactionScope = new SPSTransactionScope()) + using (var dataReader = DirectDbCompat.ExecuteReader( + dbCmd => + { + dbCmd.CommandText = configSQLStatement; + dbCmd.CommandType = CommandType.Text; + }, + SPSTransaction.Current, + CommandBehavior.SingleRow)) + { + if (dataReader.Read()) + { + // Spalten-Indizes + int versionColumnIndex = dataReader.GetOrdinal("Version"); + int timerIntervalTicketColumnIndex = dataReader.GetOrdinal("updateInterval"); + int timerIntervalAdHocColumnIndex = dataReader.GetOrdinal("UpdateIntervalAdHocAnnouncements"); + int timerIntervalRegularColumnIndex = dataReader.GetOrdinal("UpdateIntervallRegularAnnouncements"); + int isStartApplicationMinimizedColumnIndex = dataReader.GetOrdinal("startMinimized"); + int iconColorColumnIndex = dataReader.GetOrdinal("iconColor"); + int mainIconTextColorColumnIndex = dataReader.GetOrdinal("mainIconTextColor"); + int logoUrlColumnIndex = dataReader.GetOrdinal("logoUrl"); + int remoteAppColumnIndex = dataReader.GetOrdinal("remoteApp"); + int trayIconColumnIndex = dataReader.GetOrdinal("trayIcon"); + int isDraggableColumnIndex = dataReader.GetOrdinal("isDraggable"); + int disableClosingColumnIndex = dataReader.GetOrdinal("disableClosing"); + int activeButtonColorColumnIndex = dataReader.GetOrdinal("activeButtonColor"); + int inactiveButtonColorColumnIndex = dataReader.GetOrdinal("inactiveButtonColor"); + int backgroundColorColumnIndex = dataReader.GetOrdinal("backgroundColor"); + int headerColorColumnIndex = dataReader.GetOrdinal("headerColor"); + int announcementEnabledColumnIndex = dataReader.GetOrdinal("announcementEnabled"); + int incidentEnabledColumnIndex = dataReader.GetOrdinal("incidentEnabled"); + int sspEnabledColumnIndex = dataReader.GetOrdinal("sspEnabled"); + int informationEnabledColumnIndex = dataReader.GetOrdinal("informationEnabled"); + int customLinksColumnIndex = dataReader.GetOrdinal("customLinks"); + int encryptedApiTokenColumnIndex = dataReader.GetOrdinal("encryptedApiToken"); + int reloginIntervalDaysColumnIndex = dataReader.GetOrdinal("reloginIntervalDays"); + + // Version sicher parsen + string versionString = dataReader.IsDBNull(versionColumnIndex) ? "0.0.0.0" : dataReader.GetString(versionColumnIndex); + Version serverVersion; + if (!Version.TryParse(versionString, out serverVersion)) + { + serverVersion = new Version(0, 0, 0, 0); + } + + // Grundobjekt befüllen + cPconfig = new CustomerPanelConfig + { + _ServerVersion = serverVersion, + _timerIntervalTicket = dataReader.IsDBNull(timerIntervalTicketColumnIndex) ? 10 : dataReader.GetInt32(timerIntervalTicketColumnIndex), + _timerIntervalAdHocAnnouncements = dataReader.IsDBNull(timerIntervalAdHocColumnIndex) ? 2 : dataReader.GetInt32(timerIntervalAdHocColumnIndex), + _timerIntervalRegularAnnouncements = dataReader.IsDBNull(timerIntervalRegularColumnIndex) ? 10 : dataReader.GetInt32(timerIntervalRegularColumnIndex), + _isStartApplicationMinimized = ConverterHelper.ObjectToBoolConverter(dataReader[isStartApplicationMinimizedColumnIndex]?.ToString()), + _iconColor = dataReader.GetInt32(iconColorColumnIndex), + _mainIconTextColor = dataReader.GetInt32(mainIconTextColorColumnIndex), + _logoUrl = dataReader.IsDBNull(logoUrlColumnIndex) ? string.Empty : dataReader.GetString(logoUrlColumnIndex), + _trayIconUrl = dataReader.IsDBNull(trayIconColumnIndex) ? string.Empty : dataReader.GetString(trayIconColumnIndex), + _isDraggable = ConverterHelper.ObjectToBoolConverter(dataReader[isDraggableColumnIndex]?.ToString()), + _disableClosing = ConverterHelper.ObjectToBoolConverter(dataReader[disableClosingColumnIndex]?.ToString()), + _encryptedApiToken = dataReader.IsDBNull(encryptedApiTokenColumnIndex) ? string.Empty : dataReader.GetString(encryptedApiTokenColumnIndex), + _reloginIntervalDays = dataReader.IsDBNull(reloginIntervalDaysColumnIndex) ? 14 : dataReader.GetInt32(reloginIntervalDaysColumnIndex), + _remoteAppPath = dataReader.IsDBNull(remoteAppColumnIndex) ? string.Empty : dataReader.GetString(remoteAppColumnIndex) + }; + + // UI-Farben + cPconfig._uiColors["activeButtonColor"] = dataReader.IsDBNull(activeButtonColorColumnIndex) ? string.Empty : dataReader.GetString(activeButtonColorColumnIndex); + cPconfig._uiColors["inactiveButtonColor"] = dataReader.IsDBNull(inactiveButtonColorColumnIndex) ? string.Empty : dataReader.GetString(inactiveButtonColorColumnIndex); + cPconfig._uiColors["backgroundColor"] = dataReader.IsDBNull(backgroundColorColumnIndex) ? string.Empty : dataReader.GetString(backgroundColorColumnIndex); + cPconfig._uiColors["headerColor"] = dataReader.IsDBNull(headerColorColumnIndex) ? string.Empty : dataReader.GetString(headerColorColumnIndex); + + // Token neu kodieren + var encryptedToken = PrivateCustomerPanelSecurePassword.Instance.Decode(cPconfig._encryptedApiToken); + cPconfig._encryptedApiToken = CustomerPanelSecurePassword.Instance.Encode(encryptedToken); + + // Custom Links + var linkList = dataReader.IsDBNull(customLinksColumnIndex) ? string.Empty : dataReader.GetString(customLinksColumnIndex); + if (!string.IsNullOrWhiteSpace(linkList)) + { + foreach (string s in linkList.Split(';')) + { + var temp = s.Split(','); + if (temp.Length == 2) + { + cPconfig._linkList[temp[1].Trim()] = temp[0].Trim(); + } + } + } + + cPconfig.MainFunctionActivation = new Dictionary + { + [enumMainFunctions.Announcement] = ConverterHelper.ObjectToBoolConverter(dataReader[announcementEnabledColumnIndex]?.ToString()), + [enumMainFunctions.Incident] = ConverterHelper.ObjectToBoolConverter(dataReader[incidentEnabledColumnIndex]?.ToString()), + [enumMainFunctions.Ssp] = ConverterHelper.ObjectToBoolConverter(dataReader[sspEnabledColumnIndex]?.ToString()), + [enumMainFunctions.Information] = ConverterHelper.ObjectToBoolConverter(dataReader[informationEnabledColumnIndex]?.ToString()), + [enumMainFunctions.CustomLinks] = !string.IsNullOrEmpty(dataReader[customLinksColumnIndex]?.ToString()) + }; + + sPSTransactionScope.Complete(); + } + } + string suiteUuxUrl = GetSuiteUuxUrl(); + cPconfig._createNewTicketDirectLink = GetCreateTicketDeeplink(); + // LogoUrl korrigieren + if (!string.IsNullOrEmpty(cPconfig._logoUrl) && !Uri.IsWellFormedUriString(cPconfig._logoUrl, UriKind.Absolute)) + { + if (!cPconfig._logoUrl.StartsWith("m42Services/", StringComparison.InvariantCultureIgnoreCase)) + cPconfig._logoUrl = $"m42Services/{cPconfig._logoUrl}"; + + if (Uri.TryCreate(suiteUuxUrl, UriKind.Absolute, out Uri baseUri)) + { + var logoUri = new Uri(baseUri, cPconfig._logoUrl); + cPconfig._logoUrl = logoUri.ToString(); + } + else + { + LogException(new UriFormatException($"Ungültige SuiteUuxUrl: {suiteUuxUrl}")); + } + } + + // TrayIconUrl korrigieren + if (!string.IsNullOrEmpty(cPconfig._trayIconUrl) && !Uri.IsWellFormedUriString(cPconfig._trayIconUrl, UriKind.Absolute)) + { + if (!cPconfig._trayIconUrl.StartsWith("m42Services/", StringComparison.InvariantCultureIgnoreCase)) + cPconfig._trayIconUrl = $"m42Services/{cPconfig._trayIconUrl}"; + + if (Uri.TryCreate(suiteUuxUrl, UriKind.Absolute, out Uri baseTrayUri)) + { + var trayIconUri = new Uri(baseTrayUri, cPconfig._trayIconUrl); + cPconfig._trayIconUrl = trayIconUri.ToString(); + } + else + { + LogException(new UriFormatException($"Ungültige SuiteUuxUrl: {suiteUuxUrl}")); + } + + + } + + ApiCache.Add("config", cPconfig, DateTime.Now.AddMinutes(5)); + return cPconfig; + } + catch (Exception ex) + { + LogException(ex); + return cPconfig; + } + finally + { + LogMethodEnd(CM); + } + } + internal string GetCreateTicketDeeplink(string suiteUuxUrl = null) + { + var CM = MethodBase.GetCurrentMethod(); + LogMethodBegin(CM); + + string deeplink = string.Empty; + + try + { + // suiteUuxUrl einmalig ermitteln (oder vom Aufrufer übernehmen) + if (string.IsNullOrWhiteSpace(suiteUuxUrl)) + suiteUuxUrl = GetSuiteUuxUrl(); + + // Flag aus SPSGlobalConfigurationClassServiceDesk via SimpleLoad + bool ticketAndServiceRequestEnabled = false; + + var sdClassId = SPSDataEngineSchemaReader.ClassGetIDFromName("SPSGlobalConfigurationClassServiceDesk"); + DataTable sdCfg = FragmentRequestBase.SimpleLoad(sdClassId, "TicketAndServiceRequestEnabled", "1=1"); + + if (sdCfg != null && sdCfg.Rows.Count > 0) + { + string colName = sdCfg.Columns.Contains("TicketAndServiceRequestEnabled") + ? "TicketAndServiceRequestEnabled" + : (sdCfg.Columns.Contains("ticketAndServiceRequestEnabled") ? "ticketAndServiceRequestEnabled" : null); + + if (colName != null) + { + string val = sdCfg.Rows[0][colName]?.ToString(); + ticketAndServiceRequestEnabled = ConverterHelper.ObjectToBoolConverter(val); + } + } + + // DeepLink bauen + if (!string.IsNullOrEmpty(suiteUuxUrl) && Uri.TryCreate(suiteUuxUrl, UriKind.Absolute, out Uri uri)) + { + string host = $"{uri.Scheme}://{uri.Host}"; + string type = ticketAndServiceRequestEnabled ? "SPSActivityTypeTicket" : "SPSActivityTypeIncident"; + const string appName = "SelfServicePortal"; + const ViewType viewType = ViewType.New; + + deeplink = DeepLinkBuilder.CreateDeepLink(host, appName, viewType, type); + } + else + { + LogException(new UriFormatException($"Ungültige SuiteUuxUrl: {suiteUuxUrl}")); + } + } + catch (Exception ex) + { + LogException(ex); + } + finally + { + LogMethodEnd(CM); + } + + return deeplink; + } + + private string GetSuiteUuxUrl() + { + var CM = MethodBase.GetCurrentMethod(); + LogMethodBegin(CM); + + const string cacheKey = "SuiteUuxUrl"; + + if (ApiCache.GetValue(cacheKey) is string cached && !string.IsNullOrEmpty(cached)) + { + LogMethodEnd(CM); + return cached; + } + + string suiteUuxUrl = string.Empty; + + try + { + var classId = SPSDataEngineSchemaReader.ClassGetIDFromName("SPSAlertingConfiguration"); + DataTable result = FragmentRequestBase.SimpleLoad(classId, "suiteUuxUrl", "1=1"); + + if (result != null && result.Rows.Count > 0) + { + string colName = result.Columns.Contains("suiteUuxUrl") + ? "suiteUuxUrl" + : (result.Columns.Contains("SuiteUuxUrl") ? "SuiteUuxUrl" : null); + + if (colName != null) + { + suiteUuxUrl = result.Rows[0][colName]?.ToString(); + if (!string.IsNullOrWhiteSpace(suiteUuxUrl)) + suiteUuxUrl = suiteUuxUrl.Trim().TrimEnd('/'); + else + suiteUuxUrl = string.Empty; + } + } + + ApiCache.Add(cacheKey, suiteUuxUrl, DateTime.Now.AddMinutes(60)); + return suiteUuxUrl; + } + catch (Exception ex) + { + LogException(ex); + return string.Empty; + } + finally + { + LogMethodEnd(CM); + } + } + + + + + + internal bool ResetCache() + { + var CM = MethodBase.GetCurrentMethod(); + LogMethodBegin(CM); + + try + { + ApiCache.Delete("AdHocMessage"); + ApiCache.Delete("config"); + return true; + } + catch (Exception ex) + { + LogException(ex); + return false; + } + finally + { + LogMethodEnd(CM); + } + } + + internal List GetTickets(Guid? userId = null) + { + var CM = MethodBase.GetCurrentMethod(); + LogMethodBegin(CM); + + var tickets = new List(); + + if (userId == null || !userId.HasValue) + { + LogEntry("UserId is null", LogLevels.Error); + return tickets; + } + + try + { + var _globalSettings = CustomerPanelController.controller.GlobalSettings; + + // Client-Sprache aus dem Header bestimmen (fallback: en) + string defaultClientLanguageTwoLetterCode = "en"; + string acceptLanguageHeader = HttpContext.Current?.Request?.Headers["Accept-Language"]; + + if (!string.IsNullOrWhiteSpace(acceptLanguageHeader)) + { + try + { + var cultureInfo = new CultureInfo(acceptLanguageHeader.Split(',')[0]); + defaultClientLanguageTwoLetterCode = cultureInfo.TwoLetterISOLanguageName; + } + catch + { + LogEntry("Identifying the client user culture based on 'Accept-Language' parameter '" + + acceptLanguageHeader + "' failed", LogLevels.Debug); + } + } + + // Sprache aus Settings (fallback: en; falls beides nicht vorhanden, harte Defaults) + var languageInfo = + _globalSettings.GetLanguages().FirstOrDefault(lang => lang.TwoLetterCode == defaultClientLanguageTwoLetterCode) + ?? _globalSettings.GetLanguages().FirstOrDefault(lang => lang.TwoLetterCode == "en"); + + int lcidLong = languageInfo?.LCID ?? 1033; // en-US + int lcidShort = languageInfo?.ParentLCID ?? 9; // EN + + using (var sPSTransactionScope = new SPSTransactionScope()) + using (var dataReader = DirectDbCompat.ExecuteReader( + dbCmd => + { + dbCmd.CommandText = ticketSQLStatement; + dbCmd.CommandType = CommandType.Text; + + var pLong = dbCmd.CreateParameter(); + pLong.ParameterName = "@LCID_long"; + pLong.DbType = DbType.Int32; + pLong.Value = lcidLong; + dbCmd.Parameters.Add(pLong); + + var pShort = dbCmd.CreateParameter(); + pShort.ParameterName = "@LCID_short"; + pShort.DbType = DbType.Int32; + pShort.Value = lcidShort; + dbCmd.Parameters.Add(pShort); + + var pUser = dbCmd.CreateParameter(); + pUser.ParameterName = "@user_id"; + pUser.DbType = DbType.Guid; + pUser.Value = userId.Value; + dbCmd.Parameters.Add(pUser); + }, + SPSTransaction.Current, + CommandBehavior.Default)) + { + // Spalten-Indizes einmalig ermitteln + int subjectColumnIndex = dataReader.GetOrdinal("Subject"); + int expressionObjectIdColumnIndex = dataReader.GetOrdinal("eoid"); + int createdDateColumnIndex = dataReader.GetOrdinal("CreatedDate"); + int stateColumnIndex = dataReader.GetOrdinal("state"); + int newInformationReceivedColumnIdx = dataReader.GetOrdinal("NewInformationReceived"); + int sysEntityColumnIndex = dataReader.GetOrdinal("sysentity"); + int ticketTypeColumnIndex = dataReader.GetOrdinal("TicketType"); + int ticketNumberColumnIndex = dataReader.GetOrdinal("TicketNumber"); + int lastJournalActionColumnIndex = dataReader.GetOrdinal("journalAction"); + int stateValueColumnIndex = dataReader.GetOrdinal("stateValue"); + int lastJournalEntryDateColumnIndex = dataReader.GetOrdinal("maxJournalDate"); + + while (dataReader.Read()) + { + var ticket = new Ticket + { + _subject = dataReader.IsDBNull(subjectColumnIndex) ? string.Empty : dataReader.GetString(subjectColumnIndex), + _objectID = dataReader.GetGuid(expressionObjectIdColumnIndex), + _createdDate = dataReader.GetDateTime(createdDateColumnIndex), + _state = dataReader.IsDBNull(stateColumnIndex) ? string.Empty : dataReader.GetString(stateColumnIndex), + _newInformation = ConverterHelper.ObjectToBoolConverter(dataReader[newInformationReceivedColumnIdx]?.ToString()), + _sysEntity = dataReader.IsDBNull(sysEntityColumnIndex) ? string.Empty : dataReader.GetString(sysEntityColumnIndex), + _ticketType = dataReader.IsDBNull(ticketTypeColumnIndex) ? string.Empty : dataReader.GetString(ticketTypeColumnIndex), + _ticketNumber = dataReader.IsDBNull(ticketNumberColumnIndex) ? string.Empty : dataReader.GetString(ticketNumberColumnIndex), + _lastJournalEntryAction = dataReader.IsDBNull(lastJournalActionColumnIndex) ? -1 : dataReader.GetInt32(lastJournalActionColumnIndex), + _stateValue = dataReader.GetInt32(stateValueColumnIndex), + _lastJournalEntryDate = dataReader.IsDBNull(lastJournalEntryDateColumnIndex) ? DateTime.MinValue : dataReader.GetDateTime(lastJournalEntryDateColumnIndex) + }; + + tickets.Add(ticket); + } + + sPSTransactionScope.Complete(); + } + } + catch (Exception ex) + { + LogException(ex); + } + finally + { + LogMethodEnd(CM); + } + + return tickets; + } + + internal bool GetCloseAllClients() + { + var CM = MethodBase.GetCurrentMethod(); + LogMethodBegin(CM); + + try + { + var classId = SPSDataEngineSchemaReader.ClassGetIDFromName("C4IT_CustomerPanel_SetupClassBase"); + DataTable result = FragmentRequestBase.SimpleLoad(classId, "closeAllClients", $"id='{CustomerPanelConfigID:D}'"); + + if (result == null || result.Rows.Count == 0) + { + return false; + } + + string closeAllClients = result.Rows[0]["closeAllClients"]?.ToString(); + return ConverterHelper.ObjectToBoolConverter(closeAllClients); + } + catch (Exception ex) + { + LogException(ex); + return false; + } + finally + { + LogMethodEnd(CM); + } + } + + internal List GetAdHocAnnouncements(bool noCache) + { + var CM = MethodBase.GetCurrentMethod(); + LogMethodBegin(CM); + + try + { + var _globalSettings = CustomerPanelController.controller.GlobalSettings; + + // Client-Sprache ermitteln (Fallback: en) + string defaultClientLanguageTwoLetterCode = "en"; + string acceptLanguageHeader = HttpContext.Current?.Request?.Headers["Accept-Language"]; + + if (!string.IsNullOrWhiteSpace(acceptLanguageHeader)) + { + try + { + var cultureInfo = new CultureInfo(acceptLanguageHeader.Split(',')[0]); + defaultClientLanguageTwoLetterCode = cultureInfo.TwoLetterISOLanguageName; + } + catch + { + LogEntry("Identifying the client user culture based on 'Accept-Language' parameter '" + + acceptLanguageHeader + "' failed", LogLevels.Debug); + } + } + + // Sprache aus Settings (Fallbacks, falls nicht vorhanden) + var languageInfo = + _globalSettings.GetLanguages().FirstOrDefault(lang => lang.TwoLetterCode == defaultClientLanguageTwoLetterCode) + ?? _globalSettings.GetLanguages().FirstOrDefault(lang => lang.TwoLetterCode == "en"); + + int lcidLong = languageInfo?.LCID ?? 1033; // en-US + int lcidShort = languageInfo?.ParentLCID ?? 9; // EN + string langCode = languageInfo?.TwoLetterCode ?? "en"; + + // Cache-Key pro Sprache + string cacheKey = "AdHocMessages_" + langCode; + var _cachedAnnouncements = ApiCache.GetValue(cacheKey) as List; + + if (noCache && _cachedAnnouncements != null) + { + ApiCache.Delete(cacheKey); + _cachedAnnouncements = null; + } + + if (_cachedAnnouncements == null) + { + // Cache-Dauer aus Konfiguration (Fallback 2 Minuten wie in GetConfig-Defaults) + int timerIntervalAdHoc = 2; + try { timerIntervalAdHoc = GetConfig(noCache)._timerIntervalAdHocAnnouncements; } catch { /* defensiv */ } + + using (var sPSTransactionScope = new SPSTransactionScope()) + using (var dataReader = DirectDbCompat.ExecuteReader( + dbCmd => + { + dbCmd.CommandText = adHocAnnouncementsSQLStatement; + dbCmd.CommandType = CommandType.Text; + + var pLong = dbCmd.CreateParameter(); + pLong.ParameterName = "@LCID_long"; + pLong.DbType = DbType.Int32; + pLong.Value = lcidLong; + dbCmd.Parameters.Add(pLong); + + var pShort = dbCmd.CreateParameter(); + pShort.ParameterName = "@LCID_short"; + pShort.DbType = DbType.Int32; + pShort.Value = lcidShort; + dbCmd.Parameters.Add(pShort); + }, + SPSTransaction.Current, + CommandBehavior.SingleResult)) + { + // Spalten-Indizes einmalig ermitteln + int announcementSubjectColumnIndex = dataReader.GetOrdinal("AnnouncementSubject"); + int eoidColumnIndex = dataReader.GetOrdinal("eoid"); + int announcemntCreatedDateColumnIndex = dataReader.GetOrdinal("AnnouncementCreatedDate"); + int announcementVisibleFromColumnIndex = dataReader.GetOrdinal("AnnouncementVisibleFrom"); + int messageColumnIndex = dataReader.GetOrdinal("Message"); + int prioColorColumnIndex = dataReader.GetOrdinal("prioColor"); + int priorityColumnIndex = dataReader.GetOrdinal("priority"); + + _cachedAnnouncements = new List(); + + while (dataReader.Read()) + { + var announcement = new Announcement + { + _subject = dataReader.IsDBNull(announcementSubjectColumnIndex) ? string.Empty : dataReader.GetString(announcementSubjectColumnIndex), + _objectID = dataReader.GetGuid(eoidColumnIndex), + _createdDate = dataReader.IsDBNull(announcemntCreatedDateColumnIndex) ? DateTime.MinValue : dataReader.GetDateTime(announcemntCreatedDateColumnIndex), + _visibleFrom = dataReader.IsDBNull(announcementVisibleFromColumnIndex) ? (DateTime?)null : dataReader.GetDateTime(announcementVisibleFromColumnIndex), + _message = dataReader.IsDBNull(messageColumnIndex) ? string.Empty : dataReader.GetString(messageColumnIndex), + _prioColor = dataReader.IsDBNull(prioColorColumnIndex) ? string.Empty : dataReader.GetString(prioColorColumnIndex), + _priority = dataReader.IsDBNull(priorityColumnIndex) ? 0 : dataReader.GetInt32(priorityColumnIndex), + _isAdhoc = true + }; + + // Tags entfernen und HTML decodieren + announcement._message = ConverterHelper.Html2Plaintext(announcement._message); + + _cachedAnnouncements.Add(announcement); + } + + // Cache setzen nach erfolgreichem Read + ApiCache.Add(cacheKey, _cachedAnnouncements, DateTime.Now.AddMinutes(timerIntervalAdHoc)); + + sPSTransactionScope.Complete(); + } + } + + return _cachedAnnouncements; + } + catch (Exception ex) + { + LogException(ex); + return null; + } + finally + { + LogMethodEnd(CM); + } + } + + internal List GetRegularAnnouncements(Guid? userId = null) + { + var CM = MethodBase.GetCurrentMethod(); + LogMethodBegin(CM); + + var announcements = new List(); + + if (userId == null || !userId.HasValue) + { + LogEntry("UserId is null", LogLevels.Error); + return announcements; + } + + try + { + var _globalSettings = CustomerPanelController.controller.GlobalSettings; + + // Client-Sprache bestimmen (Fallback: en) + string defaultClientLanguageTwoLetterCode = "en"; + string acceptLanguageHeader = HttpContext.Current?.Request?.Headers["Accept-Language"]; + + if (!string.IsNullOrWhiteSpace(acceptLanguageHeader)) + { + try + { + var cultureInfo = new CultureInfo(acceptLanguageHeader.Split(',')[0]); + defaultClientLanguageTwoLetterCode = cultureInfo.TwoLetterISOLanguageName; + } + catch + { + LogEntry("Identifying the client user culture based on 'Accept-Language' parameter '" + + acceptLanguageHeader + "' failed", LogLevels.Debug); + } + } + + // Sprache aus Settings (Fallbacks, falls keine passende Sprache konfiguriert ist) + var languageInfo = + _globalSettings.GetLanguages().FirstOrDefault(lang => lang.TwoLetterCode == defaultClientLanguageTwoLetterCode) + ?? _globalSettings.GetLanguages().FirstOrDefault(lang => lang.TwoLetterCode == "en"); + + int lcidLong = languageInfo?.LCID ?? 1033; // en-US + int lcidShort = languageInfo?.ParentLCID ?? 9; // EN + int recursiveOU = 0; + + using (var sPSTransactionScope = new SPSTransactionScope()) + using (var dataReader = DirectDbCompat.ExecuteReader( + dbCmd => + { + dbCmd.CommandText = regularAnnouncementsSQLStatement; + dbCmd.CommandType = CommandType.Text; + + // @LCID_long + var pLong = dbCmd.CreateParameter(); + pLong.ParameterName = "@LCID_long"; + pLong.DbType = DbType.Int32; + pLong.Value = lcidLong; + dbCmd.Parameters.Add(pLong); + + // @LCID_short + var pShort = dbCmd.CreateParameter(); + pShort.ParameterName = "@LCID_short"; + pShort.DbType = DbType.Int32; + pShort.Value = lcidShort; + dbCmd.Parameters.Add(pShort); + + // @CurrentUserId + var pUser = dbCmd.CreateParameter(); + pUser.ParameterName = "@CurrentUserId"; + pUser.DbType = DbType.Guid; + pUser.Value = userId.Value; + dbCmd.Parameters.Add(pUser); + + // @RecursiveOU + var pRec = dbCmd.CreateParameter(); + pRec.ParameterName = "@RecursiveOU"; + pRec.DbType = DbType.Int32; + pRec.Value = recursiveOU; + dbCmd.Parameters.Add(pRec); + }, + SPSTransaction.Current, + CommandBehavior.SingleResult)) + { + // Spalten-Indizes nur einmal bestimmen + int announcementSubjectColumnIndex = dataReader.GetOrdinal("AnnouncementSubject"); + int eoidColumnIndex = dataReader.GetOrdinal("eoid"); + int announcemntCreatedDateColumnIndex = dataReader.GetOrdinal("AnnouncementCreatedDate"); + int messageColumnIndex = dataReader.GetOrdinal("Message"); + int prioColorColumnIndex = dataReader.GetOrdinal("prioColor"); + int priorityColumnIndex = dataReader.GetOrdinal("priority"); + int announcementVisibleFromColumnIndex = dataReader.GetOrdinal("AnnouncementVisibleFrom"); + + while (dataReader.Read()) + { + var announcement = new Announcement + { + _subject = dataReader.IsDBNull(announcementSubjectColumnIndex) ? string.Empty : dataReader.GetString(announcementSubjectColumnIndex), + _objectID = dataReader.GetGuid(eoidColumnIndex), + _createdDate = dataReader.IsDBNull(announcemntCreatedDateColumnIndex) ? DateTime.MinValue : dataReader.GetDateTime(announcemntCreatedDateColumnIndex), + _visibleFrom = dataReader.IsDBNull(announcementVisibleFromColumnIndex) ? (DateTime?)null : dataReader.GetDateTime(announcementVisibleFromColumnIndex), + _message = dataReader.IsDBNull(messageColumnIndex) ? string.Empty : dataReader.GetString(messageColumnIndex), + _prioColor = dataReader.IsDBNull(prioColorColumnIndex) ? string.Empty : dataReader.GetString(prioColorColumnIndex), + _priority = dataReader.IsDBNull(priorityColumnIndex) ? 0 : dataReader.GetInt32(priorityColumnIndex) + }; + + // Tags entfernen & HTML decodieren + announcement._message = ConverterHelper.Html2Plaintext(announcement._message); + + announcements.Add(announcement); + } + + sPSTransactionScope.Complete(); + } + } + catch (Exception ex) + { + LogException(ex); + } + finally + { + LogMethodEnd(CM); + } + + return announcements; + } + + internal string Encode(string str) + { + return PrivateCustomerPanelSecurePassword.Instance.Encode(str); + } + } +} \ No newline at end of file diff --git a/C4IT.API/CustomerPanelHub.cs b/C4IT.API/CustomerPanelHub.cs new file mode 100644 index 0000000..c46ffcf --- /dev/null +++ b/C4IT.API/CustomerPanelHub.cs @@ -0,0 +1,57 @@ +using System; +using System.Threading.Tasks; +using System.Collections.Concurrent; + +namespace C4IT.API +{ + /* + public delegate void ClientConnectionEventHandler(string clientId); + public delegate void ClientNameChangedEventHandler(string clientId, string newName); + public delegate void ClientGroupEventHandler(string clientId, string groupName); + + public delegate void MessageReceivedEventHandler(string senderClientId, string message); + class CustomerPanelHub : Hub + { + static ConcurrentDictionary _users = new ConcurrentDictionary(); + + public static event ClientConnectionEventHandler ClientConnected; + public static event ClientConnectionEventHandler ClientDisconnected; + public static event ClientNameChangedEventHandler ClientNameChanged; + + public static event ClientGroupEventHandler ClientJoinedToGroup; + public static event ClientGroupEventHandler ClientLeftGroup; + + public static event MessageReceivedEventHandler MessageReceived; + + public static void ClearState() + { + _users.Clear(); + } + + //Called when a client is connected + public override Task OnConnected() + { + _users.TryAdd(Context.ConnectionId, Context.ConnectionId); + + ClientConnected?.Invoke(Context.ConnectionId); + + return base.OnConnected(); + } + + //Called when a client is disconnected + public override Task OnDisconnected(bool stopCalled) + { + string userName; + _users.TryRemove(Context.ConnectionId, out userName); + + ClientDisconnected?.Invoke(Context.ConnectionId); + + return base.OnDisconnected(stopCalled); + } + } + */ + class CustomerPanelHub + { + + } +} diff --git a/C4IT.API/CustomerPanelSecurePassword.cs b/C4IT.API/CustomerPanelSecurePassword.cs new file mode 100644 index 0000000..3730003 --- /dev/null +++ b/C4IT.API/CustomerPanelSecurePassword.cs @@ -0,0 +1,22 @@ +using C4IT.Security; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace C4IT.API +{ + static public class CustomerPanelSecurePassword + { + public readonly static string FFH = "RL5?IX%E1fE^37cUWDY~u+|NA"; + public readonly static string FFK = "PyTLMoZo0Ece/tbEA+nmiUOcn14cjg1KPG9185EoHD5EVWUWPm2iUDwXX+8Vne4saDsihtj7CeKi0aeOFqKEL05lmrmEkVFrYOQ1yhVaLdNzz+yw2KGZ9cF9nS0g+le5PqKg67vfiueoQWwvUQYkbLjjARPm3eoaUcjqFTZqVZ7vcW4C6eushQZ4NrOAzd5WcVENU55l6ORnstRW+SoT+SV2t4MO3ObXWlOK495Gerf44juHDeVGfPL+MjnfcIyUvEVe0AcC+Uddvn7atlbcjBF2m317wVqsogKoAPDpaGHhWAW6D6j8ezP2DSRvDmYXm7EuRXqbb6XatwO1TC/JWnPBk2sHR3/suiURx0ui34oD5e+/QbqapG++caQhba4jf+ailaBrKCdauMPP+BJ6d1Zulu+6NXTWknpbQo9qgPQfWk6B9WQJfzyzUxQ8uey4TaRqS6TDgdqObSddXnzk5pjBhvwNSWOtfvaoX4m4h2iHCTWDp+O3g94MR/StOjIK/eX/D0bIbVxXQD3jgjqyiFoPYbZM6QrNT+CaXD3eEpiBKRojxe1jd5fUOj2gq64HYAvD1DQhvP/6MgR87BOeUGWwrXm8PIwyc4wMoj8RnEEnkH8+yjx9SvHfv7Gb2tW4JDKXOaCZF7+NOrDe3L9ECJh3XyyE6a6kI7eW+XEbjFh/8ugPgqbP2rGAFlKES5AzaPN3ePl2Dv/9s00gYyuGhnM02iWTkj7wOzOTpTaIrhS4uZdBxqlIxnbw/UCDkajitaqq8zeGXWNTAAEc8G4FELXruw0QbwIIuszOS770gAGsmSbpLeOtDyYNFWnnuYlZfhuCyofrk02mnB2e+nZ6p4O9G+MvZkgimeST23MnhLdLNFEIASlwFxDqD9X0GfKN0zD4S2LrwT0yp8mKfgJPyKxG9f3Dwr7yuWIIodplWcIQa/NYVEn/0lga43+F6fSv73uhAKBKqlaivMnZXRqzrX9YsRxgzMOuVJm9WXs0iWhV/Q183vrUVyQnx4H1cZq7p+RriIwEn6Y/01RgE5TzpLILDGdT56if4BGDVoKa4RcAFq4kamdAj8VnLtNTZSt+QA2IOrISFcoiFpn6Z5ZPpjp3ktP5EcqFi/jPNiLn1aQi4c4xhgsggd+S+bpEr2Q31p6WKDv40w2wXmClNz2Ck8BcYtN7z040WGqGtfu4gDPiYpQedytPwzc65ipxKJQ8/sv4At0kVd5U+u/Gsc2lYcDU5va/t338ioKOj1nfB9YmIUuxjvd5hzCmWjHizf/rjMV7SF7PbCsq3RZtPa2Hy4BcXkV5YaoZACN3wgOHadkiz1T3rAGC8KhoiJ94dlQvkwwtoNDblMrpnKoHedBDgsl1Gg09fAzlyXQ6ofNonzOsMERdSwNDyDuOQCoDK809bhxsyGeGvLsWDS7srI7ODedjevx6Obdvpgb95YXKPBIzSXgZRMKMNwTJNMUA4qWrNPZOiW0tkYRhZujN50oMHX2ZJfRKllknJk5SgiijKxlSPd4Abk62n9eGG42DXC1dAEpNoDkiP6lWbtaxVOVL6Kr+LsgD0G6N0Y21Q8YpEH1MTW+462AHaZkcnsVAEGWH"; + public static cSecurePassword Instance { get; private set; } = null; + + static public void Init() + { + Instance = new cSecurePassword(FFH); + Instance.SetRsaKey(FFK); + } + } +} diff --git a/C4IT.API/DeepLinkBuilder.cs b/C4IT.API/DeepLinkBuilder.cs new file mode 100644 index 0000000..65adb9d --- /dev/null +++ b/C4IT.API/DeepLinkBuilder.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Web; +using Newtonsoft.Json; + +namespace C4IT.API +{ + public enum ViewType + { + New, // open create dialog + Preview, // open preview + Action, // run action/wizard + Edit // open edit dialog + } + + public class DeepLinkBuilder + { + public string Host { get; set; } + public string AppName { get; set; } + + // Parameter fr view-options + public bool? Embedded { get; set; } + public Guid? DialogId { get; set; } + public Guid? ObjectId { get; set; } + public int? Archived { get; set; } + public string Type { get; set; } + public ViewType? ViewType { get; set; } + public Guid? ActionId { get; set; } + public Guid? ViewId { get; set; } + + public object PresetParams { get; set; } + + /// + /// Baut die URL basierend auf den gesetzten Eigenschaften. + /// + /// Die erstellte DeepLink-URL als string. + public string BuildUrl() + { + var viewOptions = new Dictionary(); + + if (Embedded.HasValue) + viewOptions["embedded"] = Embedded.Value; + if (DialogId.HasValue) + viewOptions["dialogId"] = DialogId.Value; + if (ObjectId.HasValue) + viewOptions["objectId"] = ObjectId.Value; + if (Archived.HasValue) + viewOptions["archived"] = Archived.Value; + if (!string.IsNullOrEmpty(Type)) + viewOptions["type"] = Type; + if (ViewType.HasValue) + viewOptions["viewType"] = ViewType.Value.ToString().ToLower(); + if (ActionId.HasValue) + viewOptions["actionId"] = ActionId.Value; + if (ViewId.HasValue) + viewOptions["viewId"] = ViewId.Value; + + string viewOptionsJson = JsonConvert.SerializeObject(viewOptions); + string encodedViewOptions = HttpUtility.UrlEncode(viewOptionsJson); + string url = $"{Host.TrimEnd('/')}/wm/app-{AppName}/?view-options={encodedViewOptions}"; + + if (PresetParams != null) + { + string presetParamsJson = JsonConvert.SerializeObject(PresetParams); + string encodedPresetParams = HttpUtility.UrlEncode(presetParamsJson); + url += $"&presetParams={encodedPresetParams}"; + } + + return url; + } + + /// + /// Statische Methode zur Erstellung eines DeepLinks basierend auf den angegebenen Parametern. + /// + /// Der Hostname der Anwendung. + /// Der Name der Anwendung. + /// Der Typ der Ansicht. + /// Der Type des Objekts. + /// Die erstellte DeepLink-URL als string. + public static string CreateDeepLink(string host, string appName, ViewType viewType, string type) + { + var builder = new DeepLinkBuilder + { + Host = host, + AppName = appName, + ViewType = viewType, + Type = type, + }; + + return builder.BuildUrl(); + } + } +} diff --git a/C4IT.API/PostBuildCopy.bat b/C4IT.API/PostBuildCopy.bat new file mode 100644 index 0000000..232faa6 --- /dev/null +++ b/C4IT.API/PostBuildCopy.bat @@ -0,0 +1,51 @@ +@echo off +SETLOCAL + +REM Überprüfe, ob die Konfiguration als Parameter übergeben wurde +IF "%1"=="" ( + echo ERROR: Keine Konfiguration übergeben. Verwenden Sie z. B. "Debug" oder "Release". + EXIT 1 +) + +REM Setze die Quelldateien und das Zielverzeichnis +SET SourceDir=%~dp0bin\%1 +SET TargetDir=\\srvwsm001.imagoverum.com\c$\Program Files (x86)\Matrix42\Matrix42 Workplace Management\svc\bin + +REM Debugging-Ausgabe +echo Starting Post-Build Copy Script... +echo Source Directory: %SourceDir% +echo Target Directory: %TargetDir% + +REM Prüfe, ob die Quelldateien existieren +IF NOT EXIST "%SourceDir%\C4IT.API.Contracts.dll" ( + echo ERROR: C4IT.API.Contracts.dll nicht gefunden. + EXIT 1 +) + +IF NOT EXIST "%SourceDir%\C4IT.API.CustomerPanel.dll" ( + echo ERROR: C4IT.API.CustomerPanel.dll nicht gefunden. + EXIT 1 +) + +REM Kopiere die Dateien +echo Kopiere C4IT.API.Contracts.dll... +xcopy "%SourceDir%\C4IT.API.Contracts.dll" "%SourceDir%\..\..\..\..\Matrix42\C4IT_CustomerPanel\Matrix42Libs" /Y +IF ERRORLEVEL 1 ( + echo ERROR: Kopiervorgang von C4IT.API.Contracts.dll fehlgeschlagen. + EXIT 1 +) +xcopy "%SourceDir%\C4IT.API.Contracts.dll" "%TargetDir%" /Y +IF ERRORLEVEL 1 ( + echo ERROR: Kopiervorgang von C4IT.API.Contracts.dll fehlgeschlagen. + EXIT 1 +) + +echo Kopiere C4IT.API.CustomerPanel.dll... +xcopy "%SourceDir%\C4IT.API.CustomerPanel.dll" "%TargetDir%" /Y +IF ERRORLEVEL 1 ( + echo ERROR: Kopiervorgang von C4IT.API.CustomerPanel.dll fehlgeschlagen. + EXIT 1 +) + +echo Dateien erfolgreich kopiert. +ENDLOCAL diff --git a/C4IT.API/PrivateCustomerPanelSecurePassword.cs b/C4IT.API/PrivateCustomerPanelSecurePassword.cs new file mode 100644 index 0000000..b38c52a --- /dev/null +++ b/C4IT.API/PrivateCustomerPanelSecurePassword.cs @@ -0,0 +1,22 @@ +using C4IT.Security; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace C4IT.API +{ + static public class PrivateCustomerPanelSecurePassword + { + public readonly static string FFH = "RL5?IX%E1fE^37cUWDY~u+|NA"; + public readonly static string FFK = "PyTLMoZo0Ece/tbEA+nmiUOcn14cjg1KPG9185EoHD5EVWUWPm2iUDwXX+8Vne4saDsihtj7CeKi0aeOFqKEL05lmrmEkVFrYOQ1yhVaLdNzz+yw2KGZ9cF9nS0g+le5PqKg67vfiueoQWwvUQYkbLjjARPm3eoaUcjqFTZqVZ7vcW4C6eushQZ4NrOAzd5WcVENU55l6ORnstRW+SoT+SV2t4MO3ObXWlOK495Gerf44juHDeVGfPL+MjnfcIyUvEVe0AcC+Uddvn7atlbcjBF2m317wVqsogKoAPDpaGHhWAW6D6j8ezP2DSRvDmYXm7EuRXqbb6XatwO1TC/JWnPBk2sHR3/suiURx0ui34oD5e+/QbqapG++caQhba4jf+ailaBrKCdauMPP+BJ6d1Zulu+6NXTWknpbQo9qgPQfWk6B9WQJfzyzUxQ8uey4TaRqS6TDgdqObSddXnzk5pjBhvwNSWOtfvaoX4m4h2iHCTWDp+O3g94MR/StOjIK/eX/D0bIbVxXQD3jgjqyiFoPYbZM6QrNT+CaXD3eEpiBKRojxe1jd5fUOj2gq64HYAvD1DQhvP/6MgR87BOeUGWwrXm8PIwyc4wMoj8RnEEnkH8+yjx9SvHfv7Gb2tW4JDKXOaCZF7+NOrDe3L9ECJh3XyyE6a6kI7eW+XEbjFh/8ugPgqbP2rGAFlKES5AzaPN3ePl2Dv/9s00gYyuGhnM02iWTkj7wOzOTpTaIrhS4uZdBxqlIxnbw/UCDkajitaqq8zeGXWNTAAEc8G4FELXruw0QbwIIuszOS770gAGsmSbpLeOtDyYNFWnnuYlZfhuCyofrk02mnB2e+nZ6p4O9G+MvZkgimeST23MnhLdLNFEIASlwFxDqD9X0GfKN0zD4S2LrwT0yp8mKfgJPyKxG9f3Dwr7yuWIIodplWcIQa/NYVEn/0lga43+F6fSv73uhAKBKqlaivMnZXRqzrX9YsRxgzMOuVJm9WXs0iWhV/Q183vrUVyQnx4H1cZq7p+RriIwEn6Y/01RgE5TzpLILDGdT56if4BGDVoKa4RcAFq4kamdAj8VnLtNTZSt+QA2IOrISFcoiFpn6Z5ZPpjp3ktP5EcqFi/jPNiLn1aQi4c4xhgsggd+S+bpEr2Q31p6WKDv40w2wXmClNz2Ck8BcYtN7z040WGqGtfu4gDPiYpQedytPwzc65ipxKJQ8/sv4At0kVd5U+u/Gsc2lYcDU5va/t338ioKOj1nfB9YmIUuxjvd5hzCmWjHizf/rjMV7SF7PbCsq3RZtPa2Hy4BcXkV5YaoZACN3wgOHadkiz1T3rAGC8KhoiJ94dlQvkwwtoNDblMrpnKoHedBDgsl1Gg09fAzlyXQ6ofNonzOsMERdSwNDyDuOQCoDK809bhxsyGeGvLsWDS7srI7ODedjevx6Obdvpgb95YXKPBIzSXgZRMKMNwTJNMUA4qWrNPZOiW0tkYRhZujN50oMHX2ZJfRKllknJk5SgiijKxlSPd4Abk62n9eGG42DXC1dAEpNoDkiP6lWbtaxVOVL6Kr+LsgD0G6N0Y21Q8YpEH1MTW+462AHaZkcnsVAEGWH"; + public static cSecurePassword Instance { get; private set; } = null; + + static public void Init() + { + Instance = new cSecurePassword(FFH); + Instance.SetRsaKey(FFK, "C4itF4sdCustomerPanelWebApi"); + } + } +} diff --git a/C4IT.API/Properties/AssemblyInfo.cs b/C4IT.API/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2d7b30f --- /dev/null +++ b/C4IT.API/Properties/AssemblyInfo.cs @@ -0,0 +1,8 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("C4IT.API")] +[assembly: ComVisible(false)] +[assembly: Guid("c965495d-d326-4521-9b6a-668227ed0651")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/C4IT.API/SignFiles.cmd b/C4IT.API/SignFiles.cmd new file mode 100644 index 0000000..6e5a1da --- /dev/null +++ b/C4IT.API/SignFiles.cmd @@ -0,0 +1,11 @@ +set ProductName="C4IT Customer Panel API" + +set SignTool=..\..\Common Code\Tools\signtool.exe +set TimeStamp=http://rfc3161timestamp.globalsign.com/advanced + +set Src=.\bin\Release +"%SignTool%" sign /a /tr %TimeStamp% /td SHA256 /fd SHA256 /d %ProductName% "%Src%\C4IT.API.Contracts.dll" "%Src%\C4IT.API.CustomerPanel.dll" "%Src%\C4IT.API.Contracts.dll" + +pause + + diff --git a/C4IT.API/app.config b/C4IT.API/app.config new file mode 100644 index 0000000..31a1d44 --- /dev/null +++ b/C4IT.API/app.config @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/C4IT.API/packages.config b/C4IT.API/packages.config new file mode 100644 index 0000000..42588ec --- /dev/null +++ b/C4IT.API/packages.config @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CommonAssembyInfo.cs b/CommonAssembyInfo.cs new file mode 100644 index 0000000..a7e3614 --- /dev/null +++ b/CommonAssembyInfo.cs @@ -0,0 +1,15 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyProduct("C4IT Customer Panel API")] + +[assembly: AssemblyCompany("Consulting4IT GmbH, Germany")] +[assembly: AssemblyCopyright("Copyright © 2025, Consulting4IT GmbH, Germany")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: AssemblyInformationalVersion("1.2.*.*")] +[assembly: AssemblyVersion("1.2.0.0")] \ No newline at end of file diff --git a/SB_DLLs/Matrix42.Common.dll b/SB_DLLs/Matrix42.Common.dll new file mode 100644 index 0000000..32a28f6 Binary files /dev/null and b/SB_DLLs/Matrix42.Common.dll differ diff --git a/SB_DLLs/Matrix42.Contracts.Common.dll b/SB_DLLs/Matrix42.Contracts.Common.dll new file mode 100644 index 0000000..66a8a49 Binary files /dev/null and b/SB_DLLs/Matrix42.Contracts.Common.dll differ diff --git a/SB_DLLs/Matrix42.DataLayer.Common.dll b/SB_DLLs/Matrix42.DataLayer.Common.dll new file mode 100644 index 0000000..a8c7e7a Binary files /dev/null and b/SB_DLLs/Matrix42.DataLayer.Common.dll differ diff --git a/SB_DLLs/Matrix42.Pandora.Contracts.dll b/SB_DLLs/Matrix42.Pandora.Contracts.dll new file mode 100644 index 0000000..7edab93 Binary files /dev/null and b/SB_DLLs/Matrix42.Pandora.Contracts.dll differ diff --git a/SB_DLLs/System.Web.Http.dll b/SB_DLLs/System.Web.Http.dll new file mode 100644 index 0000000..7e3bd30 Binary files /dev/null and b/SB_DLLs/System.Web.Http.dll differ diff --git a/SB_DLLs/update4u.SPS.Config.dll b/SB_DLLs/update4u.SPS.Config.dll new file mode 100644 index 0000000..71c00f7 Binary files /dev/null and b/SB_DLLs/update4u.SPS.Config.dll differ diff --git a/SB_DLLs/update4u.SPS.DataLayer.dll b/SB_DLLs/update4u.SPS.DataLayer.dll new file mode 100644 index 0000000..6cfc093 Binary files /dev/null and b/SB_DLLs/update4u.SPS.DataLayer.dll differ