using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media.Imaging; using Comal.Classes; using InABox.Clients; using InABox.Core; using InABox.DynamicGrid; using InABox.Mail; using InABox.WPF; using PRSDesktop.Panels.Users; using Syncfusion.Windows.Shared; namespace PRSDesktop { internal class UserGrid : DynamicDataGrid { private bool ShowAll; public UserGrid() { Options.AddRange(DynamicGridOption.RecordCount, DynamicGridOption.FilterRows, DynamicGridOption.MultiSelect, DynamicGridOption.SelectColumns); AddButton("Show All", PRSDesktop.Resources.anonymous.AsBitmapImage(Color.White), ToggleDisabledUsers); ActionColumns.Add(new DynamicTickColumn(x => x.Logins, null, PRSDesktop.Resources.tick.AsBitmapImage(), null, null)); HiddenColumns.Add(x => x.AuthenticatorToken); HiddenColumns.Add(x => x.Logins); HiddenColumns.Add(x => x.Password); OnAfterSave += AfterSave; OnCustomiseEditor += UserGrid_OnCustomiseEditor; OnEditorValueChanged += UserGrid_OnEditorValueChanged; if (Security.IsAllowed()) ActionColumns.Add(new DynamicActionColumn(EmailImage, SendEmail)); } private bool SendEmail(CoreRow? row) { if (row is null) return false; User user = row.ToObject(); string ioslink = @"prsmobile://open/"; string androidlink = @"http://www.prsmobile.com/open/"; string toEncrypt = App.DatabaseSettings.URL + "," + App.DatabaseSettings.Port + "," + user.UserID + "," + user.Password + "," + DateTime.Now.AddMinutes(5); string encrypted = Encryption.Encrypt(toEncrypt, "logindetailslink", true); ioslink = ioslink + encrypted; androidlink = androidlink + encrypted; string emailcontent = "Please ensure PRS Mobile is closed, then choose a link below:" + Environment.NewLine + Environment.NewLine + "For Apple devices, click this link: " + ioslink + Environment.NewLine + Environment.NewLine + "For Android devices (Samsung, Google, Xiaomi, Oppo, Vivo, Huawei, Motorola etc), click this link: " + androidlink + Environment.NewLine + Environment.NewLine + "Please restart the app after loading from the link." + Environment.NewLine + Environment.NewLine + "These links will expire after 10 minutes"; Clipboard.SetText(emailcontent); if (string.IsNullOrWhiteSpace(user.EmailAddress)) { MessageBox.Show("User email is blank - please populate email address or send the text copied to your clipboard"); return false; } var currentuser = new Client() .Query(new Filter(x => x.ID).IsEqualTo(ClientFactory.UserGuid)) .Rows.FirstOrDefault()?.ToObject(); if (currentuser is null) return false; var result = MessageBox.Show("Send email with user credentials to " + user.EmailAddress + " ?", "Alert", MessageBoxButton.YesNo); switch (result) { case MessageBoxResult.Yes: break; case MessageBoxResult.No: return false; default: return false; } bool currentUserEmailDetailsOK = !string.IsNullOrWhiteSpace(currentuser.EmailHost) && currentuser.EmailPort != 0 && !string.IsNullOrWhiteSpace(currentuser.EmailAddress) && !string.IsNullOrWhiteSpace(currentuser.EmailPassword); var mailer = new ExchangeMailer { MailboxHost = currentuser.EmailHost, MailboxPort = currentuser.EmailPort, MailboxUserName = currentuser.EmailAddress, MailboxPassword = currentuser.EmailPassword }; if (mailer.Connect()) { var msg = mailer.CreateMessage(); msg.To = new string[] { user.EmailAddress }; msg.Subject = "Link to PRS Mobile"; msg.Body = emailcontent; var bOK = mailer.SendMessage(msg); if (!currentUserEmailDetailsOK) MessageBox.Show("Unable to send email - Email host, port, address or password missing for current user. Please update. The link has been copied to your clipboard for sending"); else if (bOK) MessageBox.Show("Link has been sent to email service. The link has been copied to your clipboard in case it is not received by the user"); } return true; } private BitmapImage? EmailImage(CoreRow? arg) { return PRSDesktop.Resources.email.AsBitmapImage(); } private Dictionary UserGrid_OnEditorValueChanged(object sender, string name, object value) { var editorForm = (DynamicEditorForm)sender; if (name == nameof(User.TwoFactorAuthenticationType)) { var addressEditor = editorForm.FindEditor(nameof(User.Recipient2FA)); var editor = editorForm.FindEditor(name) as LookupEditorControl; var choice = (TwoFactorAuthenticationType)value; var isGoogle = choice == TwoFactorAuthenticationType.GoogleAuthenticator; addressEditor.SetEnabled(!isGoogle); (editor.EditorDefinition as EnumLookupEditor)!.Buttons[0].SetEnabled(isGoogle); } return new(); } private void UserGrid_OnCustomiseEditor(IDynamicEditorForm sender, User[]? items, DynamicGridColumn column, BaseEditor editor) { var user = items?.FirstOrDefault(); if (user is null) return; if (column.ColumnName == nameof(User.TwoFactorAuthenticationType) && editor is EnumLookupEditor enumEditor) { var qrCodeButton = new EditorButton(user, "View QR Code", 100, ViewQRCode_Click, false); qrCodeButton.SetEnabled(user.TwoFactorAuthenticationType == TwoFactorAuthenticationType.GoogleAuthenticator); enumEditor.Buttons = new[] { qrCodeButton }; } else if (column.ColumnName == nameof(User.Recipient2FA)) { editor.Editable = user.TwoFactorAuthenticationType == TwoFactorAuthenticationType.GoogleAuthenticator ? Editable.Disabled : Editable.Enabled; } } private void ViewQRCode_Click(object editor, object? item) { if (item is User user && user.TwoFactorAuthenticationType == TwoFactorAuthenticationType.GoogleAuthenticator) { var qrWindow = new QR2FAWindow(user); qrWindow.ShowDialog(); } } private bool ToggleDisabledUsers(Button btn, CoreRow[] rows) { ShowAll = !ShowAll; UpdateButton(btn, PRSDesktop.Resources.anonymous.AsBitmapImage(Color.White), ShowAll ? "Hide Finished" : "Show All"); return true; } protected override void Reload(Filters criteria, Columns columns, ref SortOrder sort, Action action) { if (!ShowAll) criteria.Add(new Filter(x => x.Disabled).IsEqualTo(false)); sort = new SortOrder(x => x.UserID); base.Reload(criteria, columns, ref sort, action); } protected override void SaveItem(User item) { base.SaveItem(item); if (item.ID == ClientFactory.UserGuid) Security.Reset(); } private void AfterSave(DynamicEditorForm editor, User[] items) { var ids = items.Select(x => x.ID).ToArray(); var linkedUsers = new Client().Query( new Filter(x => x.UserID).InList(ids), new Columns(x => x.UserID)).Rows.Select(x => (Guid)x["UserID"]).ToArray(); var newEmployees = new List(); foreach (var item in items) { if (!linkedUsers.Contains(item.ID)) { var result = MessageBox.Show($"{item.UserID} is not associated with an employee. Do you wish to create one?", "Create new Employee?", MessageBoxButton.YesNo); if (result == MessageBoxResult.Yes) { var newEmployee = new Employee() { Name = item.Description }; newEmployee.UserLink.ID = item.ID; newEmployee.UserLink.Synchronise(item); var grid = DynamicGridUtils.CreateDynamicGrid(typeof(DynamicDataGrid<>), typeof(Employee)); grid.EditItems(new object[] { newEmployee }); } } } } } }