diff --git a/csharp/app/Backend/Controllers/Controller.cs b/csharp/app/Backend/Controllers/Controller.cs index 10110397e..345ac4e58 100644 --- a/csharp/app/Backend/Controllers/Controller.cs +++ b/csharp/app/Backend/Controllers/Controller.cs @@ -160,8 +160,47 @@ public class Controller .GetAllAccessibleFolders(caller) .ToList(); // important! } - + [Returns] // assuming swagger knows about arrays but not lists (JSON) + [Returns(HttpStatusCode.Unauthorized)] + [HttpGet($"{nameof(GetTree)}/")] + public Object GetTree() + { + var caller = GetCaller(); + if (caller == null) + return new HttpResponseMessage(HttpStatusCode.Unauthorized); + + using var db = Db.Connect(); + + var folders = db + .GetDirectlyAccessibleFolders(caller) // ReSharper disable once AccessToDisposedClosure + .Select(f => PopulateChildren(db, f)); + + var installations = db.GetDirectlyAccessibleInstallations(caller); + + return folders + .Concat(installations) + .ToList(); // important! + } + + private static Folder PopulateChildren(Db db, Folder folder, HashSet? hs = null) + { + // TODO: remove cycle detector + hs ??= new HashSet(); + if (!hs.Add(folder.Id)) + throw new Exception("Cycle detected: folder " + folder.Id); + + var installations = db.GetChildInstallations(folder); + var folders = db + .GetChildFolders(folder) + .Select(c => PopulateChildren(db, c, hs)); + + folder.Children = folders.Concat(installations).ToList(); + + return folder; + } + + [Returns(HttpStatusCode.OK)] [Returns(HttpStatusCode.Unauthorized)] [HttpPut($"{nameof(UpdateUser)}/")] @@ -184,7 +223,7 @@ public class Controller [Returns(HttpStatusCode.OK)] [Returns(HttpStatusCode.Unauthorized)] [HttpPut($"{nameof(UpdateInstallation)}/")] - public Object UpdateInstallation(Installation updatedInstallation) + public Object UpdateInstallation(Installation installation) { var caller = GetCaller(); @@ -195,7 +234,7 @@ public class Controller var hasAccessToInstallation = db .GetAllAccessibleInstallations(caller) - .Any(i => i.Id == updatedInstallation.Id); + .Any(i => i.Id == installation.Id); if (!hasAccessToInstallation) return new HttpResponseMessage(HttpStatusCode.Unauthorized); @@ -203,7 +242,7 @@ public class Controller // TODO: accessibility by other users etc // TODO: sanity check changes - return db.UpdateInstallation(updatedInstallation); + return db.UpdateInstallation(installation); } diff --git a/csharp/app/Backend/Model/TreeNode.Equality.cs b/csharp/app/Backend/Model/TreeNode.Equality.cs new file mode 100644 index 000000000..b044a020f --- /dev/null +++ b/csharp/app/Backend/Model/TreeNode.Equality.cs @@ -0,0 +1,24 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Innovenergy.Backend.Model; + +public abstract partial class TreeNode +{ + protected Boolean Equals(TreeNode other) + { + return Id == other.Id && ParentId == other.ParentId; + } + + public override Boolean Equals(Object? obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + return obj.GetType() == GetType() && Equals((TreeNode)obj); + } + + [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] + public override Int32 GetHashCode() + { + return HashCode.Combine(Id, ParentId); + } +} \ No newline at end of file diff --git a/csharp/app/Backend/Model/TreeNode.cs b/csharp/app/Backend/Model/TreeNode.cs index 1daf30f74..b3cf22170 100644 --- a/csharp/app/Backend/Model/TreeNode.cs +++ b/csharp/app/Backend/Model/TreeNode.cs @@ -2,33 +2,20 @@ using SQLite; namespace Innovenergy.Backend.Model; -public abstract class TreeNode +public abstract partial class TreeNode { [PrimaryKey, AutoIncrement] public Int64 Id { get; set; } public String Name { get; set; } = ""; public String Information { get; set; } = ""; // unstructured random info - protected Boolean Equals(TreeNode other) - { - return Id == other.Id && ParentId == other.ParentId; - } - - public override Boolean Equals(Object? obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == this.GetType() && Equals((TreeNode)obj); - } - - public override Int32 GetHashCode() - { - return HashCode.Combine(Id, ParentId); - } - [Indexed] // parent/child relation public Int64 ParentId { get; set; } [Ignore] // not in DB, can be used in typescript as type discriminator public String Type => GetType().Name; + + [Ignore] + public IReadOnlyList? Children { get; set; } + } \ No newline at end of file diff --git a/csharp/app/Backend/program.cs b/csharp/app/Backend/Program.cs similarity index 81% rename from csharp/app/Backend/program.cs rename to csharp/app/Backend/Program.cs index 26c44b71c..fd0206737 100644 --- a/csharp/app/Backend/program.cs +++ b/csharp/app/Backend/Program.cs @@ -3,9 +3,9 @@ using Microsoft.OpenApi.Models; namespace Innovenergy.Backend; -public class Program +public static class Program { - public static void Main(string[] args) + public static void Main(String[] args) { using (var db = Db.Connect()) db.CreateFakeRelations(); @@ -18,10 +18,11 @@ public class Program builder.Services.AddHttpContextAccessor(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddCors(o => o.AddDefaultPolicy(p => p.WithOrigins("*").AllowAnyHeader().AllowAnyMethod())); - builder.Services.AddSwaggerGen(config => + builder.Services.AddSwaggerGen(c => { - config.SwaggerDoc("v1", new OpenApiInfo{ Title = "My API", Version = "V1" }); - config.OperationFilter(); //Todo testing throw me out + c.SwaggerDoc("v1", new OpenApiInfo { Title = "InnovEnergy Backend API", Version = "v1" }); + c.UseAllOfToExtendReferenceSchemas(); + c.OperationFilter(); //Todo testing throw me out });