diff --git a/PettingZoo.Core/Settings/IConnectionSettingsRepository.cs b/PettingZoo.Core/Settings/IConnectionSettingsRepository.cs index 18dd443..a5350c7 100644 --- a/PettingZoo.Core/Settings/IConnectionSettingsRepository.cs +++ b/PettingZoo.Core/Settings/IConnectionSettingsRepository.cs @@ -6,12 +6,12 @@ namespace PettingZoo.Core.Settings { public interface IConnectionSettingsRepository { - Task GetLastUsed(); - Task StoreLastUsed(ConnectionSettings connectionSettings); + Task GetLastUsed(); + Task StoreLastUsed(bool storePassword, ConnectionSettings connectionSettings); Task> GetStored(); - Task Add(string displayName, ConnectionSettings connectionSettings); - Task Update(Guid id, string displayName, ConnectionSettings connectionSettings); + Task Add(string displayName, bool storePassword, ConnectionSettings connectionSettings); + Task Update(Guid id, string displayName, bool storePassword, ConnectionSettings connectionSettings); Task Delete(Guid id); } @@ -22,7 +22,7 @@ namespace PettingZoo.Core.Settings public string VirtualHost { get; } public int Port { get; } public string Username { get; } - public string? Password { get; } + public string Password { get; } public bool Subscribe { get; } public string Exchange { get; } @@ -32,7 +32,7 @@ namespace PettingZoo.Core.Settings public static readonly ConnectionSettings Default = new("localhost", "/", 5672, "guest", "guest", false, "", "#"); - public ConnectionSettings(string host, string virtualHost, int port, string username, string? password, + public ConnectionSettings(string host, string virtualHost, int port, string username, string password, bool subscribe, string exchange, string routingKey) { Host = host; @@ -65,22 +65,26 @@ namespace PettingZoo.Core.Settings { public Guid Id { get; } public string DisplayName { get; } + public bool StorePassword { get; } - public StoredConnectionSettings(Guid id, string displayName, string host, string virtualHost, int port, string username, - string? password, bool subscribe, string exchange, string routingKey) + + public StoredConnectionSettings(Guid id, string displayName, bool storePassword, string host, string virtualHost, int port, string username, + string password, bool subscribe, string exchange, string routingKey) : base(host, virtualHost, port, username, password, subscribe, exchange, routingKey) { Id = id; DisplayName = displayName; + StorePassword = storePassword; } - public StoredConnectionSettings(Guid id, string displayName, ConnectionSettings connectionSettings) - : base(connectionSettings.Host, connectionSettings.VirtualHost, connectionSettings.Port, connectionSettings.Username, connectionSettings.Password, - connectionSettings.Subscribe, connectionSettings.Exchange, connectionSettings.RoutingKey) + public StoredConnectionSettings(Guid id, string displayName, bool storePassword, ConnectionSettings connectionSettings) + : base(connectionSettings.Host, connectionSettings.VirtualHost, connectionSettings.Port, connectionSettings.Username, + connectionSettings.Password, connectionSettings.Subscribe, connectionSettings.Exchange, connectionSettings.RoutingKey) { Id = id; DisplayName = displayName; + StorePassword = storePassword; } } } \ No newline at end of file diff --git a/PettingZoo.Settings.LiteDB/BaseLiteDBRepository.cs b/PettingZoo.Settings.LiteDB/BaseLiteDBRepository.cs index a24bc13..155cd50 100644 --- a/PettingZoo.Settings.LiteDB/BaseLiteDBRepository.cs +++ b/PettingZoo.Settings.LiteDB/BaseLiteDBRepository.cs @@ -24,7 +24,10 @@ namespace PettingZoo.Settings.LiteDB protected ILiteDatabaseAsync GetDatabase() { - return new LiteDatabaseAsync(databaseFilename); + return new LiteDatabaseAsync(databaseFilename, new BsonMapper + { + EmptyStringToNull = false + }); } } } diff --git a/PettingZoo.Settings.LiteDB/LiteDBConnectionSettingsRepository.cs b/PettingZoo.Settings.LiteDB/LiteDBConnectionSettingsRepository.cs index dde8c63..757ea86 100644 --- a/PettingZoo.Settings.LiteDB/LiteDBConnectionSettingsRepository.cs +++ b/PettingZoo.Settings.LiteDB/LiteDBConnectionSettingsRepository.cs @@ -15,33 +15,36 @@ namespace PettingZoo.Settings.LiteDB } - public async Task GetLastUsed() + public async Task GetLastUsed() { using var database = GetDatabase(); var collection = database.GetCollection(CollectionLastUsed); var lastUsed = await collection.FindOneAsync(r => true); if (lastUsed == null) - return ConnectionSettings.Default; + return new StoredConnectionSettings(Guid.Empty, "", false, ConnectionSettings.Default); - return new ConnectionSettings( + return new StoredConnectionSettings( + Guid.Empty, + "", + lastUsed.Password != null, lastUsed.Host, lastUsed.VirtualHost, lastUsed.Port, lastUsed.Username, - lastUsed.Password, + lastUsed.Password ?? "", lastUsed.Subscribe, lastUsed.Exchange, lastUsed.RoutingKey); } - public async Task StoreLastUsed(ConnectionSettings connectionSettings) + public async Task StoreLastUsed(bool storePassword, ConnectionSettings connectionSettings) { using var database = GetDatabase(); var collection = database.GetCollection(CollectionLastUsed); - await collection.UpsertAsync(ConnectionSettingsRecord.FromConnectionSettings(LastUsedId, connectionSettings, "")); + await collection.UpsertAsync(ConnectionSettingsRecord.FromConnectionSettings(LastUsedId, connectionSettings, "", storePassword)); } @@ -51,30 +54,30 @@ namespace PettingZoo.Settings.LiteDB var collection = database.GetCollection(CollectionStored); return (await collection.FindAllAsync()) - .Select(r => new StoredConnectionSettings(r.Id, r.DisplayName, r.Host, r.VirtualHost, r.Port, r.Username, r.Password, r.Subscribe, r.Exchange, r.RoutingKey)) + .Select(r => new StoredConnectionSettings(r.Id, r.DisplayName, r.Password != null, r.Host, r.VirtualHost, r.Port, r.Username, r.Password ?? "", r.Subscribe, r.Exchange, r.RoutingKey)) .ToArray(); } - public async Task Add(string displayName, ConnectionSettings connectionSettings) + public async Task Add(string displayName, bool storePassword, ConnectionSettings connectionSettings) { using var database = GetDatabase(); var collection = database.GetCollection(CollectionStored); var id = Guid.NewGuid(); - await collection.InsertAsync(ConnectionSettingsRecord.FromConnectionSettings(id, connectionSettings, displayName)); + await collection.InsertAsync(ConnectionSettingsRecord.FromConnectionSettings(id, connectionSettings, displayName, storePassword)); - return new StoredConnectionSettings(id, displayName, connectionSettings); + return new StoredConnectionSettings(id, displayName, storePassword, connectionSettings); } - public async Task Update(Guid id, string displayName, ConnectionSettings connectionSettings) + public async Task Update(Guid id, string displayName, bool storePassword, ConnectionSettings connectionSettings) { using var database = GetDatabase(); var collection = database.GetCollection(CollectionStored); - await collection.UpdateAsync(ConnectionSettingsRecord.FromConnectionSettings(id, connectionSettings, displayName)); - return new StoredConnectionSettings(id, displayName, connectionSettings); + await collection.UpdateAsync(ConnectionSettingsRecord.FromConnectionSettings(id, connectionSettings, displayName, storePassword)); + return new StoredConnectionSettings(id, displayName, storePassword, connectionSettings); } @@ -105,7 +108,7 @@ namespace PettingZoo.Settings.LiteDB public string RoutingKey { get; set; } = null!; - public static ConnectionSettingsRecord FromConnectionSettings(Guid id, ConnectionSettings connectionSettings, string displayName) + public static ConnectionSettingsRecord FromConnectionSettings(Guid id, ConnectionSettings connectionSettings, string displayName, bool storePassword) { return new ConnectionSettingsRecord { @@ -116,7 +119,7 @@ namespace PettingZoo.Settings.LiteDB VirtualHost = connectionSettings.VirtualHost, Port = connectionSettings.Port, Username = connectionSettings.Username, - Password = connectionSettings.Password, + Password = storePassword ? connectionSettings.Password : null, Subscribe = connectionSettings.Subscribe, Exchange = connectionSettings.Exchange, diff --git a/PettingZoo/UI/BaseViewModel.cs b/PettingZoo/UI/BaseViewModel.cs index b6f6af2..af9108d 100644 --- a/PettingZoo/UI/BaseViewModel.cs +++ b/PettingZoo/UI/BaseViewModel.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; @@ -6,6 +7,8 @@ namespace PettingZoo.UI { public class BaseViewModel : INotifyPropertyChanged { + private int commandsChangedDisabled; + public event PropertyChangedEventHandler? PropertyChanged; protected virtual void RaisePropertyChanged([CallerMemberName] string? propertyName = null) @@ -30,6 +33,7 @@ namespace PettingZoo.UI RaisePropertyChanged(otherProperty); } + // ReSharper disable once InvertIf if (delegateCommandsChanged != null) { foreach (var delegateCommand in delegateCommandsChanged) @@ -38,5 +42,24 @@ namespace PettingZoo.UI return true; } + + + protected void DisableCommandsChanged(Action updateFields, params DelegateCommand[] delegateCommandsChangedAfter) + { + commandsChangedDisabled++; + try + { + updateFields(); + } + finally + { + commandsChangedDisabled--; + if (commandsChangedDisabled == 0) + { + foreach (var delegateCommand in delegateCommandsChangedAfter) + delegateCommand.RaiseCanExecuteChanged(); + } + } + } } } \ No newline at end of file diff --git a/PettingZoo/UI/Connection/ConnectionViewModel.cs b/PettingZoo/UI/Connection/ConnectionViewModel.cs index 37afe6e..7d1cf4d 100644 --- a/PettingZoo/UI/Connection/ConnectionViewModel.cs +++ b/PettingZoo/UI/Connection/ConnectionViewModel.cs @@ -5,14 +5,12 @@ using System.Windows; using System.Windows.Input; using PettingZoo.Core.Settings; -// TODO "save password" checkbox - namespace PettingZoo.UI.Connection { public class ConnectionViewModel : BaseViewModel { private readonly IConnectionSettingsRepository connectionSettingsRepository; - private readonly ConnectionSettings defaultSettings; + private readonly StoredConnectionSettings defaultSettings; private string host = null!; private string virtualHost = null!; private int port; @@ -23,6 +21,8 @@ namespace PettingZoo.UI.Connection private string exchange = null!; private string routingKey = null!; + private bool storePassword; + private StoredConnectionSettings? selectedStoredConnection; private readonly DelegateCommand okCommand; @@ -60,7 +60,7 @@ namespace PettingZoo.UI.Connection public string Password { get => password; - set => SetField(ref password, value); + set => SetField(ref password, value, delegateCommandsChanged: connectionChangedCommands); } @@ -91,6 +91,13 @@ namespace PettingZoo.UI.Connection } + public bool StorePassword + { + get => storePassword; + set => SetField(ref storePassword, value, delegateCommandsChanged: connectionChangedCommands); + } + + public ObservableCollection StoredConnections { get; } = new(); public StoredConnectionSettings? SelectedStoredConnection @@ -104,15 +111,21 @@ namespace PettingZoo.UI.Connection if (!SetField(ref selectedStoredConnection, value, delegateCommandsChanged: new [] { deleteCommand })) return; - Host = value.Host; - VirtualHost = value.VirtualHost; - Port = value.Port; - Username = value.Username; - Password = value.Password ?? ""; + DisableCommandsChanged( + () => + { + Host = value.Host; + VirtualHost = value.VirtualHost; + Port = value.Port; + Username = value.Username; + Password = value.Password; + StorePassword = value.StorePassword; - Exchange = value.Exchange; - RoutingKey = value.RoutingKey; - Subscribe = value.Subscribe; + Exchange = value.Exchange; + RoutingKey = value.RoutingKey; + Subscribe = value.Subscribe; + }, + connectionChangedCommands); } } @@ -125,7 +138,7 @@ namespace PettingZoo.UI.Connection public event EventHandler? OkClick; - public ConnectionViewModel(IConnectionSettingsRepository connectionSettingsRepository, ConnectionSettings defaultSettings) + public ConnectionViewModel(IConnectionSettingsRepository connectionSettingsRepository, StoredConnectionSettings defaultSettings) { this.connectionSettingsRepository = connectionSettingsRepository; this.defaultSettings = defaultSettings; @@ -144,6 +157,7 @@ namespace PettingZoo.UI.Connection var defaultConnection = new StoredConnectionSettings( Guid.Empty, ConnectionWindowStrings.LastUsedDisplayName, + defaultSettings.StorePassword, defaultSettings.Host, defaultSettings.VirtualHost, defaultSettings.Port, @@ -157,7 +171,7 @@ namespace PettingZoo.UI.Connection foreach (var storedConnectionSettings in await connectionSettingsRepository.GetStored()) { - if (!isStored && storedConnectionSettings.SameParameters(defaultConnection)) + if (!isStored && storedConnectionSettings.SameParameters(defaultConnection, false)) { SelectedStoredConnection = storedConnectionSettings; isStored = true; @@ -169,7 +183,7 @@ namespace PettingZoo.UI.Connection if (isStored) { // The last used parameters match a stored connection, insert the "New connection" item with default parameters - StoredConnections.Insert(0, new StoredConnectionSettings(Guid.Empty, ConnectionWindowStrings.LastUsedDisplayName, ConnectionSettings.Default)); + StoredConnections.Insert(0, new StoredConnectionSettings(Guid.Empty, ConnectionWindowStrings.LastUsedDisplayName, true, ConnectionSettings.Default)); } else { @@ -225,7 +239,7 @@ namespace PettingZoo.UI.Connection var selectedIndex = StoredConnections.IndexOf(SelectedStoredConnection); - var updatedStoredConnection = await connectionSettingsRepository.Update(SelectedStoredConnection.Id, SelectedStoredConnection.DisplayName, ToModel()); + var updatedStoredConnection = await connectionSettingsRepository.Update(SelectedStoredConnection.Id, SelectedStoredConnection.DisplayName, StorePassword, ToModel()); StoredConnections[selectedIndex] = updatedStoredConnection; @@ -238,7 +252,10 @@ namespace PettingZoo.UI.Connection return SelectedStoredConnection != null && SelectedStoredConnection.Id != Guid.Empty && ValidConnection(false) && - !ToModel().SameParameters(SelectedStoredConnection, false); + ( + !ToModel().SameParameters(SelectedStoredConnection, StorePassword) || + SelectedStoredConnection.StorePassword != StorePassword + ); } @@ -250,7 +267,7 @@ namespace PettingZoo.UI.Connection if (!ConnectionDisplayNameDialog.Execute(ref displayName)) return; - var storedConnectionSettings = await connectionSettingsRepository.Add(displayName, ToModel()); + var storedConnectionSettings = await connectionSettingsRepository.Add(displayName, StorePassword, ToModel()); StoredConnections.Add(storedConnectionSettings); SelectedStoredConnection = storedConnectionSettings; @@ -298,7 +315,7 @@ namespace PettingZoo.UI.Connection { public DesignTimeConnectionViewModel() : base(null!, null!) { - StoredConnections.Add(new StoredConnectionSettings(Guid.Empty, "Dummy", ConnectionSettings.Default)); + StoredConnections.Add(new StoredConnectionSettings(Guid.Empty, "Dummy", true, ConnectionSettings.Default)); } } } diff --git a/PettingZoo/UI/Connection/ConnectionWindow.xaml b/PettingZoo/UI/Connection/ConnectionWindow.xaml index 66e4dba..e6a6ee3 100644 --- a/PettingZoo/UI/Connection/ConnectionWindow.xaml +++ b/PettingZoo/UI/Connection/ConnectionWindow.xaml @@ -42,9 +42,18 @@ + + + - + + + + + @@ -60,7 +69,8 @@ - + + @@ -79,14 +89,15 @@