diff --git a/TBF/Properties/AssemblyInfo.cs b/TBF/Properties/AssemblyInfo.cs index e69989dc3..bb0e389a6 100644 --- a/TBF/Properties/AssemblyInfo.cs +++ b/TBF/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("2.30.1983.0")] -[assembly: AssemblyFileVersion("2.30.1983.0")] +[assembly: AssemblyVersion("2.30.1984.0")] +[assembly: AssemblyFileVersion("2.30.1984.0")] diff --git a/TBF/Resources/Strings.Designer.cs b/TBF/Resources/Strings.Designer.cs index 776841344..057c2a7e7 100644 --- a/TBF/Resources/Strings.Designer.cs +++ b/TBF/Resources/Strings.Designer.cs @@ -673,7 +673,7 @@ namespace TBF.Resources { } /// - /// Looks up a localized string similar to Calibration Specialist. + /// Looks up a localized string similar to Legalizator. /// internal static string Calibration_Specialist { get { diff --git a/TBF/Resources/Strings.pl.resx b/TBF/Resources/Strings.pl.resx index b47a66fa6..6076c6f70 100644 --- a/TBF/Resources/Strings.pl.resx +++ b/TBF/Resources/Strings.pl.resx @@ -199,7 +199,8 @@ Parametry stanowiska - Specjalistyczna kalibracja + Legalizator + Specjalistyczna kalibracja Błąd kamery diff --git a/TBF/Resources/Strings.resx b/TBF/Resources/Strings.resx index d65f344d7..907be4fd9 100644 --- a/TBF/Resources/Strings.resx +++ b/TBF/Resources/Strings.resx @@ -424,7 +424,7 @@ Administrator - Calibration Specialist + Legalizator Head of Lab diff --git a/TBF/Rig/Sequences/MainSeq.cs b/TBF/Rig/Sequences/MainSeq.cs index de0e557d4..5d9b49cbb 100644 --- a/TBF/Rig/Sequences/MainSeq.cs +++ b/TBF/Rig/Sequences/MainSeq.cs @@ -1,5 +1,5 @@ /// -/// Copyright (c) 2013-2021 Sensus Slovensko a.s. +/// Copyright (c) 2013-2022 Sensus Slovensko a.s. /// using System; using System.Collections.Generic; @@ -23,6 +23,8 @@ namespace TBF.Rig.Sequences public override string ToString() { return "Sequences.MainSeq"; } + bool approvedByLegalizator = false; + DateTime lastApprovalByLegalizatorTime; int simultWithPurgingCount; Generic.IComponent simultWithPurging; @@ -215,6 +217,7 @@ namespace TBF.Rig.Sequences do { + bool approval = true; do { selection = MakeSelection(MKSelContext.ProcedureNotSelected); @@ -223,8 +226,13 @@ namespace TBF.Rig.Sequences Shutdown(); return; } + +#if KEMPNO_50 || KRAKOW_50 || TORUN_50 || WARSAW_50 || WARSAW_END + approval = (selection == Selection.Cycle || selection == Selection.Test || selection == Selection.Q1 || + selection == Selection.Q2 || selection == Selection.Q3) && IsApprovedByLegalizator(); +#endif } - while (selection == Selection.Shutdown); + while (selection == Selection.Shutdown || !approval); selectedTestName = (selection == Selection.Q1) ? "Q1" : ((selection == Selection.Q2) ? "Q2" @@ -1466,6 +1474,25 @@ namespace TBF.Rig.Sequences } + bool IsApprovedByLegalizator() + { + if (approvedByLegalizator && DateTime.Now < lastApprovalByLegalizatorTime.Date.AddDays(1)) + { + return true; + } + + var loginDlg = new Users.Forms.PlainLoginDlg(new GID[] { GID.CalibrationSpecialists }, "Approval by legalizator"); + if (loginDlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) + { + approvedByLegalizator = true; + lastApprovalByLegalizatorTime = DateTime.Now; + return true; + } + + return false; + } + + /// /// MakeSelection() call context /// diff --git a/Users/Forms/PlainLoginDlg.Designer.cs b/Users/Forms/PlainLoginDlg.Designer.cs new file mode 100644 index 000000000..3aae337fa --- /dev/null +++ b/Users/Forms/PlainLoginDlg.Designer.cs @@ -0,0 +1,112 @@ +/// +/// Copyright (c) 2022 Sensus Slovensko a.s. +/// +namespace Users.Forms +{ + partial class PlainLoginDlg + { + /// + /// 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 Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PlainLoginDlg)); + this.userNameLabel = new System.Windows.Forms.Label(); + this.passwordLabel = new System.Windows.Forms.Label(); + this.passwordTextBox = new System.Windows.Forms.TextBox(); + this.cancelButton = new System.Windows.Forms.Button(); + this.okButton = new System.Windows.Forms.Button(); + this.userNameTextBox = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // aliasLabel + // + resources.ApplyResources(this.userNameLabel, "aliasLabel"); + this.userNameLabel.Name = "aliasLabel"; + // + // passwordLabel + // + resources.ApplyResources(this.passwordLabel, "passwordLabel"); + this.passwordLabel.Name = "passwordLabel"; + // + // passwordTextBox + // + resources.ApplyResources(this.passwordTextBox, "passwordTextBox"); + this.passwordTextBox.Name = "passwordTextBox"; + this.passwordTextBox.UseSystemPasswordChar = true; + this.passwordTextBox.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.passwordTextBox_KeyPress); + // + // cancelButton + // + resources.ApplyResources(this.cancelButton, "cancelButton"); + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.Name = "cancelButton"; + this.cancelButton.UseVisualStyleBackColor = true; + this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click); + // + // okButton + // + resources.ApplyResources(this.okButton, "okButton"); + this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK; + this.okButton.Name = "okButton"; + this.okButton.UseVisualStyleBackColor = true; + this.okButton.Click += new System.EventHandler(this.okButton_Click); + // + // userNameTextBox + // + resources.ApplyResources(this.userNameTextBox, "userNameTextBox"); + this.userNameTextBox.Name = "userNameTextBox"; + this.userNameTextBox.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.userNameTextBox_KeyPress); + // + // PlainLoginDlg + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancelButton; + this.Controls.Add(this.userNameTextBox); + this.Controls.Add(this.okButton); + this.Controls.Add(this.cancelButton); + this.Controls.Add(this.passwordTextBox); + this.Controls.Add(this.passwordLabel); + this.Controls.Add(this.userNameLabel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Name = "PlainLoginDlg"; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.PlainLoginDlg_FormClosing); + this.Load += new System.EventHandler(this.LoginDlg_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label userNameLabel; + private System.Windows.Forms.Label passwordLabel; + private System.Windows.Forms.TextBox userNameTextBox; + private System.Windows.Forms.TextBox passwordTextBox; + private System.Windows.Forms.Button cancelButton; + private System.Windows.Forms.Button okButton; + } +} \ No newline at end of file diff --git a/Users/Forms/PlainLoginDlg.cs b/Users/Forms/PlainLoginDlg.cs new file mode 100644 index 000000000..ebd0f75c0 --- /dev/null +++ b/Users/Forms/PlainLoginDlg.cs @@ -0,0 +1,311 @@ +/// +/// Copyright (c) 2022 Sensus Slovensko a.s. +/// +using System; +using System.Windows.Forms; +using log4net; +using Common; +using GemCard; +using Users.Entities; +using Users.Resources; +using System.Drawing; + +namespace Users.Forms +{ + /// + /// Provides login dialog as well as user authorization using TBF.User.Authorize(...) + /// (i.e. when DialogResult is OK, user was authorized). + /// + public partial class PlainLoginDlg : Form + { + private static readonly ILog log = LogManager.GetLogger(typeof(PlainLoginDlg)); + + /// Public readonly + public string UserName { get { return user; } } + + /// Private fields + string user; + string password; + GID[] requiredGroupMembership; + bool noDatabase; + Color oriBackColor; + + /// Smart card support, card S/N is used as user.Tag + CardNative card; + string smartCardReader; + + public LoginMethod Method; + public string VersionString; + + /// + /// Constructor. + /// + public PlainLoginDlg() + { + InitializeComponent(); + + oriBackColor = BackColor; + } + + /// + /// Constructor with a predefined user. + /// + public PlainLoginDlg(string predefinedUser, string prompt = null) + : this() + { + user = predefinedUser; + userNameTextBox.Text = predefinedUser; + if (prompt != null) Text = prompt; + } + + /// + /// Constructor with 'no Database' flag. + /// + public PlainLoginDlg(bool noDatabase, string prompt = null) + : this() + { + this.noDatabase = noDatabase; + if (prompt != null) Text = prompt; + } + + /// + /// Constructor when a specific group membership is required. + /// + public PlainLoginDlg(GID[] requiredGroupMembership, string prompt = null) + : this() + { + this.requiredGroupMembership = requiredGroupMembership; + if (prompt != null) Text = prompt; + } + + /// + /// Constructor with a predefined user when a specific group membership is required. + /// + public PlainLoginDlg(string predefinedUser, GID[] requiredGroupMembership, string prompt = null) + : this() + { + user = predefinedUser; + userNameTextBox.Text = predefinedUser; + this.requiredGroupMembership = requiredGroupMembership; + + Text = (prompt != null) ? prompt : Strings.User_Login + (string.IsNullOrEmpty(VersionString) ? "" : (" " + VersionString)); + } + + private void LoginDlg_Load(object sender, EventArgs e) + { + Localize(); + + if (user == null) + userNameTextBox.Select(); + else + passwordTextBox.Select(); + + /// + /// Smart card reader detection + /// + smartCardReader = null; /// null = No smart card reader detected + +#if TURA_IPERL || TURA_IPERL_NEW || TURA_SPECIAL + try + { + card = new CardNative(); + + /// Find NFC smart card reader + string[] cardReaders = card.ListReaders(); + if (cardReaders != null) + { + foreach (var crd in cardReaders) + { + log.WarnFormat("SMART card reader found: {0}", crd); + } + + foreach (var crd in cardReaders) + { + if (crd.Contains("NFC")) + { + log.ErrorFormat("SMART card reader selected: {0}", crd); + smartCardReader = crd; /// NFC smart card reader detected + break; + } + } + } + + if (!string.IsNullOrEmpty(smartCardReader)) + { + /// Reader found, initialize NFC smart card reader + + card.OnCardInserted += delegate(object sndr, CardInsertedEventArgs args) + { + if (InvokeRequired) { Invoke(new EventHandler(OnCardInserted), sndr, args); } + else OnCardInserted(sndr, args); + }; + + card.OnCardRemoved += delegate(object sndr, CardRemovedEventArgs args) + { + if (InvokeRequired) { Invoke(new EventHandler(OnCardRemoved), sndr, args); } + else OnCardRemoved(sndr, args); + }; + + card.StartCardEvents(smartCardReader); + + Text += " (NFC)"; + } + } + catch (Exception) + { + smartCardReader = null; + } +#endif + } + + void Localize() + { + userNameLabel.Text = Strings.User_name; + passwordLabel.Text = Strings.Password; + okButton.Text = Strings.OkBtnText; + cancelButton.Text = Strings.CancelBtnText; + } + + /// + /// Try to authorize the user when OK clicked. + /// + private void okButton_Click(object sender, EventArgs e) + { + user = userNameTextBox.Text; + password = passwordTextBox.Text; + + bool authorized = Entities.User.IsPowerUser(user, password); + + if (!authorized && !noDatabase) + { + DBSettings[] dbs = new DBSettings[] { CurrentUser.RemoteUsersDB, CurrentUser.LocalUsersDB }; + + foreach (var db in dbs) + { + try + { + var usr1 = Users.Entities.User.LoadUserByName(user, db); + + if (usr1.IsMemberOf(requiredGroupMembership) && usr1.IsCorrectPassword(password)) + { + authorized = true; + break; + } + } + catch (Exception) { } + } + } + + if (authorized) + { + DialogResult = DialogResult.OK; + Close(); + return; + } + + MessageBox.Show(Strings.Invalid_username_or_password, Strings.Error, MessageBoxButtons.OK); + DialogResult = DialogResult.None; + return; + } + + /// + /// Cancel clicked, do not try to authorize. + /// + private void cancelButton_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.Cancel; + Close(); + return; + } + + private void userNameTextBox_KeyPress(object sender, KeyPressEventArgs e) + { + if (Convert.ToInt32(e.KeyChar) == 13) + { + passwordTextBox.Focus(); + } + } + + private void passwordTextBox_KeyPress(object sender, KeyPressEventArgs e) + { + if (Convert.ToInt32(e.KeyChar) == 13) + { + okButton_Click(sender, e); + } + } + + + void OnCardInserted(object sender, CardInsertedEventArgs args) + { + string tag = string.Empty; + + try + { + BackColor = Color.Green; + card.Connect(smartCardReader, SHARE.Shared, PROTOCOL.T0orT1); + + /// Read the serial number of the card + APDUResponse response = card.Transmit(new APDUCommand(0xFF, 0xCA, 0x00, 0x00, null, 7)); + tag = response.ToString(); + + card.Disconnect(DISCONNECT.Leave); + } + catch + { + tag = string.Empty; + } + + DBSettings[] dbs = new DBSettings[] { CurrentUser.RemoteUsersDB, CurrentUser.LocalUsersDB }; + bool authorized = false; + AuthorizedAs authorizedAs = AuthorizedAs.RemoteUser; + /// + foreach (var db in dbs) + { + try + { + Users.Entities.User loadedUser = Users.Entities.User.LoadUserByTag(tag, db); + if (loadedUser != null) + { + authorized = (tag == loadedUser.Tag && loadedUser.IsMemberOf(requiredGroupMembership)); + + if (authorized) + { + user = loadedUser.UserName; + break; + } + } + } + catch (Exception) { } + + authorizedAs = AuthorizedAs.LocalUser; + } + + if (authorized) + { + Users.CurrentUser.AuthorizedAs = authorizedAs; + DialogResult = DialogResult.OK; + Close(); + return; + } + + MessageBox.Show(Strings.Invalid_username_or_password, Strings.Error, MessageBoxButtons.OK); + DialogResult = DialogResult.None; + return; + } + + + void OnCardRemoved(object sender, CardRemovedEventArgs args) + { + BackColor = oriBackColor; + } + + private void PlainLoginDlg_FormClosing(object sender, FormClosingEventArgs e) + { + if (!string.IsNullOrEmpty(smartCardReader)) + { + try { card.StopCardEvents(); } + catch { } + } + } + } +} diff --git a/Users/Forms/PlainLoginDlg.resx b/Users/Forms/PlainLoginDlg.resx new file mode 100644 index 000000000..955e22ace --- /dev/null +++ b/Users/Forms/PlainLoginDlg.resx @@ -0,0 +1,300 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + True + + + + 11, 24 + + + 58, 13 + + + 0 + + + User name + + + aliasLabel + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 5 + + + True + + + 11, 51 + + + 53, 13 + + + 1 + + + Password + + + passwordLabel + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + + Top, Right + + + 150, 48 + + + 168, 20 + + + 3 + + + passwordTextBox + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + Top, Right + + + 336, 48 + + + 105, 28 + + + 5 + + + Cancel + + + cancelButton + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + Top, Right + + + 336, 14 + + + 105, 28 + + + 4 + + + OK + + + okButton + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + Top, Right + + + 150, 22 + + + 168, 20 + + + 2 + + + userNameTextBox + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 6, 13 + + + 456, 88 + + + CenterScreen + + + User login + + + LoginDlg + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Users/Resources/Strings.Designer.cs b/Users/Resources/Strings.Designer.cs index b00b80e99..9cd21a263 100644 --- a/Users/Resources/Strings.Designer.cs +++ b/Users/Resources/Strings.Designer.cs @@ -19,7 +19,7 @@ namespace Users.Resources { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Strings { @@ -88,7 +88,7 @@ namespace Users.Resources { } /// - /// Looks up a localized string similar to calibration specialist. + /// Looks up a localized string similar to legalizator. /// internal static string calibration_specialist { get { diff --git a/Users/Resources/Strings.pl.resx b/Users/Resources/Strings.pl.resx index 5ea18b88d..14ca0a44d 100644 --- a/Users/Resources/Strings.pl.resx +++ b/Users/Resources/Strings.pl.resx @@ -187,7 +187,8 @@ Administrator - Specjalista ds. kalibracji + Legalizator + Specjalista ds. kalibracji Kierownik Laboratorium diff --git a/Users/Resources/Strings.resx b/Users/Resources/Strings.resx index 400433a57..f56ef5617 100644 --- a/Users/Resources/Strings.resx +++ b/Users/Resources/Strings.resx @@ -208,7 +208,7 @@ administrator - calibration specialist + legalizator head of lab. diff --git a/Users/Users.csproj b/Users/Users.csproj index 8d8b3578f..dcdeab2ea 100644 --- a/Users/Users.csproj +++ b/Users/Users.csproj @@ -76,6 +76,12 @@ EditSelectedUser.cs + + Form + + + PlainLoginDlg.cs + Form @@ -114,6 +120,9 @@ PasswordChangeDlg.cs + + PlainLoginDlg.cs + UserManagementDlg.cs