Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Kukks committed Sep 20, 2022
1 parent 1540bfb commit d085707
Show file tree
Hide file tree
Showing 28 changed files with 2,520 additions and 79 deletions.
35 changes: 17 additions & 18 deletions BTCPayServer.Abstractions/Form/Field.cs
Original file line number Diff line number Diff line change
@@ -1,35 +1,34 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace BTCPayServer.Abstractions.Form;

public abstract class Field
public class Field
{
// HTML5 compatible type string like "text", "textarea", "email", "password", etc. Each type is a class and may contain more fields (i.e. "select" would have options).
public string Type;

// The name of the HTML5 node. Should be used as the key for the posted data.
public string Name;
// The translated label of the field.
public string Label;

// HTML5 compatible type string like "text", "textarea", "email", "password", etc. Each type is a class and may contain more fields (i.e. "select" would have options).
public string Type;

// The value field is what is currently in the DB or what the user entered, but possibly not saved yet due to validation errors.
// If this is the first the user sees the form, then value and original value are the same. Value changes as the user starts interacting with the form.
public string Value;

// The original value is the value that is currently saved in the backend. A "reset" button can be used to revert back to this. Should only be set from the constructor.
public string OriginalValue;

// A useful note shown below the field or via a tooltip / info icon. Should be translated for the user.
public string HelpText;

// The field is considered "valid" if there are no validation errors
public List<string> ValidationErrors = new List<string>();

public bool Required = false;

public bool IsValid()
public virtual bool IsValid()
{
return ValidationErrors.Count == 0;
return ValidationErrors.Count == 0 && Fields.All(field => field.IsValid());
}

[JsonExtensionData] public IDictionary<string, JToken> AdditionalData { get; set; }
public List<Field> Fields { get; set; } = new();


}
12 changes: 5 additions & 7 deletions BTCPayServer.Abstractions/Form/Fieldset.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
using System.Collections.Generic;

namespace BTCPayServer.Abstractions.Form;

public class Fieldset
public class Fieldset : Field
{
public bool Hidden { get; set; }
public string Label { get; set; }

public Fieldset()
{
this.Fields = new List<Field>();
Type = "fieldset";
}

public string Label { get; set; }
public List<Field> Fields { get; set; }
}
124 changes: 105 additions & 19 deletions BTCPayServer.Abstractions/Form/Form.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json.Linq;

namespace BTCPayServer.Abstractions.Form;

Expand All @@ -9,52 +13,134 @@ public class Form
public List<AlertMessage> TopMessages { get; set; } = new();

// Groups of fields in the form
public List<Fieldset> Fieldsets { get; set; } = new();
public List<Field> Fields { get; set; } = new();


// Are all the fields valid in the form?
public bool IsValid()
{
foreach (var fieldset in Fieldsets)
{
foreach (var field in fieldset.Fields)
{
if (!field.IsValid())
{
return false;
}
}
}

return true;
return Fields.All(field => field.IsValid());
}

public Field GetFieldByName(string name)
{
foreach (var fieldset in Fieldsets)
return GetFieldByName(name, Fields, null);
}


private static Field GetFieldByName(string name, List<Field> fields, string prefix)
{
prefix ??= string.Empty;
foreach (var field in fields)
{
foreach (var field in fieldset.Fields)
var currentPrefix = prefix;
if (!string.IsNullOrEmpty(field.Name))
{
if (name.Equals(field.Name))

currentPrefix = $"{prefix}{field.Name}";
if (currentPrefix.Equals(name, StringComparison.InvariantCultureIgnoreCase))
{
return field;
}

currentPrefix += "_";
}

var subFieldResult = GetFieldByName(name, field.Fields, currentPrefix);
if (subFieldResult is not null)
{
return subFieldResult;
}

}
return null;
}

public List<string> GetAllNames()
{
return GetAllNames(Fields);
}

