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,
+ @"(?:p|div|li|blockquote|pre|h[1-6]|tr)\s*> # 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