From e901afaf293468d0c125421135e8830ee4999518 Mon Sep 17 00:00:00 2001 From: Geoffroy BONNEVILLE Date: Thu, 7 May 2020 12:11:12 +0200 Subject: [PATCH] Attachment Add and Delete commands implemented --- ModernKeePass.Application/Application.csproj | 2 + .../Common/Interfaces/IDatabaseProxy.cs | 2 + .../AddAttachment/AddAttachmentCommand.cs | 34 +++++++++++++++++ .../DeleteAttachmentCommand.cs | 33 ++++++++++++++++ .../KeePass/KeePassDatabaseClient.cs | 14 ++++++- ModernKeePass/Strings/en-US/Resources.resw | 3 ++ ModernKeePass/Strings/fr-FR/Resources.resw | 3 ++ ModernKeePass/ViewModels/EntryDetailVm.cs | 36 +++++++++++++++--- ModernKeePass/ViewModels/ViewModelLocator.cs | 4 +- ModernKeePass/Views/EntryDetailPage.xaml | 38 +++++++++++++------ 10 files changed, 150 insertions(+), 19 deletions(-) create mode 100644 ModernKeePass.Application/Entry/Commands/AddAttachment/AddAttachmentCommand.cs create mode 100644 ModernKeePass.Application/Entry/Commands/DeleteAttachment/DeleteAttachmentCommand.cs diff --git a/ModernKeePass.Application/Application.csproj b/ModernKeePass.Application/Application.csproj index e23b926..baba6de 100644 --- a/ModernKeePass.Application/Application.csproj +++ b/ModernKeePass.Application/Application.csproj @@ -88,7 +88,9 @@ + + diff --git a/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs b/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs index c7a7ce2..a91a751 100644 --- a/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs +++ b/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs @@ -44,6 +44,8 @@ namespace ModernKeePass.Application.Common.Interfaces GroupEntity CreateGroup(string parentGroupId, string name, bool isRecycleBin = false); void SortEntries(string groupId); void SortSubGroups(string groupId); + void AddAttachment(string entryId, string attachmentName, byte[] attachmentContent); + void DeleteAttachment(string entryId, string attachmentName); EntryEntity AddHistory(string entryId); EntryEntity RestoreFromHistory(string entryId, int historyIndex); diff --git a/ModernKeePass.Application/Entry/Commands/AddAttachment/AddAttachmentCommand.cs b/ModernKeePass.Application/Entry/Commands/AddAttachment/AddAttachmentCommand.cs new file mode 100644 index 0000000..7097aac --- /dev/null +++ b/ModernKeePass.Application/Entry/Commands/AddAttachment/AddAttachmentCommand.cs @@ -0,0 +1,34 @@ +using System; +using MediatR; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Application.Entry.Models; +using ModernKeePass.Domain.Exceptions; + +namespace ModernKeePass.Application.Entry.Commands.AddAttachment +{ + public class AddAttachmentCommand : IRequest + { + public EntryVm Entry { get; set; } + public string AttachmentName { get; set; } + public byte[] AttachmentContent { get; set; } + + public class AddAttachmentCommandHandler : IRequestHandler + { + private readonly IDatabaseProxy _database; + + public AddAttachmentCommandHandler(IDatabaseProxy database) + { + _database = database; + } + + public void Handle(AddAttachmentCommand message) + { + if (!_database.IsOpen) throw new DatabaseClosedException(); + + if (message.Entry.Attachments.ContainsKey(message.AttachmentName)) throw new ArgumentException("AttachmentAlreadyExists", nameof(message.AttachmentName)); + _database.AddAttachment(message.Entry.Id, message.AttachmentName, message.AttachmentContent); + message.Entry.Attachments.Add(message.AttachmentName, message.AttachmentContent); + } + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Entry/Commands/DeleteAttachment/DeleteAttachmentCommand.cs b/ModernKeePass.Application/Entry/Commands/DeleteAttachment/DeleteAttachmentCommand.cs new file mode 100644 index 0000000..4453fe1 --- /dev/null +++ b/ModernKeePass.Application/Entry/Commands/DeleteAttachment/DeleteAttachmentCommand.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using MediatR; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Application.Entry.Models; +using ModernKeePass.Domain.Exceptions; + +namespace ModernKeePass.Application.Entry.Commands.DeleteAttachment +{ + public class DeleteAttachmentCommand : IRequest + { + public EntryVm Entry { get; set; } + public string AttachmentName { get; set; } + + public class DeleteAttachmentCommandHandler : IRequestHandler + { + private readonly IDatabaseProxy _database; + + public DeleteAttachmentCommandHandler(IDatabaseProxy database) + { + _database = database; + } + + public void Handle(DeleteAttachmentCommand message) + { + if (!_database.IsOpen) throw new DatabaseClosedException(); + + if (!message.Entry.Attachments.ContainsKey(message.AttachmentName)) throw new KeyNotFoundException("AttachmentDoesntExist"); + _database.DeleteAttachment(message.Entry.Id, message.AttachmentName); + message.Entry.Attachments.Remove(message.AttachmentName); + } + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs b/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs index 7eac76b..513d2d9 100644 --- a/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs +++ b/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs @@ -244,7 +244,7 @@ namespace ModernKeePass.Infrastructure.KeePass break; } } - + public EntryEntity AddHistory(string entryId) { var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entryId), true); @@ -307,6 +307,18 @@ namespace ModernKeePass.Infrastructure.KeePass pwGroup.SortSubGroups(false); } + public void AddAttachment(string entryId, string attachmentName, byte[] attachmentContent) + { + var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entryId), true); + pwEntry.Binaries.Set(attachmentName, new ProtectedBinary(true, attachmentContent)); + } + + public void DeleteAttachment(string entryId, string attachmentName) + { + var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entryId), true); + pwEntry.Binaries.Remove(attachmentName); + } + public EntryEntity GetEntry(string id) { var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(id), true); diff --git a/ModernKeePass/Strings/en-US/Resources.resw b/ModernKeePass/Strings/en-US/Resources.resw index 4de65c4..6d369ab 100644 --- a/ModernKeePass/Strings/en-US/Resources.resw +++ b/ModernKeePass/Strings/en-US/Resources.resw @@ -531,4 +531,7 @@ Icon + + Add attachment + \ No newline at end of file diff --git a/ModernKeePass/Strings/fr-FR/Resources.resw b/ModernKeePass/Strings/fr-FR/Resources.resw index e3125ac..09d162c 100644 --- a/ModernKeePass/Strings/fr-FR/Resources.resw +++ b/ModernKeePass/Strings/fr-FR/Resources.resw @@ -531,4 +531,7 @@ Icone + + Ajouter une pièce jointe + \ No newline at end of file diff --git a/ModernKeePass/ViewModels/EntryDetailVm.cs b/ModernKeePass/ViewModels/EntryDetailVm.cs index e5dad60..714f03a 100644 --- a/ModernKeePass/ViewModels/EntryDetailVm.cs +++ b/ModernKeePass/ViewModels/EntryDetailVm.cs @@ -13,7 +13,9 @@ using ModernKeePass.Application.Common.Interfaces; using ModernKeePass.Application.Database.Commands.SaveDatabase; using ModernKeePass.Application.Database.Models; using ModernKeePass.Application.Database.Queries.GetDatabase; +using ModernKeePass.Application.Entry.Commands.AddAttachment; using ModernKeePass.Application.Entry.Commands.AddHistory; +using ModernKeePass.Application.Entry.Commands.DeleteAttachment; using ModernKeePass.Application.Entry.Commands.DeleteHistory; using ModernKeePass.Application.Entry.Commands.RestoreHistory; using ModernKeePass.Application.Entry.Commands.SetFieldValue; @@ -90,6 +92,11 @@ namespace ModernKeePass.ViewModels Name = f.Key, Content = f.Value })); + Attachments.CollectionChanged += (sender, args) => + { + SaveCommand.RaiseCanExecuteChanged(); + _isDirty = true; + }; RaisePropertyChanged(string.Empty); } } @@ -102,6 +109,7 @@ namespace ModernKeePass.ViewModels { Set(() => SelectedIndex, ref _selectedIndex, value); RaisePropertyChanged(nameof(IsCurrentEntry)); + AddAttachmentCommand.RaiseCanExecuteChanged(); } } @@ -251,6 +259,8 @@ namespace ModernKeePass.ViewModels public RelayCommand GoBackCommand { get; } public RelayCommand GoToParentCommand { get; set; } public RelayCommand OpenAttachmentCommand { get; set; } + public RelayCommand AddAttachmentCommand { get; set; } + public RelayCommand DeleteAttachmentCommand { get; set; } private DatabaseVm Database => _mediator.Send(new GetDatabaseQuery()).GetAwaiter().GetResult(); @@ -285,13 +295,15 @@ namespace ModernKeePass.ViewModels GoBackCommand = new RelayCommand(() => _navigation.GoBack()); GoToParentCommand = new RelayCommand(() => GoToGroup(_parent.Id)); OpenAttachmentCommand = new RelayCommand(async attachment => await OpenAttachment(attachment)); + AddAttachmentCommand = new RelayCommand(async () => await AddAttachment(), () => IsCurrentEntry); + DeleteAttachmentCommand = new RelayCommand(async attachment => await DeleteAttachment(attachment)); MessengerInstance.Register(this, _ => SaveCommand.RaiseCanExecuteChanged()); } - - + public async Task Initialize(string entryId) { + SelectedIndex = 0; SelectedItem = await _mediator.Send(new GetEntryQuery { Id = entryId }); _parent = await _mediator.Send(new GetGroupQuery { Id = SelectedItem.ParentGroupId }); History = new ObservableCollection { SelectedItem }; @@ -299,7 +311,7 @@ namespace ModernKeePass.ViewModels { History.Add(entry); } - SelectedIndex = 0; + History.CollectionChanged += (sender, args) => SaveCommand.RaiseCanExecuteChanged(); } private async Task AskForDelete() @@ -333,7 +345,6 @@ namespace ModernKeePass.ViewModels await _mediator.Send(new DeleteHistoryCommand { Entry = History[0], HistoryIndex = History.Count - SelectedIndex - 1 }); History.RemoveAt(SelectedIndex); SelectedIndex = 0; - SaveCommand.RaiseCanExecuteChanged(); }); } } @@ -385,7 +396,6 @@ namespace ModernKeePass.ViewModels await _mediator.Send(new RestoreHistoryCommand { Entry = History[0], HistoryIndex = History.Count - SelectedIndex - 1 }); History.Insert(0, SelectedItem); SelectedIndex = 0; - SaveCommand.RaiseCanExecuteChanged(); } private async Task SaveChanges() @@ -424,5 +434,21 @@ namespace ModernKeePass.ViewModels if (fileInfo == null) return; await _file.WriteBinaryContentsToFile(fileInfo.Id, attachment.Content); } + + private async Task AddAttachment() + { + var fileInfo = await _file.OpenFile(string.Empty, Domain.Common.Constants.Extensions.Any, false); + if (fileInfo == null) return; + var contents = await _file.ReadBinaryFile(fileInfo.Id); + await _mediator.Send(new AddAttachmentCommand { Entry = SelectedItem, AttachmentName = fileInfo.Name, AttachmentContent = contents }); + Attachments.Add(new Attachment { Name = fileInfo.Name, Content = contents }); + } + + private async Task DeleteAttachment(Attachment attachment) + { + await _mediator.Send(new DeleteAttachmentCommand { Entry = SelectedItem, AttachmentName = attachment.Name }); + Attachments.Remove(attachment); + } + } } diff --git a/ModernKeePass/ViewModels/ViewModelLocator.cs b/ModernKeePass/ViewModels/ViewModelLocator.cs index 135b62c..f5959ca 100644 --- a/ModernKeePass/ViewModels/ViewModelLocator.cs +++ b/ModernKeePass/ViewModels/ViewModelLocator.cs @@ -37,7 +37,7 @@ namespace ModernKeePass.ViewModels public MainVm Main => ServiceLocator.Current.GetInstance(Guid.NewGuid().ToString()); public SettingsVm Settings => ServiceLocator.Current.GetInstance(Guid.NewGuid().ToString()); - public GroupDetailVm Group => ServiceLocator.Current.GetInstance(); - public EntryDetailVm Entry => ServiceLocator.Current.GetInstance(); + public GroupDetailVm Group => ServiceLocator.Current.GetInstance(Guid.NewGuid().ToString()); + public EntryDetailVm Entry => ServiceLocator.Current.GetInstance(Guid.NewGuid().ToString()); } } \ No newline at end of file diff --git a/ModernKeePass/Views/EntryDetailPage.xaml b/ModernKeePass/Views/EntryDetailPage.xaml index ebfe659..8c78946 100644 --- a/ModernKeePass/Views/EntryDetailPage.xaml +++ b/ModernKeePass/Views/EntryDetailPage.xaml @@ -1,4 +1,4 @@ - - + @@ -499,15 +499,31 @@ - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + +