yea boy, now I got it!

This commit is contained in:
2024-05-28 15:18:27 +02:00
parent b08041204d
commit 991987bb6d
28 changed files with 396 additions and 312 deletions

View File

@@ -1,30 +0,0 @@
using OwnChar.Model;
using Pilz.Cryptography;
namespace OwnChar.Data.ClientServer
{
public class ClientServerDataProvider : IDataProvider
{
public UserAccount? CurrentUserAccount => throw new NotImplementedException();
public ClientServerDataProvider(string serverAddress)
{
throw new NotImplementedException();
}
public UserProfile? GetUserProfile(string username)
{
throw new NotImplementedException();
}
public UserAccount? Login(string username, SecureString password)
{
throw new NotImplementedException();
}
public bool Logout()
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,22 +1,29 @@
using OwnChar.Model; using OwnChar.Model;
using Pilz.Cryptography;
namespace OwnChar.Data namespace OwnChar.Data
{ {
public interface IDataProvider public interface IDataProvider
{ {
// Properties // General
public bool IsLoggedIn => CurrentUserAccount != null; abstract bool IsInitialized();
public UserProfile? CurrentUserProfile => CurrentUserAccount?.Profile;
// Properties (abstract) // Model
abstract UserAccount? CurrentUserAccount { get; } abstract T? Create<T>() where T : class, IOwnCharObject;
abstract bool Save<T>(T obj) where T : class, IOwnCharObject;
abstract bool Delete<T>(T obj) where T : class, IOwnCharObject;
// Methods (abstract) // Hierarchy
abstract UserAccount? Initialize(bool force); abstract bool SetParent(UserProfile profile, UserAccount parent);
abstract bool SetParent(Character character, Group parent);
abstract bool SetParent(Property property, Character character);
abstract bool SetOwner(Group group, UserProfile owner);
abstract bool SetOwner(Character group, UserProfile owner);
// Gets
abstract UserAccount? GetUserAccount(string username, string password);
abstract UserProfile? GetUserProfile(string username); abstract UserProfile? GetUserProfile(string username);
abstract UserAccount? Login(string username, string password); abstract IEnumerable<UserProfile> GetGroupMembers(Group group);
abstract bool Logout(); abstract UserProfile? GetOwner(Group group);
abstract UserAccount? CreateUser(string username, string password); abstract UserProfile? GetOwner(Character character);
} }
} }

View File

@@ -0,0 +1,19 @@
using OwnChar.Model;
namespace OwnChar.Data
{
public interface IDataProxy
{
// Login
abstract UserAccount? Login(string username, string password);
abstract bool Logout(UserAccount? account);
// User management
abstract UserAccount? CreateUserAccount(string username, string password);
abstract UserProfile? GetUserProfile(UserAccount account);
// Group management
abstract UserProfile? GetOwner(Group group);
abstract IEnumerable<UserProfile> GetMembers(Group group);
}
}

View File

@@ -1,14 +0,0 @@
using OwnChar.Model;
namespace OwnChar.Data.JsonFile
{
public class JsonFile
{
public List<UserAccount> UserAccounts { get; } = [];
public List<UserProfile> UserProfiles { get; } = [];
public List<Character> Characters { get; } = [];
public List<Group> Groups { get; } = [];
public List<Property> Properties { get; } = [];
public List<PropertyCategory> PropertyCategories { get; } = [];
}
}

View File

@@ -1,87 +0,0 @@
using Newtonsoft.Json;
using OwnChar.Model;
namespace OwnChar.Data.JsonFile
{
public class JsonFileDataProvider : IDataProvider
{
public JsonFile JsonFile { get; protected set; }
public string JsonFilePath { get; protected set; }
public UserAccount? CurrentUserAccount { get; protected set; }
public JsonFileDataProvider(string filePath)
{
JsonFilePath = filePath;
LoadFile();
// Get rid of bad compiler warnings
if (JsonFile == null)
throw new Exception("Something went incredible wrong at initialization of the JsonFile.");
}
public UserAccount? Initialize(bool force)
{
if (force || JsonFile.UserAccounts.Count == 0)
CreateUser("admin", "admin");
return CurrentUserAccount;
}
protected void LoadFile()
{
if (JsonConvert.DeserializeObject<JsonFile>(File.ReadAllText(JsonFilePath), CreateJsonSerializerSettings()) is JsonFile jsonFile)
JsonFile = jsonFile;
JsonFile ??= new();
CurrentUserAccount = Initialize(false);
}
protected void SaveFile()
{
File.WriteAllText(JsonFilePath, JsonConvert.SerializeObject(JsonFile, CreateJsonSerializerSettings()));
}
protected JsonSerializerSettings CreateJsonSerializerSettings()
{
return new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.All,
ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
TypeNameHandling = TypeNameHandling.Auto,
Formatting = Formatting.Indented,
};
}
public UserAccount? Login(string username, string password)
{
return CurrentUserAccount = JsonFile.UserAccounts.FirstOrDefault(n => !string.IsNullOrWhiteSpace(n.Username) && !string.IsNullOrWhiteSpace(n.Password) && n.Username == username && n.Password == password);
}
public bool Logout()
{
CurrentUserAccount = null;
return true;
}
public UserAccount? CreateUser(string username, string password)
{
var account = new UserAccount
{
Username = username,
Password = password,
Profile = new()
{
Name = username,
}
};
JsonFile.UserAccounts.Add(account);
JsonFile.UserProfiles.Add(account.Profile);
return account;
}
public UserProfile? GetUserProfile(string username)
{
return JsonFile.UserProfiles.FirstOrDefault(n => !string.IsNullOrWhiteSpace(n.Account?.Username) && n.Account.Username == username);
}
}
}

View File

@@ -0,0 +1,6 @@
namespace OwnChar.Data.Managers
{
public class ClientDataManager
{
}
}

View File

@@ -0,0 +1,73 @@
using OwnChar.Model;
namespace OwnChar.Data.Managers
{
public class DefaultDataManager : IDataProxy
{
public IDataProvider DataProvider { get; }
public DefaultDataManager(IDataProvider dataProvider)
{
DataProvider = dataProvider;
}
public UserAccount? CreateUserAccount(string username, string password)
{
var account = DataProvider.Create<UserAccount>();
var profile = DataProvider.Create<UserProfile>();
var group = DataProvider.Create<Group>();
ArgumentNullException.ThrowIfNull(account, nameof(account));
ArgumentNullException.ThrowIfNull(profile, nameof(profile));
ArgumentNullException.ThrowIfNull(group, nameof(group));
account.Username = username;
account.Password = password;
profile.Name = username;
DataProvider.SetParent(profile, account);
group.IsInternal = true;
DataProvider.SetOwner(group, profile);
DataProvider.Save(account);
DataProvider.Save(profile);
DataProvider.Save(group);
return account;
}
public IEnumerable<UserProfile> GetMembers(Group group)
{
return DataProvider.GetGroupMembers(group);
}
public UserProfile? GetOwner(Group group)
{
return DataProvider.GetOwner(group);
}
public UserProfile? GetUserProfile(UserAccount account)
{
ArgumentException.ThrowIfNullOrWhiteSpace(account.Username, nameof(account.Username));
return DataProvider.GetUserProfile(account.Username);
}
public UserAccount? Login(string username, string password)
{
return DataProvider.GetUserAccount(username, password);
}
public bool Logout(UserAccount? account)
{
return true;
}
public bool Initialize(bool force)
{
if (force || !DataProvider.IsInitialized())
return CreateUserAccount("admin", "admin") != null;
return true;
}
}
}

View File

@@ -0,0 +1,12 @@
using OwnChar.Data.Providers.JsonFile.Model;
using OwnChar.Model;
namespace OwnChar.Data.Providers.JsonFile
{
public class JsonFile
{
public List<JsonUserAccount> UserAccounts { get; } = [];
public List<JsonCharacter> Characters { get; } = [];
public List<JsonGroup> Groups { get; } = [];
}
}

View File

@@ -0,0 +1,148 @@
using Newtonsoft.Json;
using OwnChar.Data.Providers.JsonFile.Model;
using OwnChar.Model;
namespace OwnChar.Data.Providers.JsonFile
{
public class JsonFileDataProvider : IDataProvider
{
public JsonFile JsonFile { get; protected set; }
public string JsonFilePath { get; protected set; }
public JsonFileDataProvider(string filePath)
{
JsonFilePath = filePath;
LoadFile();
// Get rid of bad compiler warnings
if (JsonFile == null)
throw new Exception("Something went incredible wrong at initialization of the JsonFile.");
}
protected void LoadFile()
{
if (JsonConvert.DeserializeObject<JsonFile>(File.ReadAllText(JsonFilePath), CreateJsonSerializerSettings()) is JsonFile jsonFile)
JsonFile = jsonFile;
JsonFile ??= new();
}
protected void SaveFile()
{
File.WriteAllText(JsonFilePath, JsonConvert.SerializeObject(JsonFile, CreateJsonSerializerSettings()));
}
protected JsonSerializerSettings CreateJsonSerializerSettings()
{
return new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.All,
ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
TypeNameHandling = TypeNameHandling.Auto,
Formatting = Formatting.Indented,
};
}
public T? Create<T>() where T : class, IOwnCharObject
{
var t = typeof(T);
IOwnCharObject? obj;
if (t == typeof(Property))
obj = new JsonProp();
else if (t == typeof(PropertyCategory))
obj = new JsonPropCat();
else if (t == typeof(Character))
obj = new JsonCharacter();
else if (t == typeof(Group))
obj = new JsonGroup();
else if (t == typeof(UserAccount))
obj = new JsonUserAccount();
else if (t == typeof(UserProfile))
obj = new JsonUserProfile();
else
obj = null;
return obj as T;
}
public bool Save<T>(T obj) where T : class, IOwnCharObject
{
if (obj is JsonCharacter character)
{
if (!JsonFile.Characters.Contains(character))
JsonFile.Characters.Add(character);
}
else if (obj is JsonGroup group)
{
if (!JsonFile.Groups.Contains(group))
JsonFile.Groups.Add(group);
}
else if(obj is JsonUserAccount account)
{
if (!JsonFile.UserAccounts.Contains(account))
JsonFile.UserAccounts.Add(account);
}
return true;
}
public bool IsInitialized()
{
return JsonFile.UserAccounts.Count != 0;
}
bool IDataProvider.Delete<T>(T obj)
{
throw new NotImplementedException();
}
public bool SetParent(UserProfile profile, UserAccount parent)
{
throw new NotImplementedException();
}
public bool SetParent(Character character, Group parent)
{
throw new NotImplementedException();
}
public bool SetParent(Property property, Character character)
{
throw new NotImplementedException();
}
public bool SetOwner(Group group, UserProfile owner)
{
throw new NotImplementedException();
}
public bool SetOwner(Character group, UserProfile owner)
{
throw new NotImplementedException();
}
public UserAccount? GetUserAccount(string username, string password)
{
throw new NotImplementedException();
}
public UserProfile? GetUserProfile(string username)
{
throw new NotImplementedException();
}
public IEnumerable<UserProfile> GetGroupMembers(Group group)
{
throw new NotImplementedException();
}
public UserProfile? GetOwner(Group group)
{
throw new NotImplementedException();
}
public UserProfile? GetOwner(Character character)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,10 @@
using OwnChar.Model;
namespace OwnChar.Data.Providers.JsonFile.Model
{
public class JsonCharacter : Character
{
public List<JsonProp> Properties { get; } = [];
public List<JsonPropCat> PropertyCategories { get; } = [];
}
}

View File

@@ -0,0 +1,11 @@
using OwnChar.Model;
namespace OwnChar.Data.Providers.JsonFile.Model
{
public class JsonGroup : Group
{
public List<JsonUserProfile> Owner { get; } = [];
public List<JsonUserProfile> Members { get; } = [];
public List<JsonCharacter> Characters { get; } = [];
}
}

View File

@@ -0,0 +1,9 @@
using OwnChar.Model;
namespace OwnChar.Data.Providers.JsonFile.Model
{
public class JsonProp : Property
{
public JsonPropCat? Category { get; set; } = null;
}
}

View File

@@ -0,0 +1,8 @@
using OwnChar.Model;
namespace OwnChar.Data.Providers.JsonFile.Model
{
public class JsonPropCat : PropertyCategory
{
}
}

View File

@@ -0,0 +1,9 @@
using OwnChar.Model;
namespace OwnChar.Data.Providers.JsonFile.Model
{
public class JsonUserAccount : UserAccount
{
public JsonUserProfile? Profile { get; set; }
}
}

View File

@@ -0,0 +1,8 @@
using OwnChar.Model;
namespace OwnChar.Data.Providers.JsonFile.Model
{
public class JsonUserProfile : UserProfile
{
}
}

View File

@@ -1,54 +1,7 @@
using OwnChar.Model; namespace OwnChar.Manager
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OwnChar.Manager
{ {
public class CharacterManager(OwnCharManager manager) public class CharacterManager(OwnCharManager manager)
{ {
public OwnCharManager Manager { get; } = manager; public OwnCharManager Manager { get; } = manager;
/// <summary>
/// Gets all personal characters (private & within groups).
/// </summary>
/// <param name="group"></param>
/// <returns>Returns a collection with personal characters.</returns>
public IEnumerable<Character>? GetCharacters()
{
if (!IsLoggedIn || UserProfile == null)
return null;
return GetCharacters(Manager.CurrentUser);
}
/// <summary>
/// Gets all public ore accessable (e.g. via shares) characters from the specified group.
/// </summary>
/// <param name="group"></param>
/// <returns>Returns a collection with characters for the specified group.</returns>
public IEnumerable<Character> GetCharacters(Group group)
{
}
/// <summary>
/// Saves a character. If it doesn't exists, it will be created.
/// </summary>
/// <param name="character">The caracter to save.</param>
/// <returns><see cref="true"/> if success, otherwise <see cref="false"/>.</returns>
public bool SaveCharacter(Character character)
{
}
/// <summary>
/// Deletes a given character. If it doesn't exists, it will be ignored.
/// </summary>
/// <param name="character"></param>
/// <returns><see cref="true"/> if the given character has been deleted successfully or doesn't exist, otherwise <see cref="false"/>.</returns>
public bool DeleteCharacter(Character character)
{
}
} }
} }

View File

@@ -1,9 +1,4 @@
using OwnChar.Model; using OwnChar.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OwnChar.Manager namespace OwnChar.Manager
{ {
@@ -11,40 +6,16 @@ namespace OwnChar.Manager
{ {
public OwnCharManager Manager { get; } = manager; public OwnCharManager Manager { get; } = manager;
public Group? GetGroup() public UserProfile? GetOwner(Group? group)
{ {
if (!IsLoggedIn || UserProfile == null) ArgumentNullException.ThrowIfNull(group, nameof(group));
return null; return Manager.DataProxy?.GetOwner(group);
// ...
} }
public IEnumerable<Group>? GetGroups() public IEnumerable<UserProfile>? GetMembers(Group? group)
{
if (!IsLoggedIn || UserProfile == null)
return null;
return GetGroups(UserProfile);
}
public IEnumerable<Group>? GetGroups(UserProfile profile)
{
if (!IsLoggedIn)
return null;
// ...
}
public Group? CreateGroup(UserProfile owner)
{
}
public bool SaveGroup(Group group)
{
}
public bool DeleteGroup(Group group)
{ {
ArgumentNullException.ThrowIfNull(group, nameof(group));
return Manager.DataProxy?.GetMembers(group);
} }
} }
} }

View File

@@ -8,11 +8,11 @@ namespace OwnChar.Manager
public class OwnCharManager public class OwnCharManager
{ {
// User // User
public bool IsLoggedIn => DataProvider != null && DataProvider.IsLoggedIn; public bool IsLoggedIn => CurrentUser != null;
public UserAccount? CurrentUser => DataProvider?.CurrentUserAccount; public UserAccount? CurrentUser { get; private set; }
// Data Provider // Data Provider
public IDataProvider? DataProvider { get; set; } public IDataProxy? DataProxy { get; set; }
// Manager // Manager
public UserManager Users { get; } public UserManager Users { get; }
@@ -26,7 +26,7 @@ namespace OwnChar.Manager
Characters = new(this); Characters = new(this);
} }
private void CheckLogin() internal protected void CheckLogin()
{ {
if (!IsLoggedIn) if (!IsLoggedIn)
throw new LoginException("You are already logged in!"); throw new LoginException("You are already logged in!");
@@ -36,11 +36,15 @@ namespace OwnChar.Manager
/// Tries to login on the given data provider. /// Tries to login on the given data provider.
/// </summary> /// </summary>
/// <returns>Returns <see cref="true"/> if the login was successfull and <see cref="false"/> if not.</returns> /// <returns>Returns <see cref="true"/> if the login was successfull and <see cref="false"/> if not.</returns>
public bool Login(IDataProvider? dataProvider, string username, SecureString password) public bool Login(IDataProxy? proxy, string? username, SecureString? password)
{ {
CheckLogin(); ArgumentNullException.ThrowIfNull(proxy, nameof(proxy));
ArgumentNullException.ThrowIfNull(dataProvider); ArgumentException.ThrowIfNullOrWhiteSpace(username, nameof(username));
return dataProvider.Login(username, password) != null; ArgumentException.ThrowIfNullOrWhiteSpace(password, nameof(password));
CurrentUser = proxy.Login(username, password);
return IsLoggedIn;
} }
/// <summary> /// <summary>
@@ -49,9 +53,7 @@ namespace OwnChar.Manager
/// <returns></returns> /// <returns></returns>
public bool Logout() public bool Logout()
{ {
if (DataProvider != null) return DataProxy?.Logout(CurrentUser) ?? true;
return DataProvider.Logout();
return true;
} }
} }
} }

