From f8c77761270c099edbb51d4273dcf7563619ce8a Mon Sep 17 00:00:00 2001 From: etogood Date: Wed, 3 Jul 2024 22:33:50 +0300 Subject: [PATCH] add: validation for file names in stores --- src/Asv.Drones.Gui.Api/RS.Designer.cs | 9 +++++++++ src/Asv.Drones.Gui.Api/RS.resx | 3 +++ src/Asv.Drones.Gui.Api/RS.ru.resx | 3 +++ .../HierarchicalStoreEntryViewModel.cs | 16 +++++++++++++--- .../HierarchicalStoreViewModel.cs | 3 ++- src/Asv.Drones.Gui/RS.Designer.cs | 9 +++++++++ src/Asv.Drones.Gui/RS.resx | 3 +++ src/Asv.Drones.Gui/RS.ru.resx | 6 ++++++ .../PlaningMissionSavingBrowserViewModel.cs | 14 +++++++++++++- 9 files changed, 61 insertions(+), 5 deletions(-) diff --git a/src/Asv.Drones.Gui.Api/RS.Designer.cs b/src/Asv.Drones.Gui.Api/RS.Designer.cs index 4c612d55..6cef5b26 100644 --- a/src/Asv.Drones.Gui.Api/RS.Designer.cs +++ b/src/Asv.Drones.Gui.Api/RS.Designer.cs @@ -562,5 +562,14 @@ public static string ParamPageViewModel_DataLossDialog_Title { return ResourceManager.GetString("ParamPageViewModel_DataLossDialog_Title", resourceCulture); } } + + /// + /// Looks up a localized string similar to Not valid name. + /// + public static string StoreFileName_Validation_ErrorMessage { + get { + return ResourceManager.GetString("StoreFileName_Validation_ErrorMessage", resourceCulture); + } + } } } diff --git a/src/Asv.Drones.Gui.Api/RS.resx b/src/Asv.Drones.Gui.Api/RS.resx index add23c66..44c767e9 100644 --- a/src/Asv.Drones.Gui.Api/RS.resx +++ b/src/Asv.Drones.Gui.Api/RS.resx @@ -193,4 +193,7 @@ Actions + + Not valid name + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/RS.ru.resx b/src/Asv.Drones.Gui.Api/RS.ru.resx index 4f73ccca..9dee5e1f 100644 --- a/src/Asv.Drones.Gui.Api/RS.ru.resx +++ b/src/Asv.Drones.Gui.Api/RS.ru.resx @@ -189,4 +189,7 @@ Действия + + Неверное имя + \ No newline at end of file diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreEntryViewModel.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreEntryViewModel.cs index 07976470..7d6ea02b 100644 --- a/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreEntryViewModel.cs +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreEntryViewModel.cs @@ -1,11 +1,14 @@ using System.Collections.ObjectModel; using System.Reactive; +using System.Reactive.Linq; +using System.Text.RegularExpressions; using Asv.Common; using Asv.Mavlink; using DynamicData; using DynamicData.Binding; using ReactiveUI; using ReactiveUI.Fody.Helpers; +using ReactiveUI.Validation.Extensions; namespace Asv.Drones.Gui.Api; @@ -15,17 +18,16 @@ public enum HierarchicalStoreEntryAction Delete } -public class HierarchicalStoreEntryViewModel : DisposableReactiveObject +public partial class HierarchicalStoreEntryViewModel : DisposableReactiveObjectWithValidation { public HierarchicalStoreEntryViewModel() { BeginEditName = ReactiveCommand.Create(() => { IsInEditNameMode = true; }).DisposeItWith(Disposable); - ; EndEditName = ReactiveCommand.Create(() => { IsInEditNameMode = false; Rename(Name); - }).DisposeItWith(Disposable); + }, CanEndEditName).DisposeItWith(Disposable); EndEditName.ThrownExceptions .Subscribe(ex => OnError(HierarchicalStoreEntryAction.Rename, ex)) .DisposeItWith(Disposable); @@ -49,6 +51,9 @@ public HierarchicalStoreEntryViewModel() this.WhenValueChanged(x => x.IsNotInMoveMode) .Subscribe(x => IsInMoveMode = !x) .DisposeItWith(Disposable); + this.ValidationRule(x => x.Name, + s => s != null && FileNameRegex().IsMatch(s), + RS.StoreFileName_Validation_ErrorMessage); } @@ -66,6 +71,11 @@ public HierarchicalStoreEntryViewModel() public virtual ReadOnlyObservableCollection Items { get; set; } [Reactive] public bool IsInEditNameMode { get; set; } = false; + [GeneratedRegex(@"^[A-Za-z][A-Za-z0-9_\- +]{0,28}")] + private partial Regex FileNameRegex(); + private IObservable CanEndEditName => this.WhenPropertyChanged(x => x.Name) + .Select(x => x.Value != null && FileNameRegex().IsMatch(x.Value)); + public ReactiveCommand DeleteEntry { get; } public ReactiveCommand BeginEditName { get; } public ReactiveCommand EndEditName { get; } diff --git a/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreViewModel.cs b/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreViewModel.cs index 0029507f..d82f23a9 100644 --- a/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreViewModel.cs +++ b/src/Asv.Drones.Gui.Api/Tools/Controls/HierarchicalStore/HierarchicalStoreViewModel.cs @@ -12,10 +12,11 @@ using DynamicData.Binding; using ReactiveUI; using ReactiveUI.Fody.Helpers; +using ReactiveUI.Validation.Helpers; namespace Asv.Drones.Gui.Api; -public class HierarchicalStoreViewModel : ViewModelBase +public class HierarchicalStoreViewModel : ViewModelBaseWithValidation { protected HierarchicalStoreViewModel(Uri id) : base(id) { diff --git a/src/Asv.Drones.Gui/RS.Designer.cs b/src/Asv.Drones.Gui/RS.Designer.cs index a4b02864..c49d1095 100644 --- a/src/Asv.Drones.Gui/RS.Designer.cs +++ b/src/Asv.Drones.Gui/RS.Designer.cs @@ -4938,6 +4938,15 @@ public static string StartAutoAnchorActionViewModel_Title { } } + /// + /// Looks up a localized string similar to Not valid name. + /// + public static string StoreFileName_Validation_ErrorMessage { + get { + return ResourceManager.GetString("StoreFileName_Validation_ErrorMessage", resourceCulture); + } + } + /// /// Looks up a localized string similar to Set altitude above ground level (AGL) for takeoff command.. /// diff --git a/src/Asv.Drones.Gui/RS.resx b/src/Asv.Drones.Gui/RS.resx index 605ffead..d810ed7f 100644 --- a/src/Asv.Drones.Gui/RS.resx +++ b/src/Asv.Drones.Gui/RS.resx @@ -1868,4 +1868,7 @@ A file with the same name already exists. After performing this action, overwriting will occur. Are you sure you want to continue? + + Not valid name + \ No newline at end of file diff --git a/src/Asv.Drones.Gui/RS.ru.resx b/src/Asv.Drones.Gui/RS.ru.resx index a2588ed6..86c051fb 100644 --- a/src/Asv.Drones.Gui/RS.ru.resx +++ b/src/Asv.Drones.Gui/RS.ru.resx @@ -1900,4 +1900,10 @@ Файл с таким именем уже существует. После выполнения данного действия произойдёт перезапись. Вы уверены, что хотите продолжить? + + Неверное имя + + + Неверное имя + \ No newline at end of file diff --git a/src/Asv.Drones.Gui/Shell/Pages/Planing/Browser/PlaningMissionSavingBrowserViewModel.cs b/src/Asv.Drones.Gui/Shell/Pages/Planing/Browser/PlaningMissionSavingBrowserViewModel.cs index 1fc36aa4..6486dc58 100644 --- a/src/Asv.Drones.Gui/Shell/Pages/Planing/Browser/PlaningMissionSavingBrowserViewModel.cs +++ b/src/Asv.Drones.Gui/Shell/Pages/Planing/Browser/PlaningMissionSavingBrowserViewModel.cs @@ -4,6 +4,7 @@ using System.Composition; using System.Linq; using System.Reactive.Linq; +using System.Text.RegularExpressions; using Asv.Drones.Gui.Api; using Asv.Mavlink; using Asv.Mavlink.V2.Common; @@ -14,10 +15,13 @@ using Material.Icons; using ReactiveUI; using ReactiveUI.Fody.Helpers; +using ReactiveUI.Validation.Abstractions; +using ReactiveUI.Validation.Contexts; +using ReactiveUI.Validation.Extensions; namespace Asv.Drones.Gui; -public class PlaningMissionSavingBrowserViewModel : HierarchicalStoreViewModel +public partial class PlaningMissionSavingBrowserViewModel : HierarchicalStoreViewModel { private readonly IPlaningMission _svc; @@ -33,8 +37,14 @@ public PlaningMissionSavingBrowserViewModel(IPlaningMission svc, ILogService log _svc = svc; FileName = name; using var a = Refresh.Execute().Subscribe(); + this.ValidationRule(x => x.FileName, + s => s != null && FileNameRegex().IsMatch(s), + RS.StoreFileName_Validation_ErrorMessage); } + [GeneratedRegex(@"^[A-Za-z][A-Za-z0-9_\- +]{0,28}")] + private partial Regex FileNameRegex(); + [Reactive] public string? FileName { get; set; } = string.Empty; protected override void RefreshImpl() @@ -129,4 +139,6 @@ public void SaveAsImpl(out Guid id) id = fileId; Refresh.Execute().Subscribe(_ => { }); } + + } \ No newline at end of file