From 91379d41639456249ffb63e6f71d7f423f211f66 Mon Sep 17 00:00:00 2001 From: Sergey Kolupaev Date: Tue, 16 Jul 2024 14:17:57 -0700 Subject: [PATCH] 'required' flag on typed field is dropped --- Commander/App.config | 2 +- Commander/Commander.csproj | 4 +- Commander/packages.config | 2 +- Commander/vault/RecordCommands.cs | 30 ++++++---- KeeperSdk/KeeperSdk.csproj | 2 +- KeeperSdk/utils/RecordTypesUtils.cs | 80 ++++++++++++++------------ KeeperSdk/vault/RecordTypes.cs | 11 +++- KeeperSdk/vault/VaultData.cs | 1 + KeeperSdk/vault/VaultDataExtensions.cs | 7 +-- KeeperSdk/vault/VaultTypes.cs | 11 ++++ 10 files changed, 90 insertions(+), 60 deletions(-) diff --git a/Commander/App.config b/Commander/App.config index 6f06adb..af86d79 100644 --- a/Commander/App.config +++ b/Commander/App.config @@ -15,7 +15,7 @@ - + diff --git a/Commander/Commander.csproj b/Commander/Commander.csproj index 67e69c2..094d4e9 100644 --- a/Commander/Commander.csproj +++ b/Commander/Commander.csproj @@ -69,7 +69,7 @@ - + ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll @@ -77,7 +77,7 @@ ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll - ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll diff --git a/Commander/packages.config b/Commander/packages.config index b658a16..56383e6 100644 --- a/Commander/packages.config +++ b/Commander/packages.config @@ -6,5 +6,5 @@ - + \ No newline at end of file diff --git a/Commander/vault/RecordCommands.cs b/Commander/vault/RecordCommands.cs index 0a0ebc0..2013448 100644 --- a/Commander/vault/RecordCommands.cs +++ b/Commander/vault/RecordCommands.cs @@ -411,7 +411,6 @@ public static async Task AddRecordCommand(this VaultContext context, AddRecordOp await context.Vault.CreateRecord(record, node.FolderUid); } - public static async Task UpdateRecordCommand(this VaultContext context, UpdateRecordOptions options) { if (context.Vault.TryGetKeeperRecord(options.RecordId, out var record)) @@ -434,6 +433,21 @@ record = r; Console.WriteLine($"Cannot resolve record {options.RecordId}"); return; } + if (!string.IsNullOrEmpty(options.RecordType)) + { + if (record is TypedRecord typed) + { + if (context.Vault.TryGetRecordTypeByName(options.RecordType, out var rt)) + { + typed.TypeName = rt.Name; + } + } + else + { + Console.WriteLine($"{options.RecordId} is a legacy record. Record type is not supported."); + return; + } + } if (!string.IsNullOrEmpty(options.Title)) { @@ -573,14 +587,7 @@ record = r; } var uploadTask = new FileAttachmentUploadTask(options.FileName); - if (record is PasswordRecord password) - { - await context.Vault.UploadAttachment(password, uploadTask); - } - else if (record is TypedRecord typed) - { - await context.Vault.UploadAttachment(typed, uploadTask); - } + await context.Vault.UploadAttachment(record, uploadTask); } public static async Task RemoveRecordCommand(this VaultContext context, RemoveRecordOptions options) @@ -740,7 +747,7 @@ class AddRecordOptions [Option("folder", Required = false, HelpText = "folder")] public string Folder { get; set; } - [Option('t', "type", Required = true, HelpText = "record type. legacy if omitted.")] + [Option('t', "type", Required = true, HelpText = "record type.")] public string RecordType { get; set; } [Option("title", Required = true, HelpText = "record title.")] @@ -758,6 +765,9 @@ class UpdateRecordOptions [Option("title", Required = false, HelpText = "title")] public string Title { get; set; } + [Option('t', "type", Required = true, HelpText = "record type. typed records only.")] + public string RecordType { get; set; } + [Option('g', "generate", Required = false, Default = false, HelpText = "generate random password")] public bool Generate { get; set; } diff --git a/KeeperSdk/KeeperSdk.csproj b/KeeperSdk/KeeperSdk.csproj index 27d3907..a424807 100644 --- a/KeeperSdk/KeeperSdk.csproj +++ b/KeeperSdk/KeeperSdk.csproj @@ -55,7 +55,7 @@ - 4.5.2 + 4.5.3 diff --git a/KeeperSdk/utils/RecordTypesUtils.cs b/KeeperSdk/utils/RecordTypesUtils.cs index c302a01..65e15bc 100644 --- a/KeeperSdk/utils/RecordTypesUtils.cs +++ b/KeeperSdk/utils/RecordTypesUtils.cs @@ -194,7 +194,8 @@ public static IEnumerable GetTypedFieldValues(this ITypedField field) { yield return fts.GetValueAsString(); } - else { + else + { yield return ""; } } @@ -387,60 +388,63 @@ public static void AdjustTypedRecord(this VaultData vault, TypedRecord typed) { if (!vault.TryGetRecordTypeByName(typed.TypeName, out var recordType)) return; - var fields = new Dictionary(StringComparer.InvariantCultureIgnoreCase); - for (var i = 0; i < typed.Fields.Count; i++) + var allFields = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + foreach (var rf in typed.Fields.Concat(typed.Custom)) { - var rf = typed.Fields[i]; - fields[rf.GetTypedFieldName()] = i; - } - - foreach (var field in recordType.Fields) - { - if (!fields.ContainsKey(field.GetTypedFieldName())) + for (var i = rf.Count - 1; i >= 0; i--) { - typed.Fields.Add(field.CreateTypedField()); + var value = rf.GetValueAt(i); + if (value == null) + { + rf.DeleteValueAt(i); + } } - } - - fields.Clear(); - for (var i = 0; i < recordType.Fields.Length; i++) - { - var rf = recordType.Fields[i]; - fields[rf.GetTypedFieldName()] = i; - } - - typed.Fields.Sort((f1, f2) => - { - var name1 = f1.GetTypedFieldName(); - var name2 = f2.GetTypedFieldName(); - if (fields.ContainsKey(name1) && fields.ContainsKey(name2)) + var fieldKey = rf.GetTypedFieldName(); + if (!allFields.ContainsKey(fieldKey)) { - return fields[name1] - fields[name2]; + allFields.Add(fieldKey, rf); } + } - if (fields.ContainsKey(name1)) + typed.Fields.Clear(); + foreach (var field in recordType.Fields) + { + var fieldKey = field.GetTypedFieldName(); + if (allFields.TryGetValue(fieldKey, out var rf)) { - return -1; + allFields.Remove(fieldKey); } - - if (fields.ContainsKey(name2)) + else { - return 1; + rf = field.CreateTypedField(); } + rf.Required = field.Required; + typed.Fields.Add(rf); + } - return 0; - }); - foreach (var field in typed.Fields.Concat(typed.Custom)) + var customFields = new List(typed.Custom); + typed.Custom.Clear(); + foreach (var rf in customFields) { - for (var i = field.Count - 1; i >= 0; i--) + if (rf.Count > 0) { - var value = field.GetValueAt(i); - if (value == null) + var fieldKey = rf.GetTypedFieldName(); + if (allFields.ContainsKey(fieldKey)) { - field.DeleteValueAt(0); + typed.Custom.Add(rf); + allFields.Remove(fieldKey); } } } + if (allFields.Count > 0) + { + typed.Custom.AddRange(allFields.Values.Where(x => x.Count > 0)); + } + typed.Custom.RemoveAll((rf) => rf.Count == 0); + foreach (var rf in typed.Custom) + { + rf.Required = false; + } } } } diff --git a/KeeperSdk/vault/RecordTypes.cs b/KeeperSdk/vault/RecordTypes.cs index 8e67fbd..88327aa 100644 --- a/KeeperSdk/vault/RecordTypes.cs +++ b/KeeperSdk/vault/RecordTypes.cs @@ -147,6 +147,8 @@ public RecordTypeField(RecordField recordField, string label = null) /// Gets field label /// public string FieldLabel { get; } + + public bool Required { get; internal set; } } /// @@ -1528,13 +1530,17 @@ internal class RecordTypeDataField : RecordTypeDataFieldBase public override ITypedField CreateTypedField() { - return new TypedField(this); + return new TypedField(this) + { + Required = Required + }; } public RecordTypeDataField(TypedField typedField) { Type = typedField.FieldName; Label = typedField.FieldLabel; + Required = typedField.Required; Value = typedField.Values.Where(x => x != null).ToArray(); } } @@ -1547,6 +1553,9 @@ internal class RecordTypeDataFieldBase : IExtensibleDataObject public string Type { get; set; } [DataMember(Name = "label", Order = 2, EmitDefaultValue = false)] public string Label { get; set; } + [DataMember(Name = "required", Order = 3, EmitDefaultValue = false)] + public bool Required { get; set; } + public ExtensionDataObject ExtensionData { get; set; } public virtual ITypedField CreateTypedField() diff --git a/KeeperSdk/vault/VaultData.cs b/KeeperSdk/vault/VaultData.cs index a28fa56..0d3387a 100644 --- a/KeeperSdk/vault/VaultData.cs +++ b/KeeperSdk/vault/VaultData.cs @@ -318,6 +318,7 @@ private void LoadRecordTypes() { typeField = new RecordTypeField(rf, x.Label); } + typeField.Required = x.Required ?? false; return typeField; } else diff --git a/KeeperSdk/vault/VaultDataExtensions.cs b/KeeperSdk/vault/VaultDataExtensions.cs index 96bba17..c226c4e 100644 --- a/KeeperSdk/vault/VaultDataExtensions.cs +++ b/KeeperSdk/vault/VaultDataExtensions.cs @@ -69,12 +69,7 @@ public static ITypedField CreateTypedField(string fieldName, string fieldLabel = public static ITypedField CreateTypedField(this IRecordTypeField fieldInfo) { - var tf = CreateTypedField(fieldInfo.FieldName, fieldInfo.FieldLabel); - if (fieldInfo is RecordTypeField rtf) - { - } - - return tf; + return CreateTypedField(fieldInfo.FieldName, fieldInfo.FieldLabel); } public static bool FindTypedField(this IList fields, IRecordTypeField fieldInfo, out ITypedField field) diff --git a/KeeperSdk/vault/VaultTypes.cs b/KeeperSdk/vault/VaultTypes.cs index 9dc803c..2355d66 100644 --- a/KeeperSdk/vault/VaultTypes.cs +++ b/KeeperSdk/vault/VaultTypes.cs @@ -808,6 +808,11 @@ public interface ITypedField : IRecordTypeField /// Gets the number of values /// int Count { get; } + + /// + /// Gets required flag + /// + bool Required { get; set; } } /// @@ -855,6 +860,7 @@ public class UnsupportedField : ITypedField, IToRecordTypeDataField internal UnsupportedField(RecordTypeDataFieldBase dataField) { _dataField = dataField; + Required = dataField.Required; } RecordTypeDataFieldBase IToRecordTypeDataField.ToRecordTypeDataField() @@ -888,6 +894,8 @@ void ITypedField.DeleteValueAt(int index) string IRecordTypeField.FieldName => _dataField.Type; string IRecordTypeField.FieldLabel => _dataField.Label; + + public bool Required { get; set; } } /// @@ -952,6 +960,9 @@ public TypedField(string fieldType, string fieldLabel = null) /// public List Values { get; } = new List(); + /// + public bool Required { get; set; } + public T AppendTypedValue() { switch (Values)