View File

@@ -1,5 +1,4 @@
using OwnChar.Model; using OwnChar.Model;
using Pilz.Cryptography;
namespace OwnChar.Manager namespace OwnChar.Manager
{ {
@@ -7,50 +6,17 @@ namespace OwnChar.Manager
{ {
public OwnCharManager Manager { get; } = manager; public OwnCharManager Manager { get; } = manager;
public UserProfile? GetUserProfile(UserAccount account) public UserProfile? GetOwnUserProfile(UserAccount account)
{ {
Manager.CheckLogin();
return Manager.DataProxy!.GetUserProfile(Manager.CurrentUser!);
} }
public UserAccount? CreateAccount(string username, SecureString password, string email, string displayName) public UserAccount? CreateUserAccount(string? username, string? password)
{
// Create account
// ...
// Create profile
// ...
}
/// <summary>
/// Saves the current logged in user account.
/// </summary>
/// <returns><see cref="true"/> if success, otherwise <see cref="false"/>.</returns>
public bool SaveAccount()
{
}
public bool DeleteAccount()
{
}
public UserProfile? CreateProfile()
{
// Create profile
// ...
// Create pre-defined group
// ...
}
/// <summary>
/// Saves the current logged in user profile.
/// </summary>
/// <returns><see cref="true"/> if success, otherwise <see cref="false"/>.</returns>
public bool SaveProfile()
{
}
public bool DeleteProfile()
{ {
ArgumentException.ThrowIfNullOrWhiteSpace(username, nameof(username));
ArgumentException.ThrowIfNullOrWhiteSpace(password, nameof(password));
return Manager.DataProxy?.CreateUserAccount(username, password);
} }
} }
} }

