From 82bb4b87b640e4d969fdb39959fbf0e7bf0a8ff2 Mon Sep 17 00:00:00 2001 From: Stoyan Zlatev Date: Fri, 2 Jun 2023 15:49:59 +0200 Subject: [PATCH] Genesis Toolbox login form --- .gitignore | 1 + .../CommonCore.Configuration/ServiceUrls.cs | 7 + ...ToXlsHelper.csproj.CoreCompileInputs.cache | 2 +- .../GenesisToolBox/Ctls/LoginForm.Designer.cs | 160 ++++++++++++++++++ Common/Ui/GenesisToolBox/Ctls/LoginForm.cs | 68 ++++++++ Common/Ui/GenesisToolBox/Ctls/LoginForm.resx | 123 ++++++++++++++ .../Ui/GenesisToolBox/GenesisToolBox.csproj | 15 ++ .../GenesisToolBox/GenesisToolBox.csproj.user | 1 + .../Infrastructure/ApplicationHttp.cs | 105 ++++++++++++ .../Infrastructure/ApplicationState.cs | 57 +++++++ .../Infrastructure/ApplicationVersion.cs | 44 +++++ .../Infrastructure/SoftwareFunctions.cs | 27 +++ Common/Ui/GenesisToolBox/Program.cs | 13 +- Common/Ui/GenesisToolBox/frmMainForm.cs | 98 ++++++++++- .../Interfaces/ISoftwareService.cs | 4 +- .../SoftwareService.cs | 49 +++++- .../Controllers/FunctionsController.cs | 54 ------ .../Account/Controllers/PWDController.cs | 40 ----- .../Software/Controllers/AppIdController.cs | 26 +++ .../Controllers/FunctionsController.cs | 42 +++++ .../Software/SoftwareAreaRegistration.cs | 17 ++ .../LaaProductionWeb/LaaProductionWeb.csproj | 9 +- 22 files changed, 853 insertions(+), 109 deletions(-) create mode 100644 Common/Ui/GenesisToolBox/Ctls/LoginForm.Designer.cs create mode 100644 Common/Ui/GenesisToolBox/Ctls/LoginForm.cs create mode 100644 Common/Ui/GenesisToolBox/Ctls/LoginForm.resx create mode 100644 Common/Ui/GenesisToolBox/Infrastructure/ApplicationHttp.cs create mode 100644 Common/Ui/GenesisToolBox/Infrastructure/ApplicationState.cs create mode 100644 Common/Ui/GenesisToolBox/Infrastructure/ApplicationVersion.cs create mode 100644 Common/Ui/GenesisToolBox/Infrastructure/SoftwareFunctions.cs delete mode 100644 LaaProductionWeb/LaaProductionWeb/Areas/Account/Controllers/FunctionsController.cs delete mode 100644 LaaProductionWeb/LaaProductionWeb/Areas/Account/Controllers/PWDController.cs create mode 100644 LaaProductionWeb/LaaProductionWeb/Areas/Software/Controllers/AppIdController.cs create mode 100644 LaaProductionWeb/LaaProductionWeb/Areas/Software/Controllers/FunctionsController.cs create mode 100644 LaaProductionWeb/LaaProductionWeb/Areas/Software/SoftwareAreaRegistration.cs diff --git a/.gitignore b/.gitignore index 44011104..8400ee83 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ *.user *.userosscache *.sln.docstates +*MagFlux/MjkControlledCodeRef* # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs diff --git a/Common/CommonCore.Configuration/ServiceUrls.cs b/Common/CommonCore.Configuration/ServiceUrls.cs index 2d5bb901..ac5c7236 100644 --- a/Common/CommonCore.Configuration/ServiceUrls.cs +++ b/Common/CommonCore.Configuration/ServiceUrls.cs @@ -199,6 +199,13 @@ namespace Xylem.Common.CommonCore.Configuration private const String PressureSensorTestURL_GetTestResults = "http://sla12iis01.emea.sensus.net/MeterProcessState/api/CordonelPressureSensorTest/GetTestResults/{0}"; + public const string LaaProductionAPI +#if DEBUG + = "http://localhost:54448"; +#else + = "http://sla12iis01.emea.sensus.net"; +#endif + /// /// GET: test specification for water meter with pressure sensor. diff --git a/Common/Tools/Tools.JsonToXlsHelper/obj/Debug/Tools.JsonToXlsHelper.csproj.CoreCompileInputs.cache b/Common/Tools/Tools.JsonToXlsHelper/obj/Debug/Tools.JsonToXlsHelper.csproj.CoreCompileInputs.cache index 0028f628..f98f081f 100644 --- a/Common/Tools/Tools.JsonToXlsHelper/obj/Debug/Tools.JsonToXlsHelper.csproj.CoreCompileInputs.cache +++ b/Common/Tools/Tools.JsonToXlsHelper/obj/Debug/Tools.JsonToXlsHelper.csproj.CoreCompileInputs.cache @@ -1 +1 @@ -f64d563def603c89cafafa61a3219ba97e1e344c +57a46bdf07e306281dc4ae72a3747ed460385fe7 diff --git a/Common/Ui/GenesisToolBox/Ctls/LoginForm.Designer.cs b/Common/Ui/GenesisToolBox/Ctls/LoginForm.Designer.cs new file mode 100644 index 00000000..c18c0208 --- /dev/null +++ b/Common/Ui/GenesisToolBox/Ctls/LoginForm.Designer.cs @@ -0,0 +1,160 @@ +namespace Xylem.Common.Ui.GenesisToolBox.Ctls +{ + partial class LoginForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.LoginFormPanel = new System.Windows.Forms.Panel(); + this.ErrorMessage = new System.Windows.Forms.Label(); + this.LoginButton = new System.Windows.Forms.Button(); + this.Password = new System.Windows.Forms.TextBox(); + this.UsernameLabel = new System.Windows.Forms.Label(); + this.Username = new System.Windows.Forms.TextBox(); + this.PasswordLabel = new System.Windows.Forms.Label(); + this.LoginErrorProvider = new System.Windows.Forms.ErrorProvider(this.components); + this.LoginFormPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.LoginErrorProvider)).BeginInit(); + this.SuspendLayout(); + // + // LoginFormPanel + // + this.LoginFormPanel.Controls.Add(this.ErrorMessage); + this.LoginFormPanel.Controls.Add(this.LoginButton); + this.LoginFormPanel.Controls.Add(this.Password); + this.LoginFormPanel.Controls.Add(this.UsernameLabel); + this.LoginFormPanel.Controls.Add(this.Username); + this.LoginFormPanel.Controls.Add(this.PasswordLabel); + this.LoginFormPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.LoginFormPanel.Location = new System.Drawing.Point(0, 0); + this.LoginFormPanel.Name = "LoginFormPanel"; + this.LoginFormPanel.Size = new System.Drawing.Size(458, 439); + this.LoginFormPanel.TabIndex = 0; + // + // ErrorMessage + // + this.ErrorMessage.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.ErrorMessage.AutoSize = true; + this.ErrorMessage.ForeColor = System.Drawing.Color.Red; + this.ErrorMessage.Location = new System.Drawing.Point(96, 251); + this.ErrorMessage.Name = "ErrorMessage"; + this.ErrorMessage.Size = new System.Drawing.Size(0, 13); + this.ErrorMessage.TabIndex = 5; + // + // LoginButton + // + this.LoginButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.LoginButton.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.LoginButton.Location = new System.Drawing.Point(97, 221); + this.LoginButton.Name = "LoginButton"; + this.LoginButton.Size = new System.Drawing.Size(266, 23); + this.LoginButton.TabIndex = 4; + this.LoginButton.Text = "Login"; + this.LoginButton.UseVisualStyleBackColor = true; + this.LoginButton.Click += new System.EventHandler(this.LoginButtonClick); + // + // Password + // + this.Password.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.Password.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.Password.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Password.Location = new System.Drawing.Point(97, 195); + this.Password.Name = "Password"; + this.Password.PasswordChar = '*'; + this.Password.Size = new System.Drawing.Size(266, 20); + this.Password.TabIndex = 3; + this.Password.UseSystemPasswordChar = true; + // + // UsernameLabel + // + this.UsernameLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.UsernameLabel.AutoSize = true; + this.UsernameLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.UsernameLabel.Location = new System.Drawing.Point(94, 140); + this.UsernameLabel.Name = "UsernameLabel"; + this.UsernameLabel.Size = new System.Drawing.Size(63, 13); + this.UsernameLabel.TabIndex = 0; + this.UsernameLabel.Text = "Username"; + // + // Username + // + this.Username.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.Username.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Username.Location = new System.Drawing.Point(97, 156); + this.Username.Name = "Username"; + this.Username.Size = new System.Drawing.Size(266, 20); + this.Username.TabIndex = 2; + // + // PasswordLabel + // + this.PasswordLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.PasswordLabel.AutoSize = true; + this.PasswordLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.PasswordLabel.Location = new System.Drawing.Point(94, 179); + this.PasswordLabel.Name = "PasswordLabel"; + this.PasswordLabel.Size = new System.Drawing.Size(61, 13); + this.PasswordLabel.TabIndex = 1; + this.PasswordLabel.Text = "Password"; + // + // LoginErrorProvider + // + this.LoginErrorProvider.BlinkRate = 0; + this.LoginErrorProvider.BlinkStyle = System.Windows.Forms.ErrorBlinkStyle.NeverBlink; + this.LoginErrorProvider.ContainerControl = this; + // + // LoginForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.LoginFormPanel); + this.Name = "LoginForm"; + this.Size = new System.Drawing.Size(458, 439); + this.LoginFormPanel.ResumeLayout(false); + this.LoginFormPanel.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.LoginErrorProvider)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Panel LoginFormPanel; + private System.Windows.Forms.Button LoginButton; + private System.Windows.Forms.TextBox Password; + private System.Windows.Forms.Label UsernameLabel; + private System.Windows.Forms.TextBox Username; + private System.Windows.Forms.Label PasswordLabel; + private System.Windows.Forms.ErrorProvider LoginErrorProvider; + private System.Windows.Forms.Label ErrorMessage; + } +} diff --git a/Common/Ui/GenesisToolBox/Ctls/LoginForm.cs b/Common/Ui/GenesisToolBox/Ctls/LoginForm.cs new file mode 100644 index 00000000..4a327012 --- /dev/null +++ b/Common/Ui/GenesisToolBox/Ctls/LoginForm.cs @@ -0,0 +1,68 @@ +namespace Xylem.Common.Ui.GenesisToolBox.Ctls +{ + using System; + using System.Security.Cryptography; + using System.Text; + using System.Windows.Forms; + + public partial class LoginForm : UserControl + { + private readonly Action submittedCallback; + + public LoginForm() + { + this.InitializeComponent(); + + this.Dock = DockStyle.Fill; + } + + public LoginForm(Action submittedCallback) : this() + => this.submittedCallback = submittedCallback; + + private void LoginButtonClick(object sender, EventArgs e) + { + this.ErrorMessage.Text = default(string); + this.LoginErrorProvider.Clear(); + + var isValid = true; + + if (string.IsNullOrWhiteSpace(this.Username.Text)) + { + isValid = false; + + this.LoginErrorProvider.SetError(this.Username, "Username is required."); + } + + if (string.IsNullOrWhiteSpace(this.Password.Text)) + { + isValid = false; + + this.LoginErrorProvider.SetError(this.Password, "Password is required."); + } + + if (isValid) + { + this.submittedCallback?.Invoke(this.Username.Text, this.Password.Text.ComputeBase64Hash(), this); + } + } + + internal void ShowError(string errorMessage) + => this.ErrorMessage.Text = errorMessage; + } + + internal static class PasswordExtensions + { + internal static string ComputeBase64Hash(this string plainText) + { + if (string.IsNullOrWhiteSpace(plainText)) + { + return plainText; + } + + var buffer = Encoding.UTF8.GetBytes(plainText); + var hash = SHA256.Create().ComputeHash(buffer); + + return Convert.ToBase64String(hash); + } + } +} diff --git a/Common/Ui/GenesisToolBox/Ctls/LoginForm.resx b/Common/Ui/GenesisToolBox/Ctls/LoginForm.resx new file mode 100644 index 00000000..4995eff7 --- /dev/null +++ b/Common/Ui/GenesisToolBox/Ctls/LoginForm.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/Common/Ui/GenesisToolBox/GenesisToolBox.csproj b/Common/Ui/GenesisToolBox/GenesisToolBox.csproj index 00fb9b10..a6cf4710 100644 --- a/Common/Ui/GenesisToolBox/GenesisToolBox.csproj +++ b/Common/Ui/GenesisToolBox/GenesisToolBox.csproj @@ -43,6 +43,7 @@ 7.0 false bin\Debug\Xylem.Common.Ui.GenesisToolBox.xml + 1591 AnyCPU @@ -170,6 +171,7 @@ + @@ -196,6 +198,12 @@ ctlConnectInterface.cs + + UserControl + + + LoginForm.cs + Component @@ -404,6 +412,10 @@ FrmTempMeter.cs + + + + @@ -422,6 +434,9 @@ TextFileMatchControl.cs + + LoginForm.cs + FrmCalibrationResults.cs diff --git a/Common/Ui/GenesisToolBox/GenesisToolBox.csproj.user b/Common/Ui/GenesisToolBox/GenesisToolBox.csproj.user index 54b1889f..888ca413 100644 --- a/Common/Ui/GenesisToolBox/GenesisToolBox.csproj.user +++ b/Common/Ui/GenesisToolBox/GenesisToolBox.csproj.user @@ -10,5 +10,6 @@ de-DE false + ProjectFiles \ No newline at end of file diff --git a/Common/Ui/GenesisToolBox/Infrastructure/ApplicationHttp.cs b/Common/Ui/GenesisToolBox/Infrastructure/ApplicationHttp.cs new file mode 100644 index 00000000..9e606a66 --- /dev/null +++ b/Common/Ui/GenesisToolBox/Infrastructure/ApplicationHttp.cs @@ -0,0 +1,105 @@ +namespace Xylem.Common.Ui.GenesisToolBox.Infrastructure +{ + using Newtonsoft.Json; + + using System; + using System.Collections.Generic; + using System.Net.Http; + using System.Text; + using System.Threading.Tasks; + + using Xylem.Common.CommonCore.Configuration; + + internal class ApplicationHttp + { + const string APPLICATION_JSON = "application/json"; + + private static readonly HttpClient httpClient = new HttpClient() + { + BaseAddress = new Uri(ServiceUrls.LaaProductionAPI) + }; + + internal static int ApplicationId(string software, params string[] functions) + => Task + .Run(async () => + { + var applicationId = default(int); + + try + { + using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "api/software/appid")) + { + httpRequestMessage.Content = new StringContent( + mediaType: APPLICATION_JSON, + encoding: Encoding.UTF8, + content: JsonConvert.SerializeObject(new + { + software, + functions + })); + + using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage)) + { + if (httpResponseMessage.Content != null) + { + var httpResponseContent = await httpResponseMessage.Content.ReadAsStringAsync(); + + _ = int.TryParse(httpResponseContent, out applicationId); + } + } + } + } + catch (Exception) + { + // TODO: Log the error message. + } + + return applicationId; + }) + .ConfigureAwait(true) + .GetAwaiter() + .GetResult(); + + internal static IEnumerable GetSoftwareFunction(int appId, string username, string password) + => Task + .Run(async () => + { + var functions = default(IEnumerable); + + try + { + using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "api/software/functions")) + { + httpRequestMessage.Content = new StringContent( + mediaType: APPLICATION_JSON, + encoding: Encoding.UTF8, + content: JsonConvert.SerializeObject(new + { + appId, + username, + password, + })); + + using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage)) + { + if (httpResponseMessage.IsSuccessStatusCode && httpResponseMessage.Content != null) + { + var httpResponseContent = await httpResponseMessage.Content.ReadAsStringAsync(); + + functions = JsonConvert.DeserializeObject(httpResponseContent); + } + } + } + } + catch (Exception) + { + // TODO: Log the error message. + } + + return functions; + }) + .ConfigureAwait(true) + .GetAwaiter() + .GetResult(); + } +} diff --git a/Common/Ui/GenesisToolBox/Infrastructure/ApplicationState.cs b/Common/Ui/GenesisToolBox/Infrastructure/ApplicationState.cs new file mode 100644 index 00000000..779a9200 --- /dev/null +++ b/Common/Ui/GenesisToolBox/Infrastructure/ApplicationState.cs @@ -0,0 +1,57 @@ +namespace Xylem.Common.Ui.GenesisToolBox.Infrastructure +{ + using System; + using System.Collections.Generic; + using System.Linq; + + internal class ApplicationState + { + internal const string UNAVAILABLE = "Genesis Toolbox is currently not available."; + + + private static IEnumerable softwareFunctions; + + internal static int Id { get; private set; } + + internal static bool IsAuthorized { get; private set; } + + internal static bool Initialized { get; private set; } + + internal static ApplicationVersion Version { get; private set; } + = ApplicationVersion.Current; + + internal static void Initialize() + { + Id = ApplicationHttp.ApplicationId( + software: Version.Assembly.Name, + functions: Enum.GetNames(typeof(SoftwareFunctions))); + Initialized = Id > 0; + } + + internal static bool Authorize(string username, string password, out string error) + { + error = default(string); + + if (Id <= 0) + { + error = "Genesis Toolbox is currently not available."; + } + else + { + softwareFunctions = ApplicationHttp.GetSoftwareFunction(Id, username, password); + IsAuthorized = softwareFunctions != null; + + if (!IsAuthorized) + { + error = "Genesis Toolbox is currently not available."; + softwareFunctions = Array.Empty(); + } + } + + return IsAuthorized; + } + + internal static Boolean IsEnabled(SoftwareFunctions softwareFunction) + => softwareFunctions.Contains(softwareFunction); + } +} diff --git a/Common/Ui/GenesisToolBox/Infrastructure/ApplicationVersion.cs b/Common/Ui/GenesisToolBox/Infrastructure/ApplicationVersion.cs new file mode 100644 index 00000000..2f511562 --- /dev/null +++ b/Common/Ui/GenesisToolBox/Infrastructure/ApplicationVersion.cs @@ -0,0 +1,44 @@ +namespace Xylem.Common.Ui.GenesisToolBox.Infrastructure +{ + using System; + using System.Reflection; + + internal struct ApplicationVersion + { + private ApplicationVersion(bool initialize) + { + if (initialize) + { + this.Assembly = System.Reflection.Assembly + .GetExecutingAssembly() + .GetName(); + this.Major = this.Assembly.Version.Major; + this.Minor = this.Assembly.Version.Minor; + this.Build = this.Assembly.Version.Build; + } + else + { + this.Major = default(int); + this.Minor = default(int); + this.Build = default(int); + this.Assembly = default(AssemblyName); + } + } + + public int Major { get; } + + public int Minor { get; } + + public int Build { get; } + + public AssemblyName Assembly { get; } + + public override string ToString() + => $"{nameof(Version)}: {this.Major}.{this.Minor}.{this.Build}"; + + public static ApplicationVersion Current => new ApplicationVersion(true); + + public static implicit operator string(ApplicationVersion assemblyVersion) + => assemblyVersion.ToString(); + } +} diff --git a/Common/Ui/GenesisToolBox/Infrastructure/SoftwareFunctions.cs b/Common/Ui/GenesisToolBox/Infrastructure/SoftwareFunctions.cs new file mode 100644 index 00000000..aa6514b7 --- /dev/null +++ b/Common/Ui/GenesisToolBox/Infrastructure/SoftwareFunctions.cs @@ -0,0 +1,27 @@ +namespace Xylem.Common.Ui.GenesisToolBox.Infrastructure +{ + internal enum SoftwareFunctions + { + DEV_FILE_CONTROL, + DEV_FILE_SPLIT, + DEV_LEGACY_TEST_APP, + DEV_LOW_LEVEL_TOOLS, + + GENERAL_ALARM, + GENERAL_FIRMWARE_UPDATE, + GENERAL_LUT_MANAGEMENT, + GENERAL_LUT_UPDATE, + GENERAL_PRESSURE_LOG, + GENERAL_PULS_CONFIG, + GENERAL_REGISTER_STORE, + GENERAL_SETUP, + GENERAL_STREAM_QUALITY, + GENERAL_TEMP_METER, + + LAA_MAPPING_NA, + LAA_PASSWORD, + LAA_PARAMETERIZATION, + LAA_PROCESS_PARAMETER, + LAA_REGISTER_HISTORY, + } +} diff --git a/Common/Ui/GenesisToolBox/Program.cs b/Common/Ui/GenesisToolBox/Program.cs index d6623317..d88ebca5 100644 --- a/Common/Ui/GenesisToolBox/Program.cs +++ b/Common/Ui/GenesisToolBox/Program.cs @@ -1,16 +1,19 @@ -using System; -using System.Windows.Forms; - -namespace Xylem.Common.Ui.GenesisToolBox +namespace Xylem.Common.Ui.GenesisToolBox { + using System; + using System.Windows.Forms; + + using Xylem.Common.Ui.GenesisToolBox.Infrastructure; + internal static class Program { /// /// The main entry point for the application. /// [STAThread] - static void Main() + internal static void Main() { + ApplicationState.Initialize(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new FrmMainForm()); diff --git a/Common/Ui/GenesisToolBox/frmMainForm.cs b/Common/Ui/GenesisToolBox/frmMainForm.cs index e694bdf5..6ae037dc 100644 --- a/Common/Ui/GenesisToolBox/frmMainForm.cs +++ b/Common/Ui/GenesisToolBox/frmMainForm.cs @@ -1,9 +1,14 @@ using GenesisToolBox; + using System; +using System.Drawing; using System.IO; using System.Reflection; using System.Windows.Forms; + using Xylem.Common.CommonCore.Consts; +using Xylem.Common.Ui.GenesisToolBox.Ctls; +using Xylem.Common.Ui.GenesisToolBox.Infrastructure; using Xylem.Common.Utils.Logging; namespace Xylem.Common.Ui.GenesisToolBox @@ -19,7 +24,9 @@ namespace Xylem.Common.Ui.GenesisToolBox /// public FrmMainForm() { - InitializeComponent(); + this.InitializeComponent(); + this.InitializeFormState(); + var logger = NLogHelper.CreateOrGetLogger("GenesisToolBox"); var version = Assembly.GetExecutingAssembly().GetName().Version; logger.Info($"GenesisToolBox Version: {version.Major}.{version.Minor}.{version.Build}"); @@ -34,6 +41,95 @@ namespace Xylem.Common.Ui.GenesisToolBox lblVersionNumber.Text = $@"Version: {version.Major}.{version.Minor}.{version.Build}"; } + private void InitializeFormState() + { + foreach (var control in this.Controls) + { + if (control is GroupBox groupBox) + { + groupBox.Hide(); + } + } + + this.btnSetup.Tag = SoftwareFunctions.GENERAL_SETUP; + this.btnAlarm.Tag = SoftwareFunctions.GENERAL_ALARM; + this.btnRegisterStore.Tag = SoftwareFunctions.GENERAL_REGISTER_STORE; + this.btnTempLogger.Tag = SoftwareFunctions.GENERAL_TEMP_METER; + this.btnStreamingQuality.Tag = SoftwareFunctions.GENERAL_STREAM_QUALITY; + this.btnFwUpdate.Tag = SoftwareFunctions.GENERAL_FIRMWARE_UPDATE; + this.btnLutUpdate.Tag = SoftwareFunctions.GENERAL_LUT_UPDATE; + this.button4.Tag = SoftwareFunctions.GENERAL_LUT_MANAGEMENT; + this.btnPressure.Tag = SoftwareFunctions.GENERAL_PRESSURE_LOG; + this.button1.Tag = SoftwareFunctions.GENERAL_PULS_CONFIG; + + this.btnPassword.Tag = SoftwareFunctions.LAA_PASSWORD; + this.btnRegHistory.Tag = SoftwareFunctions.LAA_REGISTER_HISTORY; + this.btnPara.Tag = SoftwareFunctions.LAA_PARAMETERIZATION; + this.button2.Tag = SoftwareFunctions.LAA_PROCESS_PARAMETER; + this.button5.Tag = SoftwareFunctions.LAA_MAPPING_NA; + + this.btnLegacyTestApp.Tag = SoftwareFunctions.DEV_LEGACY_TEST_APP; + this.btnFiles.Tag = SoftwareFunctions.DEV_FILE_CONTROL; + this.BtnFileSplit.Tag = SoftwareFunctions.DEV_FILE_SPLIT; + this.btnLowLevelTools.Tag = SoftwareFunctions.DEV_LOW_LEVEL_TOOLS; + + if (!ApplicationState.Initialized) + { + this.Controls.Add(new Label() + { + Dock = DockStyle.Fill, + Text = ApplicationState.UNAVAILABLE, + TextAlign = ContentAlignment.MiddleCenter, + Font = new Font(FontFamily.GenericSansSerif, 10, FontStyle.Bold), + ForeColor = Color.DarkRed, + Padding = new Padding(15) + }); + } + else if (!ApplicationState.IsAuthorized) + { + this.Controls.Add(new LoginForm(this.LoginFormSubmitted)); + } + else + { + this.ShowAvailableSoftwareFunctions(); + } + } + + private void LoginFormSubmitted(string username, string password, object sender) + { + if (sender is LoginForm loginForm) + { + var errorMessage = default(string); + + if (ApplicationState.Authorize(username, password, out errorMessage)) + { + this.Controls.Remove(loginForm); + this.ShowAvailableSoftwareFunctions(); + } + + loginForm.ShowError(errorMessage); + } + } + + private void ShowAvailableSoftwareFunctions() + { + foreach (var control in this.Controls) + { + if (control is GroupBox groupBox) + { + foreach (var groupBoxControl in groupBox.Controls) + { + if (groupBoxControl is Button button && button.Tag is SoftwareFunctions softwareFunction) + { + button.Enabled = ApplicationState.IsEnabled(softwareFunction); + } + } + + groupBox.Show(); + } + } + } + private void btnSetup_Click(Object sender, EventArgs e) { var form = new FrmSetup(); diff --git a/LaaProductionWeb/LaaProductionWeb.Services/Interfaces/ISoftwareService.cs b/LaaProductionWeb/LaaProductionWeb.Services/Interfaces/ISoftwareService.cs index 4ee9c6d9..dc151e7b 100644 --- a/LaaProductionWeb/LaaProductionWeb.Services/Interfaces/ISoftwareService.cs +++ b/LaaProductionWeb/LaaProductionWeb.Services/Interfaces/ISoftwareService.cs @@ -10,12 +10,14 @@ void DeleteFunction(int funcId); - IEnumerable FindSoftwareForUser(short appId, string username, string password); + short FindAndUpdateSoftware(string name, IEnumerable functions); IEnumerable GetAllSoftwareFunctions(); IEnumerable GetSoftwareFunctions(short appId); + IEnumerable GetSoftwareFunctions(short appId, short userId); + SoftwareOverview GetSoftwareOverview(short appId); IEnumerable GetSoftwareVersions(short appId); diff --git a/LaaProductionWeb/LaaProductionWeb.Services/SoftwareService.cs b/LaaProductionWeb/LaaProductionWeb.Services/SoftwareService.cs index 1022c089..d66d11c9 100644 --- a/LaaProductionWeb/LaaProductionWeb.Services/SoftwareService.cs +++ b/LaaProductionWeb/LaaProductionWeb.Services/SoftwareService.cs @@ -6,7 +6,9 @@ using System; using System.Collections.Generic; + using System.Linq; using System.Security.Cryptography; + using System.Text.RegularExpressions; public class SoftwareService : ISoftwareService { @@ -27,6 +29,15 @@ .AddParameter(nameof(name), name) .ExecuteNonQuery(); + public int ApplicationId(string name) + => this.sqlClient + .CreateCommand($@" + SELECT TOP 1 [AppId] + FROM [VersionSoftwareAccess] + WHERE [SoftwareAccess_Program] = @{nameof(name)}") + .AddParameter(nameof(name), name) + .FirstOrDefault(x => x.GetSmallint()); + public void DeleteFunction(int funcId) { this.sqlClient @@ -44,9 +55,30 @@ .ExecuteNonQuery(); } - public IEnumerable FindSoftwareForUser(short appId, string username, string password) + public short FindAndUpdateSoftware(string name, IEnumerable functions) { - throw new NotImplementedException(); + var appId = this.sqlClient + .CreateCommand($@" + SELECT TOP 1 [AppId] + , MAX([SoftwareAccess_VaildTo]) OVER (PARTITION BY [AppId]) + FROM [VersionSoftwareAccess] + WHERE [SoftwareAccess_Program] = @{nameof(name)} + AND [SoftwareAccess_VaildTo] > GETDATE()") + .AddParameter(nameof(name), name) + .FirstOrDefault(x => x.GetSmallint()); + + if (appId > 0 && functions != null && functions.Any()) + { + foreach (var function in functions) + { + if (Regex.IsMatch(function, "[a-zA-Z_]+")) + { + this.AddFunction(appId, function); + } + } + } + + return appId; } public IEnumerable GetAllSoftwareFunctions() @@ -79,6 +111,19 @@ Function = f.GetString() }); + public IEnumerable GetSoftwareFunctions(short appId, short userId) + => this.sqlClient + .CreateCommand($@" + SELECT [SF].[Function] AS [Function] + FROM [UsersFunctions] AS [UF] + JOIN [SoftwareFunctions] AS [SF] + ON [SF].[Id] = [UF].[SoftwareFunctionId] + WHERE [UF].[UserId] = @{nameof(userId)} + AND [SF].[AppId] = @{nameof(appId)}") + .AddParameter(nameof(appId), appId) + .AddParameter(nameof(userId), userId) + .ExecuteReader(x => x.GetString()); + public SoftwareOverview GetSoftwareOverview(short appId) => this.sqlClient .CreateCommand($@" diff --git a/LaaProductionWeb/LaaProductionWeb/Areas/Account/Controllers/FunctionsController.cs b/LaaProductionWeb/LaaProductionWeb/Areas/Account/Controllers/FunctionsController.cs deleted file mode 100644 index 33a1835e..00000000 --- a/LaaProductionWeb/LaaProductionWeb/Areas/Account/Controllers/FunctionsController.cs +++ /dev/null @@ -1,54 +0,0 @@ -namespace LaaProductionWeb.Areas.Account.Controllers -{ - using LaaProductionWeb.Services.Interfaces; - - using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; - using System.Web.Http; - - [AllowAnonymous] - public class FunctionsController : ApiController - { - private readonly IAccountService accountService; - - public FunctionsController() - => this.accountService = ServiceProvider.Current.GetService(); - - [HttpGet] - public IHttpActionResult Get() - { - if (this.ActionContext.Request.Headers.TryGetValues("Authorization", out IEnumerable values) && values.Any()) - { - var bearer = values - .FirstOrDefault() - .Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) - .LastOrDefault(); - - try - { - var tokens = Encoding.UTF8 - .GetString(Convert.FromBase64String(bearer)) - .Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries); - - if (tokens != null && tokens.Length == 3 && short.TryParse(tokens[0], out short appId)) - { - var username = tokens[1]; - var password = tokens[2]; - - var functions = this.accountService.FindUserFunctions(appId, username, password); - - return this.Ok(functions); - } - } - catch (Exception) - { - // TODO: Log exception. - } - } - - return this.BadRequest("Endpoint expects bearer authorization header with appId:username:password base64 encoded."); - } - } -} \ No newline at end of file diff --git a/LaaProductionWeb/LaaProductionWeb/Areas/Account/Controllers/PWDController.cs b/LaaProductionWeb/LaaProductionWeb/Areas/Account/Controllers/PWDController.cs deleted file mode 100644 index d397bac5..00000000 --- a/LaaProductionWeb/LaaProductionWeb/Areas/Account/Controllers/PWDController.cs +++ /dev/null @@ -1,40 +0,0 @@ -namespace LaaProductionWeb.Areas.Account.Controllers -{ - using LaaProductionWeb.Services.Interfaces; - - using System.Web.Http; - - public class PWDController : ApiController - { - private readonly IAccountService accountService; - - public PWDController() - => this.accountService = ServiceProvider.Current.GetService(); - - [HttpPost] - public IHttpActionResult Post(string username, string password) - { - if (string.IsNullOrWhiteSpace(password)) - { - return this.BadRequest("Invalid password."); - } - else if (this.accountService.ResetPassword(username, password) == 1) - { - return this.Ok(); - } - - return this.BadRequest("Password was not reseted."); - } - - [HttpDelete] - public IHttpActionResult Delete(string username) - { - if (this.accountService.ResetPassword(username) == 1) - { - return this.Ok(); - } - - return this.BadRequest("Password was not reseted."); - } - } -} \ No newline at end of file diff --git a/LaaProductionWeb/LaaProductionWeb/Areas/Software/Controllers/AppIdController.cs b/LaaProductionWeb/LaaProductionWeb/Areas/Software/Controllers/AppIdController.cs new file mode 100644 index 00000000..881a902b --- /dev/null +++ b/LaaProductionWeb/LaaProductionWeb/Areas/Software/Controllers/AppIdController.cs @@ -0,0 +1,26 @@ +namespace LaaProductionWeb.Areas.Software.Controllers +{ + using LaaProductionWeb.Services.Interfaces; + + using System.Collections.Generic; + using System.Web.Http; + + public class AppIdController : ApiController + { + private readonly ISoftwareService softwareService; + + public AppIdController() + => this.softwareService = ServiceProvider.Current.GetService(); + + [HttpPost] + public int Post(AppIdPostInputModel model) + => this.softwareService.FindAndUpdateSoftware(model.Software, model.Functions); + } + + public class AppIdPostInputModel + { + public string Software { get; set; } + + public IEnumerable Functions { get; set; } + } +} diff --git a/LaaProductionWeb/LaaProductionWeb/Areas/Software/Controllers/FunctionsController.cs b/LaaProductionWeb/LaaProductionWeb/Areas/Software/Controllers/FunctionsController.cs new file mode 100644 index 00000000..8492e02b --- /dev/null +++ b/LaaProductionWeb/LaaProductionWeb/Areas/Software/Controllers/FunctionsController.cs @@ -0,0 +1,42 @@ +namespace LaaProductionWeb.Areas.Software.Controllers +{ + using LaaProductionWeb.Services.Interfaces; + + using System.Web.Http; + + public class FunctionsController : ApiController + { + private readonly IAccountService accountService; + private readonly ISoftwareService softwareService; + + public FunctionsController() + { + this.accountService = ServiceProvider.Current.GetService(); + this.softwareService = ServiceProvider.Current.GetService(); + } + + [HttpPost] + public IHttpActionResult Post(FunctionsPostInputModel model) + { + var userId = this.accountService.Login(model.Username, model.Password); + + if (userId <= 0) + { + return this.Unauthorized(); + } + + var functions = this.softwareService.GetSoftwareFunctions(model.AppId, userId); + + return this.Json(functions); + } + } + + public class FunctionsPostInputModel + { + public short AppId { get; set; } + + public string Username { get; set; } + + public string Password { get; set; } + } +} diff --git a/LaaProductionWeb/LaaProductionWeb/Areas/Software/SoftwareAreaRegistration.cs b/LaaProductionWeb/LaaProductionWeb/Areas/Software/SoftwareAreaRegistration.cs new file mode 100644 index 00000000..29775497 --- /dev/null +++ b/LaaProductionWeb/LaaProductionWeb/Areas/Software/SoftwareAreaRegistration.cs @@ -0,0 +1,17 @@ +namespace LaaProductionWeb.Areas.Software +{ + using System.Web.Mvc; + + public class SoftwareAreaRegistration : AreaRegistration + { + public override string AreaName => "Software"; + + public override void RegisterArea(AreaRegistrationContext context) + { + //context.MapRoute( + // "Software_default", + // "api/Software/{controller}/{id}", + // new { action = "Index", id = UrlParameter.Optional }); + } + } +} \ No newline at end of file diff --git a/LaaProductionWeb/LaaProductionWeb/LaaProductionWeb.csproj b/LaaProductionWeb/LaaProductionWeb/LaaProductionWeb.csproj index 4aaea828..fa9eee80 100644 --- a/LaaProductionWeb/LaaProductionWeb/LaaProductionWeb.csproj +++ b/LaaProductionWeb/LaaProductionWeb/LaaProductionWeb.csproj @@ -135,8 +135,6 @@ - - @@ -161,6 +159,9 @@ + + + @@ -194,9 +195,7 @@ - - - +