Merge remote-tracking branch 'origin/main'

# Conflicts:
#	csharp/App/Backend/Database/Db.cs
#	csharp/App/Backend/Database/User.cs
This commit is contained in:
Kim 2023-03-09 16:34:19 +01:00
commit 2fdd920572
7 changed files with 119 additions and 135 deletions

View File

@ -10,16 +10,16 @@ namespace InnovEnergy.App.Backend.Database;
public partial class Db : IDisposable public partial class Db : IDisposable
{ {
internal const String DbPath = "./db.sqlite"; internal const String DbPath = "./db.sqlite";
private readonly SQLiteConnection _Db; // internal handle to the connection, disposable private readonly SQLiteConnection _Db; // internal handle to the connection, disposable
private TableQuery<Session> Sessions => _Db.Table<Session>(); private TableQuery<Session> Sessions => _Db.Table<Session>();
[SuppressMessage("ReSharper", "AccessToDisposedClosure")] [SuppressMessage("ReSharper", "AccessToDisposedClosure")]
static Db() static Db()
{ {
// on startup create/migrate tables // on startup create/migrate tables
using var db = new SQLiteConnection(DbPath); using var db = new SQLiteConnection(DbPath);
db.RunInTransaction(() => db.RunInTransaction(() =>
@ -31,105 +31,115 @@ public partial class Db : IDisposable
db.CreateTable<User2Installation>(); db.CreateTable<User2Installation>();
db.CreateTable<Session>(); db.CreateTable<Session>();
}); });
} }
// private, force access through Connect() // private, force access through Connect()
private Db() => _Db = new SQLiteConnection(DbPath); private Db() => _Db = new SQLiteConnection(DbPath);
public static Db Connect() => new Db(); public static Db Connect() => new Db();
public void Dispose() => _Db.Dispose(); public void Dispose() => _Db.Dispose();
// the C in CRUD // the C in CRUD
private Result Create(TreeNode treeNode) private Int64 Create(TreeNode treeNode)
{ {
try try
{ {
_Db.Insert(treeNode); _Db.Insert(treeNode);
return SQLite3.LastInsertRowid(_Db.Handle);
} }
catch (Exception e) catch (Exception e)
{ {
return Result.Error(e); return -1;
} }
}
private Boolean Create(Session session)
{
try
{
_Db.Insert(session);
return true;
}
catch (Exception e)
{
return false;
}
}
return Result.Ok;
}
// the U in CRUD // the U in CRUD
private Result Update(TreeNode treeNode) private Boolean Update(TreeNode treeNode)
{ {
try try
{ {
_Db.InsertOrReplace(treeNode); _Db.InsertOrReplace(treeNode);
return true;
} }
catch (Exception e) catch (Exception e)
{ {
return Result.Error(e); return false;
} }
return Result.Ok;
} }
// the D in CRUD // the D in CRUD
private Result Delete(TreeNode treeNode) private Boolean Delete(TreeNode treeNode)
{ {
try try
{ {
_Db.Delete(treeNode); _Db.Delete(treeNode);
return true;
} }
catch (Exception e) catch (Exception e)
{ {
return Result.Error(e); return false;
} }
return Result.Ok;
} }
public IEnumerable<Installation> GetAllAccessibleInstallations(User user) public IEnumerable<Installation> GetAllAccessibleInstallations(User user)
{ {
var direct = GetDirectlyAccessibleInstallations(user); var direct = GetDirectlyAccessibleInstallations(user);
var fromFolders = GetAllAccessibleFolders(user) var fromFolders = GetAllAccessibleFolders(user)
.SelectMany(GetChildInstallations); .SelectMany(GetChildInstallations);
return direct return direct
.Concat(fromFolders) .Concat(fromFolders)
.Distinct(); .Distinct();
} }
public IEnumerable<Folder> GetAllAccessibleFolders(User user) public IEnumerable<Folder> GetAllAccessibleFolders(User user)
{ {
return GetDirectlyAccessibleFolders(user) return GetDirectlyAccessibleFolders(user)
.SelectMany(GetDescendantFolders) .SelectMany(GetDescendantFolders)
.Distinct(); .Distinct();
// Distinct because the user might have direct access // Distinct because the user might have direct access
// to a child folder of a folder he has already access to // to a child folder of a folder he has already access to
} }
public IEnumerable<Installation> GetDirectlyAccessibleInstallations(User user) public IEnumerable<Installation> GetDirectlyAccessibleInstallations(User user)
{ {
return User2Installation return User2Installation
.Where(r => r.UserId == user.Id) .Where(r => r.UserId == user.Id)
.Select(r => r.InstallationId) .Select(r => r.InstallationId)
.Select(GetInstallationById) .Select(GetInstallationById)
.NotNull() .NotNull()
.Do(i => i.ParentId = 0); // hide inaccessible parents from calling user .Do(i => i.ParentId = 0); // hide inaccessible parents from calling user
} }
public IEnumerable<Folder> GetDirectlyAccessibleFolders(User user) public IEnumerable<Folder> GetDirectlyAccessibleFolders(User user)
{ {
return User2Folder return User2Folder
.Where(r => r.UserId == user.Id) .Where(r => r.UserId == user.Id)
.Select(r => r.FolderId) .Select(r => r.FolderId)
.Select(GetFolderById) .Select(GetFolderById)
.NotNull() .NotNull()
.Do(i => i.ParentId = 0); // hide inaccessible parents from calling user; .Do(i => i.ParentId = 0); // hide inaccessible parents from calling user;
} }
public Result AddToAccessibleInstallations(Int64 userId, Int64 updatedInstallationId) public Boolean AddToAccessibleInstallations(Int64 userId, Int64 updatedInstallationId)
{ {
var con = new User2Installation var con = new User2Installation
{ {
@ -139,17 +149,16 @@ public partial class Db : IDisposable
try try
{ {
_Db.InsertOrReplace(con); _Db.Insert(con);
return true;
} }
catch (Exception e) catch (Exception e)
{ {
return Result.Error(e); return false;
} }
return Result.Ok;
} }
public Result AddToAccessibleFolders(Int64 userId, Int64 updatedFolderId) public Boolean AddToAccessibleFolders(Int64 userId, Int64 updatedFolderId)
{ {
var con = new User2Folder var con = new User2Folder
{ {
@ -159,16 +168,14 @@ public partial class Db : IDisposable
try try
{ {
_Db.InsertOrReplace(con); _Db.Insert(con);
return true;
} }
catch (Exception e) catch (Exception e)
{ {
return Result.Error(e); return false;
} }
return Result.Ok;
} }
public User? GetUserByToken(String token) public User? GetUserByToken(String token)
@ -182,32 +189,19 @@ public partial class Db : IDisposable
} }
public Result NewSession(Session ses) public Boolean NewSession(Session ses) => Create(ses);
{
try
{
_Db.InsertOrReplace(ses);
}
catch (Exception e)
{
return Result.Error(e);
}
return Result.Ok; public Boolean DeleteSession(Int64 id)
}
public Result DeleteSession(Int64 id)
{ {
try try
{ {
Sessions.Delete(u => u.UserId == id); Sessions.Delete(u => u.UserId == id);
return true;
} }
catch (Exception e) catch (Exception e)
{ {
return Result.Error(e); return false;
} }
return Result.Ok;
} }
public Object? GetInstallationS3Key(Int64 installationId) public Object? GetInstallationS3Key(Int64 installationId)
@ -224,16 +218,4 @@ public partial class Db : IDisposable
Update(installation); Update(installation);
} }
} }
}
public Installation? GetInstallationByName(String installationName)
{
return Installations
.FirstOrDefault(installation => installation.Name == installationName);
}
public Int64 LastInsertRowId()
{
return _Db.;
}
}