View File

@@ -1,11 +1,7 @@
namespace OwnChar.Model namespace OwnChar.Model
{ {
public class Character(Group group, string name) public abstract class Character : IOwnCharObject
{ {
public ulong Id { get; set; } public virtual string? Name { get; set; }
public string Name { get; set; } = name;
public Group Group { get; set; } = group;
public List<Property> Properties { get; set; } = [];
public List<PropertyCategory> PropertyCategories { get; set; } = [];
} }
} }

View File

@@ -1,15 +1,8 @@
using System; namespace OwnChar.Model
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OwnChar.Model
{ {
public class Group(UserProfile owner) public abstract class Group : IOwnCharObject
{ {
public int Id { get; set; } public virtual string? Name { get; set; }
public UserProfile Owner { get; set; } = owner; public virtual bool IsInternal { get; set; }
public List<UserProfile> Members { get; set; } = [];
} }
} }

View File

@@ -0,0 +1,6 @@
namespace OwnChar.Model
{
public interface IOwnCharObject
{
}
}

View File

@@ -1,10 +1,8 @@
namespace OwnChar.Model namespace OwnChar.Model
{ {
public class Property(string name) public abstract class Property : IOwnCharObject
{ {
public ulong Id { get; set; } public virtual string? Name { get; set; }
public string Name { get; set; } = name; public virtual object? Value { get; set; }
public PropertyCategory? Category { get; set; }
public object? Value { get; set; }
} }
} }

