From 02805630d01646e2d2ee14d6f5c58ec26c0f3eb7 Mon Sep 17 00:00:00 2001 From: Mohammad Awad <“mohammadawad2024@gmail.com”> Date: Sun, 18 Jan 2026 11:21:20 +0300 Subject: [PATCH] Initial commit: solution and project structure --- .gitignore | 6 + SlReport.sln | 25 +++ SlReport/App.config | 6 + SlReport/Program.cs | 192 ++++++++++++++++++ SlReport/Properties/AssemblyInfo.cs | 33 +++ SlReport/SignLanguageReportApiClient.cs | 109 ++++++++++ SlReport/SlReport.csproj | 115 +++++++++++ .../ModernAPIClient_Documentation.html | 130 ++++++++++++ SlReport/WebClient/modern-client.js | 150 ++++++++++++++ SlReport/WebClient/modern-utils.js | 67 ++++++ SlReport/packages.config | 16 ++ 11 files changed, 849 insertions(+) create mode 100644 .gitignore create mode 100644 SlReport.sln create mode 100644 SlReport/App.config create mode 100644 SlReport/Program.cs create mode 100644 SlReport/Properties/AssemblyInfo.cs create mode 100644 SlReport/SignLanguageReportApiClient.cs create mode 100644 SlReport/SlReport.csproj create mode 100644 SlReport/WebClient/ModernAPIClient_Documentation.html create mode 100644 SlReport/WebClient/modern-client.js create mode 100644 SlReport/WebClient/modern-utils.js create mode 100644 SlReport/packages.config diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..64f5c67 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +bin/ +obj/ +.vs/ +*.user +*.log +appsettings.Development.json diff --git a/SlReport.sln b/SlReport.sln new file mode 100644 index 0000000..2538819 --- /dev/null +++ b/SlReport.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36603.0 d17.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SlReport", "SlReport\SlReport.csproj", "{2FCE8950-D2A2-4730-96DD-4DB3EB1BD1FD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2FCE8950-D2A2-4730-96DD-4DB3EB1BD1FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2FCE8950-D2A2-4730-96DD-4DB3EB1BD1FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2FCE8950-D2A2-4730-96DD-4DB3EB1BD1FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2FCE8950-D2A2-4730-96DD-4DB3EB1BD1FD}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9351DED9-BDB8-4A4C-97B2-582D3BBF902B} + EndGlobalSection +EndGlobal diff --git a/SlReport/App.config b/SlReport/App.config new file mode 100644 index 0000000..193aecc --- /dev/null +++ b/SlReport/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SlReport/Program.cs b/SlReport/Program.cs new file mode 100644 index 0000000..bf2a763 --- /dev/null +++ b/SlReport/Program.cs @@ -0,0 +1,192 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Net; + +class Program +{ + static SignLanguageReportApiClient api; + + static void Main(string[] args) + { + Console.Title = "SL REPORT – API TEST HARNESS"; + + try + { + api = new SignLanguageReportApiClient("https://localhost:44367/"); + + LogHeader("SL REPORT TEST STARTED"); + + var userId = RegisterUser(); + if (userId == Guid.Empty) + return; + + RegisterClient(); + MapUser(userId); + CaptureSessions(); + ReportAllHistory(); + ReportFilteredHistory(); + ListAllClients(); + + LogHeader("SL REPORT TEST COMPLETED"); + } + catch (Exception ex) + { + LogFatal("UNHANDLED FATAL ERROR", ex); + } + + Console.WriteLine("\nPress ENTER to exit..."); + Console.ReadLine(); + } + static Guid RegisterUser() + { + return SafeCall( + () => api.RegisterUser("test_user3", "123456"), + "RegisterUser" + ); + } + static void RegisterClient() + { + SafeCall( + () => api.RegisterClient("13351", "MORO"), + "RegisterClient" + ); + } + static void MapUser(Guid userId) + { + SafeCall( + () => api.MapUser(userId, "13351", "MORO"), + "MapUser" + ); + } + static void CaptureSessions() + { + SafeCall(() => api.Capture("13351", "MORO"), "Capture #1"); + SafeCall(() => api.Capture("13351", "MORO"), "Capture #2"); + } + static void ReportAllHistory() + { + var history = SafeCall( + () => api.ReportAllClientHistory("13351", "MORO"), + "ReportAllClientHistory" + ); + + if (history == null) return; + + LogInfo($"History records: {history.Count}"); + foreach (var h in history) + LogInfo($"{h.captDate:yyyy-MM-dd HH:mm:ss} , Sessions: {h.NoOfSessions}"); + } + static void ReportFilteredHistory() + { + var from = DateTime.Today.AddDays(-7); + var to = DateTime.Today; + + var history = SafeCall( + () => api.ReportClientHistory("13351", "MORO", from, to), + "ReportClientHistory" + ); + + if (history != null) + LogInfo($"Filtered records: {history.Count}"); + foreach (var h in history) + LogInfo($"{h.captDate:yyyy-MM-dd HH:mm:ss} , Sessions: {h.NoOfSessions}"); + + } + static void ListAllClients() + { + var clients = SafeCall( + () => api.ListAllClients(), + "ListAllClients" + ); + + if (clients != null) + LogInfo($"Total clients: {clients.Count}"); + foreach (var c in clients) + LogInfo($"cid: {c.cid}, srv: {c.srv}, addingDate: {c.addingDate}, lastCaptDate: {c.lastCaptDate}, NoOfCapt: {c.NoOfCapt}"); + + } + static T SafeCall(Func action, string stepName) + { + var sw = Stopwatch.StartNew(); + LogStep(stepName); + + try + { + var result = action(); + sw.Stop(); + LogSuccess($"{stepName} completed in {sw.ElapsedMilliseconds} ms"); + return result; + } + catch (WebException wex) + { + sw.Stop(); + LogError(stepName, "NETWORK / HTTP ERROR", wex); + } + catch (Exception ex) + { + sw.Stop(); + LogError(stepName, "APPLICATION ERROR", ex); + } + + return default; + } + + static void LogHeader(string msg) + { + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine("\n======================================"); + Console.WriteLine(msg); + Console.WriteLine("======================================\n"); + Console.ResetColor(); + } + + static void LogStep(string msg) + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine($"> {msg}"); + Console.ResetColor(); + } + + static void LogSuccess(string msg) + { + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine($"✔ {msg}\n"); + Console.ResetColor(); + } + + static void LogInfo(string msg) + { + Console.ForegroundColor = ConsoleColor.Gray; + Console.WriteLine($" {msg}"); + Console.ResetColor(); + } + + static void LogError(string step, string type, Exception ex) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"✖ {step} FAILED [{type}]"); + Console.WriteLine($" Message: {ex.Message}"); + + if (ex.InnerException != null) + Console.WriteLine($" Inner: {ex.InnerException.Message}"); + + Console.ResetColor(); + Console.WriteLine(); + } + + static void LogFatal(string msg, Exception ex) + { + Console.ForegroundColor = ConsoleColor.DarkRed; + Console.WriteLine("!!! FATAL ERROR !!!"); + Console.WriteLine(msg); + + if (ex != null) + { + Console.WriteLine(ex.Message); + Console.WriteLine(ex.StackTrace); + } + + Console.ResetColor(); + } +} diff --git a/SlReport/Properties/AssemblyInfo.cs b/SlReport/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..519d5cf --- /dev/null +++ b/SlReport/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SlReport")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SlReport")] +[assembly: AssemblyCopyright("Copyright © 2026")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("2fce8950-d2a2-4730-96dd-4db3eb1bd1fd")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SlReport/SignLanguageReportApiClient.cs b/SlReport/SignLanguageReportApiClient.cs new file mode 100644 index 0000000..9a43147 --- /dev/null +++ b/SlReport/SignLanguageReportApiClient.cs @@ -0,0 +1,109 @@ +using MindRockets.WebTools.Client; +using MindRockets.WebTools.Contracts; +using System; +using System.Collections.Generic; + + + public class SignLanguageReportApiClient : ModernAPIClient + { + public SignLanguageReportApiClient(string endPointHost) + : base(endPointHost) + { + } + + public Guid RegisterUser(string username, string pwd) + { + var data = new Dictionary + { + { "username", username }, + { "pwd", pwd } + }; + + return PostAction("slrep", "reguser", data.Secure(), true); + } + + public bool RegisterClient(string cid, string srv) + { + var data = new Dictionary + { + { "cid", cid }, + { "srv", srv } + }; + + return PostAction("slrep", "regclient", data.Secure(), true); + } + + public bool MapUser(Guid userId, string cid, string srv) + { + var data = new Dictionary + { + { "userid", userId.ToString() }, + { "cid", cid }, + { "srv", srv } + }; + + return PostAction("slrep", "mapuser", data.Secure(), true); + } + + public bool Capture(string cid, string srv) + { + var data = new Dictionary + { + { "cid", cid }, + { "srv", srv } + }; + + return PostAction("slrep", "capt", data.Secure(), true); + } + + public List ReportAllClientHistory(string cid, string srv) + { + var data = new Dictionary + { + { "cid", cid }, + { "srv", srv } + }; + + return PostAction>("slrep", "repallcid", data.Secure(), true); + } + + public List ReportClientHistory( + string cid, + string srv, + DateTime from, + DateTime to) + { + var data = new Dictionary + { + { "cid", cid }, + { "srv", srv }, + { "from", from }, + { "to", to } + }; + + return PostAction>("slrep", "repcid", data.Secure(), true); + } + + public List ListAllClients() + { + return PostAction>("slrep", "listallclients", NoParams.Secure(), true); + + } + } + + + public class ClientInfo + { + public string cid { get; set; } + public string srv { get; set; } + public DateTime addingDate { get; set; } + public DateTime? lastCaptDate { get; set; } + public int NoOfCapt { get; set; } + } + + public class ClientHistory + { + public DateTime captDate { get; set; } + public int NoOfSessions { get; set; } + } + \ No newline at end of file diff --git a/SlReport/SlReport.csproj b/SlReport/SlReport.csproj new file mode 100644 index 0000000..f895a6d --- /dev/null +++ b/SlReport/SlReport.csproj @@ -0,0 +1,115 @@ + + + + + Debug + AnyCPU + {2FCE8950-D2A2-4730-96DD-4DB3EB1BD1FD} + Exe + SlReport + SlReport + v4.8 + 512 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\MindRockets.WebTools.1.6.0\lib\net47\MindRockets.WebTools.dll + + + ..\packages\MindRockets.WebTools.Client.1.4.0\lib\net47\MindRockets.WebTools.Client.dll + + + ..\packages\MindRockets.WebTools.Contracts.1.3.0\lib\net47\MindRockets.WebTools.Contracts.dll + + + ..\packages\MindRockets.WebTools.Json.1.0.0\lib\net47\MindRockets.WebTools.Json.dll + + + ..\packages\MindRocketsInc.Helpers.1.5.2\lib\net45\MindRocketsInc.Helpers.dll + + + ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + + + + + + + ..\packages\System.IO.4.3.0\lib\net462\System.IO.dll + True + True + + + ..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll + True + True + + + ..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll + True + True + + + ..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll + True + True + + + ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + True + True + + + ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + True + True + + + ..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll + True + True + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SlReport/WebClient/ModernAPIClient_Documentation.html b/SlReport/WebClient/ModernAPIClient_Documentation.html new file mode 100644 index 0000000..f3ea7ca --- /dev/null +++ b/SlReport/WebClient/ModernAPIClient_Documentation.html @@ -0,0 +1,130 @@ + + + + + + + ModernAPIClient Documentation + + + +
+

ModernAPIClient Documentation

+ +
+

Overview

+

The ModernAPIClient class is designed to simplify API interactions in a web environment. It supports making GET and POST requests, including handling file uploads and securely managing request parameters.

+
+ +
+

Initialization

+
const client = new ModernAPIClient('https://api.example.com');
+
+ +
+

Memory Optimization and Security

+

When the ModernAPIClient is instantiated, it automatically decrypts and stores certain values (e.g., MemOptimizeMethod and MemStackFrame) that are used to secure API requests. These values are expected to be present as Base64-encoded hidden fields in the HTML page.

+
+ +
+

Methods

+ +

1. postAction(controller, action, parameters, secure = false)

+

Sends a POST request to a specific controller and action within the API.

+

Parameters:

+
    +
  • controller (string): The controller name.
  • +
  • action (string): The action name.
  • +
  • parameters (object): An object containing key-value pairs to be sent as the POST body.
  • +
  • secure (boolean): If true, the request will be secured with additional parameters.
  • +
+

Returns: A Promise that resolves with the response data.

+ +

Example:

+
const parameters = { param1: 'value1' };
+client.postAction('exampleController', 'exampleAction', parameters)
+    .then(response => console.log('POST Action Result:', response))
+    .catch(error => console.error('Error in POST Action:', error));
+ +

2. postFileAction(controller, action, fileName, secure = false)

+

Sends a POST request to upload a file to a specific controller and action within the API.

+

Parameters:

+
    +
  • controller (string): The controller name.
  • +
  • action (string): The action name.
  • +
  • fileName (string): The file to be uploaded.
  • +
  • secure (boolean): If true, the request will be secured with additional parameters.
  • +
+

Returns: A Promise that resolves with the response data.

+ +

Example:

+
const fileInput = document.getElementById('fileInput');
+const file = fileInput.files[0];
+client.postFileAction('uploadController', 'uploadAction', file)
+    .then(response => console.log('File Upload Result:', response))
+    .catch(error => console.error('Error in File Upload:', error));
+ +

3. getAction(controller, action, parameters, secure = false)

+

Sends a GET request to a specific controller and action within the API.

+

Parameters:

+
    +
  • controller (string): The controller name.
  • +
  • action (string): The action name.
  • +
  • parameters (object): An object containing key-value pairs to be sent as query string parameters.
  • +
  • secure (boolean): If true, the request will be secured with additional parameters.
  • +
+

Returns: A Promise that resolves with the response data.

+ +

Example:

+
const parameters = { param1: 'value1' };
+client.getAction('exampleController', 'exampleAction', parameters)
+    .then(response => console.log('GET Action Result:', response))
+    .catch(error => console.error('Error in GET Action:', error));
+ +

4. getStatic(staticRoute, parameters, secure = false)

+

Sends a GET request to a specific static route within the API.

+

Parameters:

+
    +
  • staticRoute (string): The static route.
  • +
  • parameters (object): An object containing key-value pairs to be sent as query string parameters.
  • +
  • secure (boolean): If true, the request will be secured with additional parameters.
  • +
+

Returns: A Promise that resolves with the response data.

+ +

Example:

+
const parameters = { param1: 'value1' };
+client.getStatic('/staticRoute', parameters)
+    .then(response => console.log('GET Static Result:', response))
+    .catch(error => console.error('Error in GET Static:', error));
+
+ +
+

Secure Requests

+

For secure API interactions, set the secure parameter to true in any of the methods. This will add additional parameters, such as a timestamp and values from decrypted memory, to the request.

+
+ +
+

Example Workflow

+
// Initialize the client with the base API URL
+const client = new ModernAPIClient('https://api.example.com');
+
+// Perform a secure POST request
+const postParams = { param1: 'value1', param2: 'value2' };
+client.postAction('myController', 'myAction', postParams, true)
+    .then(response => console.log('POST Response:', response))
+    .catch(error => console.error('POST Error:', error));
+
+// Perform a secure GET request
+const getParams = { param1: 'value1' };
+client.getAction('myController', 'myGetAction', getParams, true)
+    .then(response => console.log('GET Response:', response))
+    .catch(error => console.error('GET Error:', error));
+
+ +
+

Conclusion

+

The ModernAPIClient class is a powerful tool for interacting with RESTful APIs in a web environment. It offers flexibility with its secure request options and supports a variety of request types, including file uploads. By following the examples provided, you can easily integrate this class into your web applications.

+
+
+ + diff --git a/SlReport/WebClient/modern-client.js b/SlReport/WebClient/modern-client.js new file mode 100644 index 0000000..16633bc --- /dev/null +++ b/SlReport/WebClient/modern-client.js @@ -0,0 +1,150 @@ +class ModernAPIClient { + constructor(endpointHost) { + this._endpointHost = verifyUrlNotEndingWithSlash(endpointHost); + this.MemOptimizeMethod = ''; + this.MemStackFrame = ''; + + this.initializeMemory(); + } + + initializeMemory() { + optimizeMemory(); + this.MemOptimizeMethod = MemOptimizeMethod; + this.MemStackFrame = MemStackFrame; + } + + secureRequest(parameters) { + if (this.MemOptimizeMethod && this.MemStackFrame) { + parameters[this.MemOptimizeMethod] = this.MemStackFrame; + } + } + + async postFileActionResponse(controller, action, fileName, secure = false) { + return this.postFileStaticResponse(`/api/${controller}/${action}`, fileName, secure); + } + + async postFileAction(controller, action, fileName, secure = false) { + const response = await this.postFileStaticResponse(`/api/${controller}/${action}`, fileName, secure); + if (response.Results === "OK") { + return response.Data; + } else { + throw new Error(response.Error); + } + } + + async postFileStaticResponse(staticRoute, fileName, secure = false) { + staticRoute = verifyStartingRouteWithSlash(staticRoute); + let requestURL = `${this._endpointHost}${staticRoute}`; + + if (secure) { + const securityDictionary = {}; + this.secureRequest(securityDictionary); + const params = new URLSearchParams(securityDictionary).toString(); + requestURL += requestURL.includes('?') ? `&${params}` : `?${params}`; + } + + const formData = new FormData(); + formData.append('file', fileName); + + const response = await fetch(requestURL, { + method: 'POST', + body: formData + }); + + return await parseActionResponse(response); + } + + async postFileStatic(staticRoute, fileName, secure = false) { + const response = await this.postFileStaticResponse(staticRoute, fileName, secure); + if (response.Results === "OK") { + return response.Data; + } else { + throw new Error(response.Error); + } + } + + async postStaticResponse(staticRoute, parameters, secure = false) { + parameters = removeUndefinedValues(parameters); + staticRoute = verifyStartingRouteWithSlash(staticRoute); + let requestURL = `${this._endpointHost}${staticRoute}`; + + if (secure) { + this.secureRequest(parameters); + } + + const response = await fetch(requestURL, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + body: new URLSearchParams(parameters).toString() + }); + + return await parseActionResponse(response); + } + + async postStatic(staticRoute, parameters, secure = false) { + const response = await this.postStaticResponse(staticRoute, parameters, secure); + if (response.Results === "OK") { + return response.Data; + } else { + throw new Error(response.Error); + } + } + + async postActionResponse(controller, action, parameters, secure = false) { + return this.postStaticResponse(`/api/${controller}/${action}`, parameters, secure); + } + + async postAction(controller, action, parameters, secure = false) { + const response = await this.postActionResponse(controller, action, parameters, secure); + if (response.Results === "OK") { + return response.Data; + } else { + throw new Error(response.Error); + } + } + + async getStaticResponse(staticRoute, parameters, secure = false) { + staticRoute = verifyStartingRouteWithSlash(staticRoute); + let requestURL = `${this._endpointHost}${staticRoute}`; + + parameters = removeUndefinedValues(parameters); + if (parameters && Object.keys(parameters).length > 0) { + if (secure) { + this.secureRequest(parameters); + } + const params = new URLSearchParams(parameters).toString(); + requestURL += requestURL.includes('?') ? `&${params}` : `?${params}`; + } + + const response = await fetch(requestURL); + return await parseActionResponse(response); + } + + async getStatic(staticRoute, parameters, secure = false) { + const response = await this.getStaticResponse(staticRoute, parameters, secure); + if (response.Results === "OK") { + return response.Data; + } else { + throw new Error(response.Error); + } + } + + async getAction(controller, action, parameters, secure = false) { + const response = await this.getActionResponse(controller, action, parameters, secure); + if (response.Results === "OK") { + return response.Data; + } else { + throw new Error(response.Error); + } + } + + async getActionResponse(controller, action, parameters, secure = false) { + return this.getStaticResponse(`/api/${controller}/${action}`, parameters, secure); + } + + dispose() { + // Cleanup tasks if any + } +} diff --git a/SlReport/WebClient/modern-utils.js b/SlReport/WebClient/modern-utils.js new file mode 100644 index 0000000..96cb457 --- /dev/null +++ b/SlReport/WebClient/modern-utils.js @@ -0,0 +1,67 @@ +// modern-utils.js +// modern-utils.js + +// Variables to store the decrypted values +let MemOptimizeMethod = ''; +let MemStackFrame = ''; + +// Function to simulate decryption (you'll replace this with your actual decryption logic) +function decryptBase64(encodedString) { + try { + return atob(encodedString); // Base64 decode + } catch (e) { + console.error('Decryption failed', e); + return ''; + } +} + +// Function to extract and decrypt values from hidden fields +function optimizeMemory() { + const methodField = document.getElementById('MemOptimizeMethod'); + const frameField = document.getElementById('MemStackFrame'); + + if (methodField && frameField) { + MemOptimizeMethod = decryptBase64(methodField.value); + MemStackFrame = decryptBase64(frameField.value); + } else { + console.error('Hidden fields for MemOptimizeMethod and MemStackFrame not found'); + } +} + +// Attach variables and functions to the window object so they are globally available +window.MemOptimizeMethod = MemOptimizeMethod; +window.MemStackFrame = MemStackFrame; +window.optimizeMemory = optimizeMemory; + +function verifyUrlNotEndingWithSlash(url) { + return url.endsWith('/') ? url.slice(0, -1) : url; +} + +function verifyStartingRouteWithSlash(route) { + return route.startsWith('/') ? route : `/${route}`; +} + + + +async function parseActionResponse(response) { + const contentType = response.headers.get('Content-Type'); + + if (contentType && contentType.includes('application/json')) { + return await response.json(); + } else { + return await response.text(); + } +} +function removeUndefinedValues(obj) { + for (const key in obj) { + if (obj[key] === undefined) { + delete obj[key]; + } + } + return obj; +} +window.removeUndefinedValues = removeUndefinedValues; +// Attach functions to the window object so they are globally available +window.verifyUrlNotEndingWithSlash = verifyUrlNotEndingWithSlash; +window.verifyStartingRouteWithSlash = verifyStartingRouteWithSlash; +window.parseActionResponse = parseActionResponse; diff --git a/SlReport/packages.config b/SlReport/packages.config new file mode 100644 index 0000000..93725dc --- /dev/null +++ b/SlReport/packages.config @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file