View File

@ -46,31 +46,31 @@ public partial class Db
return parent.Traverse(GetChildUsers); return parent.Traverse(GetChildUsers);
} }
public Result CreateFolder(Folder folder) public Int64 CreateFolder(Folder folder)
{ {
return Create(folder); return Create(folder);
} }
public Result UpdateFolder(Folder folder) public Boolean UpdateFolder(Folder folder)
{ {
// TODO: no circles in path // TODO: no circles in path
return Update(folder); return Update(folder);
} }
public Result ChangeParent(Installation child, Int64 parentId) public Boolean ChangeParent(Installation child, Int64 parentId)
{ {
child.ParentId = parentId; child.ParentId = parentId;
return UpdateInstallation(child); return UpdateInstallation(child);
} }
public Result ChangeParent(Folder child, Int64 parentId) public Boolean ChangeParent(Folder child, Int64 parentId)
{ {
child.ParentId = parentId; child.ParentId = parentId;
return UpdateFolder(child); return UpdateFolder(child);
} }
public Result DeleteFolder(Folder folder) public Boolean DeleteFolder(Folder folder)
{ {
// Delete direct children // Delete direct children
User2Folder .Delete(f => f.FolderId == folder.Id); User2Folder .Delete(f => f.FolderId == folder.Id);

View File

@ -14,18 +14,18 @@ public partial class Db
public Installation? GetInstallationById(Int64 id) => Installations public Installation? GetInstallationById(Int64 id) => Installations
.FirstOrDefault(u => u.Id == id); .FirstOrDefault(u => u.Id == id);
public Result CreateInstallation(Installation installation) public Int64 CreateInstallation(Installation installation)
{ {
return Create(installation); return Create(installation);
} }
public Result UpdateInstallation(Installation installation) public Boolean UpdateInstallation(Installation installation)
{ {
return Update(installation); return Update(installation);
} }
public Result DeleteInstallation(Installation installation) public Boolean DeleteInstallation(Installation installation)
{ {
User2Installation.Delete(i => i.InstallationId == installation.Id); User2Installation.Delete(i => i.InstallationId == installation.Id);

View File

@ -1,16 +1,13 @@
using System.Diagnostics.CodeAnalysis;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Net.Mail; using System.Net.Mail;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Text.Json.Nodes; using System.Text.Json.Nodes;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Flurl.Http;
using InnovEnergy.App.Backend.Model; using InnovEnergy.App.Backend.Model;
using InnovEnergy.App.Backend.Utils; using InnovEnergy.App.Backend.Utils;
using InnovEnergy.Lib.Utils; using InnovEnergy.Lib.Utils;
using SQLite; using SQLite;
using ResponseExtensions = Flurl.Http.ResponseExtensions;
#pragma warning disable CS0472 #pragma warning disable CS0472
#pragma warning disable CS8602 #pragma warning disable CS8602
@ -53,10 +50,10 @@ public partial class Db
public User? GetUserByEmail(String email) => Users.FirstOrDefault(u => u.Email == email); public User? GetUserByEmail(String email) => Users.FirstOrDefault(u => u.Email == email);
public Object CreateUser(User user) public Int64 CreateUser(User user)
{ {
if (GetUserByEmail(user.Email) is not null) if (GetUserByEmail(user.Email) is not null)
return Result.Error("User with that email already exists"); return -1; // TODO: User with that email already exists
//Salting and Hashing password //Salting and Hashing password
var salt = Crypto.GenerateSalt(); var salt = Crypto.GenerateSalt();
@ -195,23 +192,23 @@ public partial class Db
return newKey; return newKey;
} }
public Result UpdateUser(User user) public Boolean UpdateUser(User user)
{ {
var oldUser = GetUserById(user.Id); var oldUser = GetUserById(user.Id);
if (oldUser == null) if (oldUser == null)
return Result.Error("User doesn't exist"); return false; // TODO: "User doesn't exist"
//Checking for unchangeable things //Checking for unchangeable things
// TODO: depends on privileges of caller // TODO: depends on privileges of caller
user.Id = oldUser.Id; user.Id = oldUser.Id;
user.ParentId = oldUser.ParentId; user.ParentId = oldUser.ParentId;
user.Email = oldUser.Email; user.Email = oldUser.Email;
return Update(user); return Update(user);
} }
public Result DeleteUser(User user) public Boolean DeleteUser(User user)
{ {
User2Folder.Delete(u => u.UserId == user.Id); User2Folder.Delete(u => u.UserId == user.Id);
User2Installation.Delete(u => u.UserId == user.Id); User2Installation.Delete(u => u.UserId == user.Id);

View File

@ -1,29 +0,0 @@
namespace InnovEnergy.App.Backend.Utils;
public class Result
{
private const String OkMsg = "Ok";
private readonly String _Error;
public static Result Ok = new Result(OkMsg);
public Boolean IsError => _Error != OkMsg;
public Boolean IsSuccess => _Error == OkMsg;
private Result(String error) => _Error = error;
public static Result Error(String error) => new Result(error);
public static Result Error(Exception exception)
{
#if DEBUG
var msg = exception.ToString(); // includes stacktrace
#else
var msg = exception.Message; // excludes stacktrace
#endif
return new Result(msg);
}
}

View File

@ -34,4 +34,11 @@ public readonly struct State : IReadOnlyList<String>
public Int32 Count => Values.Count; public Int32 Count => Values.Count;
public String this[Int32 index] => Values[index]; public String this[Int32 index] => Values[index];
}
public static State<T> From<T>(T t) where T : Enum
{
return new State<T>(t);
}
}

View File

@ -0,0 +1,27 @@
using System.Collections;
namespace InnovEnergy.Lib.Units;
public readonly struct State<T> : IReadOnlyList<T> where T:Enum
{
public IReadOnlyList<T> Values { get; }
public State(IReadOnlyList<T> values) => Values = values;
public State(params T[] values) : this((IReadOnlyList<T>)values){}
public State(params State<T>[] states) : this((IReadOnlyList<T>)states.SelectMany(s => s.Values).ToList()){}
public static implicit operator State<T>(T s) => new((IReadOnlyList<T>)s);
public static implicit operator State<T>(List<T> s) => new((IReadOnlyList<T>)s);
public static implicit operator State<T>(T[] s) => new((IReadOnlyList<T>)s);
public static State<T> operator |(State<T> left, State<T> right) => new State<T>(left, right);
public IEnumerator<T> GetEnumerator() => Values.GetEnumerator();
public override String ToString() => String.Join("; ", Values);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public Int32 Count => Values.Count;
public T this[Int32 index] => Values[index];
}