View File

@@ -1,8 +1,7 @@
namespace OwnChar.Model namespace OwnChar.Model
{ {
public class PropertyCategory(string name) public abstract class PropertyCategory : IOwnCharObject
{ {
public ulong Id { get; set; } public virtual string? Name { get; set; }
public string Name { get; set; } = name;
} }
} }

View File

@@ -1,11 +1,9 @@
namespace OwnChar.Model namespace OwnChar.Model
{ {
public class UserAccount public abstract class UserAccount : IOwnCharObject
{ {
public ulong Id { get; set; } public virtual string? Username { get; set; }
public string? Username { get; set; } public virtual string? Password { get; set; }
public string? Password { get; set; } public virtual string? Email { get; set; }
public string? Email { get; set; }
public UserProfile? Profile { get; set; }
} }
} }

View File

@@ -1,9 +1,7 @@
namespace OwnChar.Model namespace OwnChar.Model
{ {
public class UserProfile public abstract class UserProfile : IOwnCharObject
{ {
public ulong Id { get; set; } public virtual string? Name { get; set; }
public string? Name { get; set; }
public UserAccount? Account { get; set; }
} }
} }

View File

@@ -10,4 +10,8 @@
<PackageReference Include="Pilz.Cryptography" Version="2.0.1" /> <PackageReference Include="Pilz.Cryptography" Version="2.0.1" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Data\Providers\SqlDb\" />
</ItemGroup>
</Project> </Project>

11
OwnChar/Utils.cs Normal file
View File

@@ -0,0 +1,11 @@
namespace OwnChar
{
public static class Utils
{
public static string HashPassword(string username, string password)
{
// TODO: Implement a good hasing algorythmus (like MD5) BEFORE going productive!
return (username + ":" + password).GetHashCode().ToString();
}
}
}