private static List<string> GetAllNames(List<Field> fields)
{
var names = new List<string>();
foreach (var fieldset in Fieldsets)

foreach (var field in fields)
{
foreach (var field in fieldset.Fields)
string prefix = string.Empty;
if (!string.IsNullOrEmpty(field.Name))
{
names.Add(field.Name);
prefix = $"{field.Name}_";
}

if (field.Fields.Any())
{
names.AddRange(GetAllNames(field.Fields).Select(s => $"{prefix}{s}" ));
}
}

return names;
}

public void ApplyValuesFromOtherForm(Form form)
{
foreach (var fieldset in Fields)
{
foreach (var field in fieldset.Fields)
{
field.Value = form
.GetFieldByName(
$"{(string.IsNullOrEmpty(fieldset.Name) ? string.Empty : fieldset.Name + "_")}{field.Name}")
?.Value;
}
}
}

public void ApplyValuesFromForm(IFormCollection form)
{
var names = GetAllNames();
foreach (var name in names)
{
var field = GetFieldByName(name);
if (field is null || !form.TryGetValue(name, out var val))
{
continue;
}

field.Value = val;
}
}

public Dictionary<string, object> GetValues()
{
return GetValues(Fields);
}
private static Dictionary<string, object> GetValues(List<Field> fields)
{
var result = new Dictionary<string, object>();
foreach (Field field in fields)
{
var name = field.Name ?? string.Empty;
if (field.Fields.Any())
{
var values = GetValues(fields);
values.Remove(string.Empty, out var keylessValue);

result.TryAdd(name, values);

if (keylessValue is not Dictionary<string, object> dict) continue;
foreach (KeyValuePair<string,object> keyValuePair in dict)
{
result.TryAdd(keyValuePair.Key, keyValuePair.Value);
}
}
else
{
result.TryAdd(name, field.Value);
}
}

return result;
}

}
13 changes: 13 additions & 0 deletions BTCPayServer.Abstractions/Form/TextField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@ namespace BTCPayServer.Abstractions.Form;

public class TextField : Field
{



// The translated label of the field.
public string Label;

// The original value is the value that is currently saved in the backend. A "reset" button can be used to revert back to this. Should only be set from the constructor.
public string OriginalValue;

// A useful note shown below the field or via a tooltip / info icon. Should be translated for the user.
public string HelpText;

public bool Required = false;
public TextField(string label, string name, string value, bool required, string helpText)
{
this.Label = label;
Expand Down
2 changes: 2 additions & 0 deletions BTCPayServer.Data/ApplicationDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, bool
public DbSet<WebhookData> Webhooks { get; set; }
public DbSet<LightningAddressData> LightningAddresses{ get; set; }
public DbSet<PayoutProcessorData> PayoutProcessors { get; set; }
public DbSet<FormData> Forms { get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
Expand Down Expand Up @@ -114,6 +115,7 @@ protected override void OnModelCreating(ModelBuilder builder)
LightningAddressData.OnModelCreating(builder);
PayoutProcessorData.OnModelCreating(builder);
//WebhookData.OnModelCreating(builder);
FormData.OnModelCreating(builder, Database);


if (Database.IsSqlite() && !_designTime)
Expand Down
30 changes: 30 additions & 0 deletions BTCPayServer.Data/Data/FormData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;

namespace BTCPayServer.Data.Data;

public class FormData
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
public string Name { get; set; }
public string StoreId { get; set; }
public StoreData Store { get; set; }

public string Config { get; set; }


internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<FormData>()
.HasOne(o => o.Store)
.WithMany(o => o.Forms).OnDelete(DeleteBehavior.Cascade);
if (databaseFacade.IsNpgsql())
{
builder.Entity<FormData>()
.Property(o => o.Config)
.HasColumnType("JSONB");
}
}
}
1 change: 1 addition & 0 deletions BTCPayServer.Data/Data/StoreData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,6 @@ public class StoreData
public IEnumerable<PayoutData> Payouts { get; set; }
public IEnumerable<CustodianAccountData> CustodianAccounts { get; set; }
public IEnumerable<StoreSettingData> Settings { get; set; }
public IEnumerable<FormData> Forms { get; set; }
}
}

0 comments on commit d085707

Please sign in to comment.