Compare commits
13 Commits
342c6dfcb2
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32a8a3ec38 | ||
|
|
f268058cdc | ||
| 6b5445ccdf | |||
| 24708eb798 | |||
|
|
b08c7619a4 | ||
|
|
db5191b0b8 | ||
| 38dc09ab12 | |||
| 32708e3e26 | |||
| 986bc3853c | |||
|
|
a721b5ab6c | ||
|
|
bd0053cc03 | ||
|
|
9e77090bd4 | ||
|
|
f1deeeda6c |
5
OwnChar/Api/Clients/CharactersApiClient.cs
Normal file
5
OwnChar/Api/Clients/CharactersApiClient.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
namespace OwnChar.Api.Clients;
|
||||||
|
|
||||||
|
internal class CharactersApiClient(OwnCharApiClient client) : ICharactersApiClient
|
||||||
|
{
|
||||||
|
}
|
||||||
43
OwnChar/Api/Clients/GroupsApiClient.cs
Normal file
43
OwnChar/Api/Clients/GroupsApiClient.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using OwnChar.Api.Packets.General;
|
||||||
|
using OwnChar.Api.Packets.Groups;
|
||||||
|
using OwnChar.Data.Model.Client;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Clients;
|
||||||
|
|
||||||
|
internal class GroupsApiClient(IOwnCharApiClient client) : IGroupsApiClient
|
||||||
|
{
|
||||||
|
public async Task<Group?> GetGroup(long id)
|
||||||
|
{
|
||||||
|
var result = await client.SendRequest<GetSingleObjectResponse<Group>>("/groups/get/byid", new GetSinlgeObjectRequest(id));
|
||||||
|
result.EnsureOk();
|
||||||
|
return result.Message.Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Group>> GetGroupsForProfile(long userProfileId)
|
||||||
|
{
|
||||||
|
var result = await client.SendRequest<GetGroupsResponse>("/groups/get", new GetGroupsRequest
|
||||||
|
{
|
||||||
|
ProfileId = userProfileId,
|
||||||
|
UseProfileId = true,
|
||||||
|
});
|
||||||
|
result.EnsureOk();
|
||||||
|
return result.Message.Groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Group>> GetPublicGroups()
|
||||||
|
{
|
||||||
|
var result = await client.SendRequest<GetGroupsResponse>("/groups/get", new GetGroupsRequest());
|
||||||
|
result.EnsureOk();
|
||||||
|
return result.Message.Groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Group>> GetAllGroups()
|
||||||
|
{
|
||||||
|
var result = await client.SendRequest<GetGroupsResponse>("/groups/get", new GetGroupsRequest
|
||||||
|
{
|
||||||
|
IncludeNonPublic = true,
|
||||||
|
});
|
||||||
|
result.EnsureOk();
|
||||||
|
return result.Message.Groups;
|
||||||
|
}
|
||||||
|
}
|
||||||
5
OwnChar/Api/Clients/ICharactersApiClient.cs
Normal file
5
OwnChar/Api/Clients/ICharactersApiClient.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
namespace OwnChar.Api.Clients;
|
||||||
|
|
||||||
|
public interface ICharactersApiClient
|
||||||
|
{
|
||||||
|
}
|
||||||
10
OwnChar/Api/Clients/IGroupsApiClient.cs
Normal file
10
OwnChar/Api/Clients/IGroupsApiClient.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using OwnChar.Data.Model.Client;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Clients;
|
||||||
|
public interface IGroupsApiClient
|
||||||
|
{
|
||||||
|
Task<IEnumerable<Group>> GetAllGroups();
|
||||||
|
Task<Group?> GetGroup(long id);
|
||||||
|
Task<IEnumerable<Group>> GetGroupsForProfile(long userProfileId);
|
||||||
|
Task<IEnumerable<Group>> GetPublicGroups();
|
||||||
|
}
|
||||||
9
OwnChar/Api/Clients/ILoginApiClient.cs
Normal file
9
OwnChar/Api/Clients/ILoginApiClient.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using OwnChar.Data.Model.Client;
|
||||||
|
using Pilz.Cryptography;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Clients;
|
||||||
|
public interface ILoginApiClient
|
||||||
|
{
|
||||||
|
Task<UserProfile?> Login(string username, SecureString password);
|
||||||
|
Task<bool> Logout();
|
||||||
|
}
|
||||||
11
OwnChar/Api/Clients/IUsersApiClient.cs
Normal file
11
OwnChar/Api/Clients/IUsersApiClient.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Clients;
|
||||||
|
|
||||||
|
public interface IUsersApiClient
|
||||||
|
{
|
||||||
|
}
|
||||||
30
OwnChar/Api/Clients/LoginApiClient.cs
Normal file
30
OwnChar/Api/Clients/LoginApiClient.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using OwnChar.Api.Packets.General;
|
||||||
|
using OwnChar.Data.Model.Client;
|
||||||
|
using Pilz.Cryptography;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Clients;
|
||||||
|
|
||||||
|
internal class LoginApiClient(OwnCharApiClient client) : ILoginApiClient
|
||||||
|
{
|
||||||
|
public async Task<UserProfile?> Login(string username, SecureString password)
|
||||||
|
{
|
||||||
|
var result = await client.SendRequest<LoginResponse>("/auth/login", new LoginRequest(username, password));
|
||||||
|
result.EnsureOk();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(result.Message.Secret) && result.Message.Profile != null && result.Message.Account != null)
|
||||||
|
{
|
||||||
|
client.AuthKey = result.Message.Secret;
|
||||||
|
client.CurrentUser = result.Message.Account;
|
||||||
|
return result.Message.Profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> Logout()
|
||||||
|
{
|
||||||
|
var res = await client.SendRequest("/auth/logout");
|
||||||
|
client.AuthKey = null;
|
||||||
|
return res.IsOk;
|
||||||
|
}
|
||||||
|
}
|
||||||
5
OwnChar/Api/Clients/UsersApiClient.cs
Normal file
5
OwnChar/Api/Clients/UsersApiClient.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
namespace OwnChar.Api.Clients;
|
||||||
|
|
||||||
|
internal class UsersApiClient(IOwnCharApiClient client) : IUsersApiClient
|
||||||
|
{
|
||||||
|
}
|
||||||
29
OwnChar/Api/Endpoint/CharactersApi.cs
Normal file
29
OwnChar/Api/Endpoint/CharactersApi.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
namespace OwnChar.Api.Endpoint;
|
||||||
|
|
||||||
|
internal class CharactersApi(IOwnCharApiServer server)
|
||||||
|
{
|
||||||
|
private IResult GetCharacter(long characterId)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private IResult CreateGroupCharacter(string name, long groupId)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private IResult CreateUserCharacter(string name, long userId)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private IResult UpdateCharacter(long characterId)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private IResult DeleteCharacter(long characterId)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
184
OwnChar/Api/Endpoint/GroupsApi.cs
Normal file
184
OwnChar/Api/Endpoint/GroupsApi.cs
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
using OwnChar.Api.Packets.General;
|
||||||
|
using OwnChar.Api.Packets.Groups;
|
||||||
|
using OwnChar.Api.Updates;
|
||||||
|
using OwnChar.Data;
|
||||||
|
using OwnChar.Data.Model.Client;
|
||||||
|
using OwnChar.Data.Model.Server;
|
||||||
|
using OwnChar.Server.Extensions;
|
||||||
|
using Pilz.Net.Api;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Endpoint;
|
||||||
|
|
||||||
|
internal class GroupsApi(IOwnCharApiServer server)
|
||||||
|
{
|
||||||
|
[MessageHandler("/group/get/byid")]
|
||||||
|
public ApiResult GetById(GetSinlgeObjectRequest request, ApiRequestInfo info)
|
||||||
|
{
|
||||||
|
if (!server.CheckLogin(info, UserType.Guest, out UserAccountDb? user))
|
||||||
|
return ApiResult.Unauthorized();
|
||||||
|
|
||||||
|
if (server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Id == request.ObjectId && n.Members.Any(m => m.User != null && m.User.Id == user.Id)) is not GroupDb group)
|
||||||
|
return ApiResult.NotFound();
|
||||||
|
|
||||||
|
return ApiResult.Ok(new GetSingleObjectResponse<Group>(group.ToClient()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MessageHandler("/group/get", RequiesAuth = true)]
|
||||||
|
public ApiResult Get(GetGroupsRequest request, ApiRequestInfo info)
|
||||||
|
{
|
||||||
|
if (!server.CheckLogin(info, UserType.Guest, out UserAccountDb? user))
|
||||||
|
return ApiResult.Unauthorized();
|
||||||
|
|
||||||
|
IQueryable<GroupDb> groups;
|
||||||
|
|
||||||
|
if (request.UseProfileId && server.Data!.Set<UserProfileDb>().FirstOrDefault(p => p.Id == request.ProfileId) is UserProfileDb profile)
|
||||||
|
groups = server.Data!.Set<GroupDb>().Where(group => group.Members.Any(m => m.User != null && m.User.Id == profile.Id));
|
||||||
|
else if (request.IncludeNonPublic && user.Is(UserType.Admin))
|
||||||
|
groups = server.Data!.Set<GroupDb>();
|
||||||
|
else
|
||||||
|
groups = Array.Empty<GroupDb>().AsQueryable(); // Currently not supported.
|
||||||
|
|
||||||
|
return ApiResult.Ok(new GetGroupsResponse([.. groups.Select(g => g.ToClient())]));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MessageHandler("/group/create", RequiesAuth = true)]
|
||||||
|
public ApiResult Create(CreateGroupRequest request, ApiRequestInfo info)
|
||||||
|
{
|
||||||
|
if (!server.CheckLogin(info, UserType.User, out UserAccountDb? user))
|
||||||
|
return ApiResult.Unauthorized();
|
||||||
|
|
||||||
|
var group = new GroupDb();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(request.Name))
|
||||||
|
group.Name = request.Name;
|
||||||
|
|
||||||
|
group.Members.Add(new()
|
||||||
|
{
|
||||||
|
User = user.Profile,
|
||||||
|
Level = MemberLevel.Owner,
|
||||||
|
});
|
||||||
|
|
||||||
|
server.Data!.Update(group);
|
||||||
|
server.Data.SaveChanges();
|
||||||
|
|
||||||
|
return ApiResult.Ok(new CreateGroupResponse(group.ToClient()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MessageHandler("/group/update", RequiesAuth = true)]
|
||||||
|
public ApiResult Update(UpdateRequest request, ApiRequestInfo info)
|
||||||
|
{
|
||||||
|
if (!server.CheckLogin(info, UserType.User, out UserAccountDb? user)
|
||||||
|
|| server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Id == request.Update.Id) is not GroupDb group
|
||||||
|
|| !group.Members.Any(m => m.Id == user.Profile!.Id && m.Level >= MemberLevel.Admin
|
||||||
|
|| user.IsNot(UserType.Admin)))
|
||||||
|
return ApiResult.Unauthorized();
|
||||||
|
|
||||||
|
if (request.Update is not GroupUpdate update)
|
||||||
|
return ApiResult.NotFound();
|
||||||
|
|
||||||
|
group.Name = update.Name;
|
||||||
|
group.Fandom = update.Fandom;
|
||||||
|
|
||||||
|
server.Data.Update(group);
|
||||||
|
server.Data.SaveChanges();
|
||||||
|
|
||||||
|
return ApiResult.Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MessageHandler("/group/delete", RequiesAuth = true)]
|
||||||
|
public ApiResult Delete(DeleteObjectRequest request, ApiRequestInfo info)
|
||||||
|
{
|
||||||
|
if (!server.CheckLogin(info, UserType.User, out UserAccountDb? user)
|
||||||
|
|| server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Id == request.ObjectId) is not GroupDb group
|
||||||
|
|| !group.Members.Any(m => m.Id == user.Profile!.Id && m.Level >= MemberLevel.Owner)
|
||||||
|
|| user.IsNot(UserType.Admin))
|
||||||
|
return ApiResult.Unauthorized();
|
||||||
|
|
||||||
|
server.Data.Remove(group);
|
||||||
|
server.Data.SaveChanges();
|
||||||
|
|
||||||
|
return ApiResult.Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MessageHandler("/group/members/get", RequiesAuth = true)]
|
||||||
|
public ApiResult GetMembers(GetGroupMembersRequest request, ApiRequestInfo info)
|
||||||
|
{
|
||||||
|
if (!server.CheckLogin(info, UserType.User, out UserAccountDb? user)
|
||||||
|
|| server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Id == request.GroupId) is not GroupDb group
|
||||||
|
|| !group.Members.Any(m => m.Id == user.Profile!.Id && m.Level >= MemberLevel.Member)
|
||||||
|
|| user.IsNot(UserType.Admin))
|
||||||
|
return ApiResult.Unauthorized();
|
||||||
|
|
||||||
|
var members = group.Members.Select(n => n.ToClient());
|
||||||
|
return ApiResult.Ok(new GetGroupMembersResponse(members.ToList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MessageHandler("/group/members/add", RequiesAuth = true)]
|
||||||
|
public ApiResult AddMembers(GroupMemberAddRequest request, ApiRequestInfo info)
|
||||||
|
{
|
||||||
|
if (!server.CheckLogin(info, UserType.User, out UserAccountDb? user)
|
||||||
|
|| server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Id == request.GroupId) is not GroupDb group
|
||||||
|
|| !group.Members.Any(m => m.Id == user.Profile!.Id && m.Level >= MemberLevel.Admin)
|
||||||
|
|| user.IsNot(UserType.Admin))
|
||||||
|
return ApiResult.Unauthorized();
|
||||||
|
|
||||||
|
var addedMembers = new List<MemberEntryDb>();
|
||||||
|
|
||||||
|
foreach (var kvp in request.Members)
|
||||||
|
{
|
||||||
|
if (group.Members.FirstOrDefault(m => m.User != null && m.User.Id == kvp.Key) is not MemberEntryDb member
|
||||||
|
&& server.Data.Set<UserProfileDb>().FirstOrDefault(u => u.Id == kvp.Key) is UserProfileDb mu)
|
||||||
|
{
|
||||||
|
member = new()
|
||||||
|
{
|
||||||
|
User = mu,
|
||||||
|
Level = kvp.Value,
|
||||||
|
};
|
||||||
|
server.Data.Update(member);
|
||||||
|
server.Data.Update(group);
|
||||||
|
server.Data.SaveChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ApiResult.Ok(new GroupMemberAddResponse(addedMembers.Select(m => m.ToClient()).ToList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MessageHandler("/group/members/update", RequiesAuth = true)]
|
||||||
|
public ApiResult UpdateMember(UpdateRequest request, ApiRequestInfo info)
|
||||||
|
{
|
||||||
|
if (!server.CheckLogin(info, UserType.User, out UserAccountDb? user)
|
||||||
|
|| server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Id == request.Update.Id) is not GroupDb group
|
||||||
|
|| group.Members.FirstOrDefault(m => m.Id == request.Update.Id) is not MemberEntryDb member
|
||||||
|
|| !group.Members.Any(m => m.Id == user.Profile!.Id && m.Level >= MemberLevel.Admin
|
||||||
|
|| user.IsNot(UserType.Admin)))
|
||||||
|
return ApiResult.Unauthorized();
|
||||||
|
|
||||||
|
if (request.Update is not MemberUpdate update)
|
||||||
|
return ApiResult.NotFound();
|
||||||
|
|
||||||
|
member.Level = update.Level;
|
||||||
|
|
||||||
|
server.Data.Update(member);
|
||||||
|
server.Data.SaveChanges();
|
||||||
|
|
||||||
|
return ApiResult.Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MessageHandler("/group/members/remove", RequiesAuth = true)]
|
||||||
|
public ApiResult RemoveMembers(DeleteObjectRequest request, ApiRequestInfo info)
|
||||||
|
{
|
||||||
|
if (!server.CheckLogin(info, UserType.User, out UserAccountDb? user)
|
||||||
|
|| server.Data?.Set<MemberEntryDb>().FirstOrDefault(m => m.Id == request.ObjectId) is not MemberEntryDb member
|
||||||
|
|| server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Members.Contains(member)) is not GroupDb group
|
||||||
|
|| !group.Members.Any(m => m.Id == user.Profile!.Id && m.Level >= MemberLevel.Admin
|
||||||
|
|| user.IsNot(UserType.Admin)))
|
||||||
|
return ApiResult.Unauthorized();
|
||||||
|
|
||||||
|
group.Members.Remove(member);
|
||||||
|
server.Data.Remove(member);
|
||||||
|
server.Data.Update(group);
|
||||||
|
server.Data.SaveChanges();
|
||||||
|
|
||||||
|
return ApiResult.Ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
30
OwnChar/Api/Endpoint/LoginApi.cs
Normal file
30
OwnChar/Api/Endpoint/LoginApi.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using OwnChar.Api.Packets;
|
||||||
|
using OwnChar.Api.Packets.General;
|
||||||
|
using OwnChar.Data.Model.Server;
|
||||||
|
using OwnChar.Server.Extensions;
|
||||||
|
using Pilz.Net.Api;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Endpoint;
|
||||||
|
|
||||||
|
internal class LoginApi(OwnCharApiServer server)
|
||||||
|
{
|
||||||
|
[MessageHandler("/auth/login")]
|
||||||
|
public ApiResult Login(LoginRequest request, ApiRequestInfo info)
|
||||||
|
{
|
||||||
|
if (server.Data?.Set<UserAccountDb>()?.FirstOrDefault(n => n.Username == request.Username && n.Password == request.Password) is UserAccountDb acc && acc.Profile != null)
|
||||||
|
{
|
||||||
|
if (info.IsAuthenticated)
|
||||||
|
server.Logout(info.AuthKey);
|
||||||
|
return ApiResult.Ok(new LoginResponse(acc.ToClient(), acc.Profile.ToClient(), server.Login(acc)));
|
||||||
|
}
|
||||||
|
return ApiResult.NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MessageHandler("/auth/logout")]
|
||||||
|
public ApiResult Logout(ApiRequestInfo info)
|
||||||
|
{
|
||||||
|
if (info.IsAuthenticated)
|
||||||
|
server.Logout(info.AuthKey);
|
||||||
|
return ApiResult.Ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
39
OwnChar/Api/Endpoint/UsersApi.cs
Normal file
39
OwnChar/Api/Endpoint/UsersApi.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
namespace OwnChar.Api.Endpoint;
|
||||||
|
|
||||||
|
internal class UsersApi(IOwnCharApiServer server)
|
||||||
|
{
|
||||||
|
private IResult GetUsers()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private IResult GetUser(long userId)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private IResult GetUserProfile(long userId)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private IResult CreateUser(string username, string password)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private IResult DeleteUser(long userId)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private IResult UpdateUserPassword(long userId, string username, string password)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private IResult UpdateUserProfile(long profileId, string displayName)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
5
OwnChar/Api/Exceptions/ApiException.cs
Normal file
5
OwnChar/Api/Exceptions/ApiException.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
namespace OwnChar.Api.Exceptions;
|
||||||
|
|
||||||
|
public class ApiException(string message) : Exception(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using OwnChar.Model;
|
|
||||||
|
|
||||||
namespace OwnChar.Api;
|
|
||||||
public interface ICharacterManager
|
|
||||||
{
|
|
||||||
Character? CreateCharacter(string? name);
|
|
||||||
Character? CreateCharacter(string? name, Group? destination);
|
|
||||||
bool DeleteCharacter(Character? character);
|
|
||||||
IEnumerable<Character>? GetCharacters(Group? group);
|
|
||||||
IEnumerable<Character>? GetCharacters(UserProfile? profile);
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
using OwnChar.Data;
|
|
||||||
using OwnChar.Model;
|
|
||||||
|
|
||||||
namespace OwnChar.Api;
|
|
||||||
|
|
||||||
public interface IDataManager
|
|
||||||
{
|
|
||||||
public delegate void OnActionEventHandler(object sender, OnActionEventArgs e);
|
|
||||||
public delegate void OnCallbackEventHandler(object sender, OnCallbackEventArgs e);
|
|
||||||
|
|
||||||
event OnActionEventHandler? OnAction;
|
|
||||||
event OnCallbackEventHandler? OnCallback;
|
|
||||||
// Login
|
|
||||||
UserAccount? Login(string username, string password);
|
|
||||||
bool Logout(UserAccount? account);
|
|
||||||
|
|
||||||
// Action
|
|
||||||
DataManagerActionResult ExecuteAction(DataManagerAction action, DataManagerActionType actionType, UserAccount currentUser, object? obj, params object?[] parameters);
|
|
||||||
|
|
||||||
//// User management
|
|
||||||
//UserProfile? GetUserProfile(UserAccount account);
|
|
||||||
|
|
||||||
//// Group management
|
|
||||||
//UserProfile? GetOwner(UserAccount account, Group group);
|
|
||||||
//IEnumerable<UserProfile>? GetMembers(UserAccount account, Group group);
|
|
||||||
//bool AddMember(UserAccount account, Group group, UserProfile user);
|
|
||||||
//bool RemoveMember(UserAccount account, Group group, UserProfile user);
|
|
||||||
|
|
||||||
//// Character management
|
|
||||||
//UserProfile? GetOwner(UserAccount account, Character group);
|
|
||||||
//IEnumerable<Character>? GetCharacters(UserAccount account, Group group);
|
|
||||||
//IEnumerable<Character>? GetCharacters(UserAccount account, UserProfile profile);
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
using OwnChar.Model;
|
|
||||||
|
|
||||||
namespace OwnChar.Api;
|
|
||||||
|
|
||||||
public interface IDataProvider
|
|
||||||
{
|
|
||||||
bool IsInitialized();
|
|
||||||
void SetInitialized();
|
|
||||||
bool SaveDatabase();
|
|
||||||
|
|
||||||
// Model
|
|
||||||
abstract T? Create<T>() where T : OwnCharObject;
|
|
||||||
abstract bool Save<T>(T obj) where T : OwnCharObject;
|
|
||||||
abstract bool Delete<T>(T obj) where T : OwnCharObject;
|
|
||||||
|
|
||||||
// Hierarchy
|
|
||||||
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 IEnumerable<UserProfile>? GetMembers(Group group);
|
|
||||||
abstract UserProfile? GetOwner(Group group);
|
|
||||||
abstract UserProfile? GetOwner(Character character);
|
|
||||||
abstract IEnumerable<Character>? GetCharacters(Group group);
|
|
||||||
abstract IEnumerable<Character>? GetCharacters(UserProfile jprofile);
|
|
||||||
|
|
||||||
// Sets
|
|
||||||
abstract bool AddMember(Group group, UserProfile user);
|
|
||||||
abstract bool RemoveMember(Group group, UserProfile user);
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using OwnChar.Model;
|
|
||||||
|
|
||||||
namespace OwnChar.Api;
|
|
||||||
public interface IGroupsManager
|
|
||||||
{
|
|
||||||
bool AddMember(UserProfile? profile, Group? group);
|
|
||||||
Group? CreateGroup(string? name);
|
|
||||||
bool DeleteGroup(Group? group);
|
|
||||||
bool DeleteMember(UserProfile? profile, Group? group);
|
|
||||||
IEnumerable<UserProfile>? GetMembers(Group? group);
|
|
||||||
UserProfile? GetOwner(Group? group);
|
|
||||||
}
|
|
||||||
21
OwnChar/Api/IOwnCharApiClient.cs
Normal file
21
OwnChar/Api/IOwnCharApiClient.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using OwnChar.Api.Clients;
|
||||||
|
using OwnChar.Data.Model.Client;
|
||||||
|
using Pilz.Net.Api;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace OwnChar.Api;
|
||||||
|
public interface IOwnCharApiClient : IApiClient
|
||||||
|
{
|
||||||
|
UserAccount? CurrentUser { get; }
|
||||||
|
|
||||||
|
[MemberNotNullWhen(true, nameof(AuthKey), nameof(CurrentUser))]
|
||||||
|
bool IsLoggedIn { get; }
|
||||||
|
|
||||||
|
ILoginApiClient Auth { get; }
|
||||||
|
|
||||||
|
IGroupsApiClient Groups { get; }
|
||||||
|
|
||||||
|
ICharactersApiClient Characters { get; }
|
||||||
|
|
||||||
|
IUsersApiClient Users { get; }
|
||||||
|
}
|
||||||
20
OwnChar/Api/IOwnCharApiServer.cs
Normal file
20
OwnChar/Api/IOwnCharApiServer.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using OwnChar.Data.Model.Base;
|
||||||
|
using Pilz.Net.Api;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace OwnChar.Api;
|
||||||
|
|
||||||
|
public interface IOwnCharApiServer : IApiServer
|
||||||
|
{
|
||||||
|
DbContext? Data { get; }
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(Data))]
|
||||||
|
void CheckLogin(string secret);
|
||||||
|
|
||||||
|
[MemberNotNullWhen(true, nameof(Data))]
|
||||||
|
bool IsLoggedIn(string secret);
|
||||||
|
|
||||||
|
[MemberNotNullWhen(true, nameof(Data))]
|
||||||
|
UserAccountBase? GetUser(string secret);
|
||||||
|
}
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
using OwnChar.Model;
|
|
||||||
using Pilz.Cryptography;
|
|
||||||
|
|
||||||
namespace OwnChar.Api;
|
|
||||||
public interface IOwnCharManager
|
|
||||||
{
|
|
||||||
IDataManager? DataManager { get; set; }
|
|
||||||
UserAccount? CurrentUser { get; }
|
|
||||||
bool IsLoggedIn { get; }
|
|
||||||
|
|
||||||
IUserManager Users { get; }
|
|
||||||
IGroupsManager Groups { get; }
|
|
||||||
ICharacterManager Characters { get; }
|
|
||||||
|
|
||||||
bool Login(IDataManager? proxy, string? username, SecureString? password);
|
|
||||||
bool Logout();
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
using OwnChar.Model;
|
|
||||||
using Pilz.Cryptography;
|
|
||||||
|
|
||||||
namespace OwnChar.Api;
|
|
||||||
public interface IUserManager
|
|
||||||
{
|
|
||||||
UserAccount? CreateUserAccount(string? username, SecureString? password);
|
|
||||||
bool DeleteUserAccount(UserAccount? account);
|
|
||||||
UserProfile? GetOwnUserProfile();
|
|
||||||
}
|
|
||||||
38
OwnChar/Api/OwnCharApiClient.cs
Normal file
38
OwnChar/Api/OwnCharApiClient.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using OwnChar.Api.Clients;
|
||||||
|
using OwnChar.Data.Model.Client;
|
||||||
|
using Pilz.Cryptography;
|
||||||
|
using Pilz.Net.Api;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace OwnChar.Api;
|
||||||
|
|
||||||
|
internal class OwnCharApiClient : ApiClient, IOwnCharApiClient
|
||||||
|
{
|
||||||
|
public UserAccount? CurrentUser { get; internal set; }
|
||||||
|
|
||||||
|
[MemberNotNullWhen(true, nameof(AuthKey), nameof(CurrentUser))]
|
||||||
|
public bool IsLoggedIn => CurrentUser != null && !string.IsNullOrWhiteSpace(AuthKey);
|
||||||
|
|
||||||
|
public ILoginApiClient Auth { get; }
|
||||||
|
|
||||||
|
public IGroupsApiClient Groups { get; }
|
||||||
|
|
||||||
|
public ICharactersApiClient Characters { get; }
|
||||||
|
|
||||||
|
public IUsersApiClient Users { get; }
|
||||||
|
|
||||||
|
public OwnCharApiClient(string apiUrl) : base(apiUrl)
|
||||||
|
{
|
||||||
|
Auth = new LoginApiClient(this);
|
||||||
|
Groups = new GroupsApiClient(this);
|
||||||
|
Characters = new CharactersApiClient(this);
|
||||||
|
Users = new UsersApiClient(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string? EncodeAuthKey()
|
||||||
|
{
|
||||||
|
if (IsLoggedIn && !string.IsNullOrWhiteSpace(CurrentUser.Username))
|
||||||
|
return new SecureString($"{CurrentUser}:{AuthKey}", false).EncryptedValue;
|
||||||
|
return AuthKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
89
OwnChar/Api/OwnCharApiServer.cs
Normal file
89
OwnChar/Api/OwnCharApiServer.cs
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using OwnChar.Api;
|
||||||
|
using OwnChar.Api.Endpoint;
|
||||||
|
using OwnChar.Data.Model.Base;
|
||||||
|
using OwnChar.Server.Data;
|
||||||
|
using Pilz.Cryptography;
|
||||||
|
using Pilz.Extensions.Collections;
|
||||||
|
using Pilz.Net.Api;
|
||||||
|
|
||||||
|
namespace OwnChar.Api;
|
||||||
|
|
||||||
|
internal class OwnCharApiServer(string apiUrl, string dbServer, string dbDatabase, string dbUser, SecureString dbPassword) : ApiServer(apiUrl), IOwnCharApiServer
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, UserAccountBase> users = [];
|
||||||
|
|
||||||
|
public DbContext? Data { get; private set; }
|
||||||
|
|
||||||
|
public override void Start()
|
||||||
|
{
|
||||||
|
Log.Info("Prepairing server");
|
||||||
|
|
||||||
|
// Load database
|
||||||
|
Log.Debug("Loading database");
|
||||||
|
Data = new DatabaseContext(dbServer, dbDatabase, dbUser, dbPassword);
|
||||||
|
|
||||||
|
// Built-in endpoints
|
||||||
|
Log.Debug("Loading internal api endpoints");
|
||||||
|
RegisterHandler(new LoginApi(this));
|
||||||
|
RegisterHandler(new UsersApi(this));
|
||||||
|
RegisterHandler(new GroupsApi(this));
|
||||||
|
RegisterHandler(new CharactersApi(this));
|
||||||
|
|
||||||
|
// Run server
|
||||||
|
Log.Info("Starting webserver");
|
||||||
|
base.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string? DecodeAuthKey(string authKey)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(authKey))
|
||||||
|
return new SecureString(authKey, true).Value;
|
||||||
|
return authKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool CheckAuthentication(string authKey)
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(authKey)
|
||||||
|
|| authKey.Split(":") is not string[] authKeyParts
|
||||||
|
|| authKey.Length != 2
|
||||||
|
|| string.IsNullOrWhiteSpace(authKeyParts[0])
|
||||||
|
|| string.IsNullOrWhiteSpace(authKeyParts[1])
|
||||||
|
|| !IsLoggedIn(authKeyParts[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Login(UserAccountBase account)
|
||||||
|
{
|
||||||
|
var secret = new UniquieID(UniquieIDGenerationMode.GenerateOnInit).ID;
|
||||||
|
users.Add(secret, account);
|
||||||
|
Log.DebugFormat("Logged-in out user with secret {0}", secret);
|
||||||
|
return secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Logout(string secret)
|
||||||
|
{
|
||||||
|
users.Remove(secret);
|
||||||
|
Log.DebugFormat("Logged-out user with secret {0}", secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsLoggedIn(string secret)
|
||||||
|
{
|
||||||
|
Log.DebugFormat("Deleting user with secret {0}", secret);
|
||||||
|
return users.ContainsKey(secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CheckLogin(string secret)
|
||||||
|
{
|
||||||
|
Log.DebugFormat("Checking login for user with secret {0}", secret);
|
||||||
|
if (!IsLoggedIn(secret))
|
||||||
|
throw new UnauthorizedAccessException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserAccountBase? GetUser(string secret)
|
||||||
|
{
|
||||||
|
Log.DebugFormat("Getting user with secret {0}", secret);
|
||||||
|
if (users.TryGetValue(secret, out UserAccountBase? value))
|
||||||
|
return value;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
8
OwnChar/Api/Packets/General/DeleteObjectRequest.cs
Normal file
8
OwnChar/Api/Packets/General/DeleteObjectRequest.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using OwnChar.Api.Packets;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets.General;
|
||||||
|
|
||||||
|
public class DeleteObjectRequest(long objectId) : OwnCharRequest
|
||||||
|
{
|
||||||
|
public long ObjectId { get; } = objectId;
|
||||||
|
}
|
||||||
9
OwnChar/Api/Packets/General/GetSingleObjectResponse.cs
Normal file
9
OwnChar/Api/Packets/General/GetSingleObjectResponse.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using OwnChar.Api.Packets;
|
||||||
|
using OwnChar.Data;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets.General;
|
||||||
|
|
||||||
|
public class GetSingleObjectResponse<T>(T? result) : OwnCharResponse where T : OwnCharObject
|
||||||
|
{
|
||||||
|
public T? Result { get; } = result;
|
||||||
|
}
|
||||||
8
OwnChar/Api/Packets/General/GetSinlgeObjectRequest.cs
Normal file
8
OwnChar/Api/Packets/General/GetSinlgeObjectRequest.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using OwnChar.Api.Packets;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets.General;
|
||||||
|
|
||||||
|
public class GetSinlgeObjectRequest(long objectId) : OwnCharRequest
|
||||||
|
{
|
||||||
|
public long ObjectId { get; } = objectId;
|
||||||
|
}
|
||||||
10
OwnChar/Api/Packets/General/LoginRequest.cs
Normal file
10
OwnChar/Api/Packets/General/LoginRequest.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using OwnChar.Api.Packets;
|
||||||
|
using Pilz.Cryptography;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets.General;
|
||||||
|
|
||||||
|
public class LoginRequest(string username, SecureString password) : OwnCharRequest
|
||||||
|
{
|
||||||
|
public new string Username { get; set; } = username;
|
||||||
|
public SecureString Password { get; } = password;
|
||||||
|
}
|
||||||
11
OwnChar/Api/Packets/General/LoginResponse.cs
Normal file
11
OwnChar/Api/Packets/General/LoginResponse.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using OwnChar.Api.Packets;
|
||||||
|
using OwnChar.Data.Model.Client;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets.General;
|
||||||
|
|
||||||
|
public class LoginResponse(UserAccount? account, UserProfile? profile, string? secret) : OwnCharResponse
|
||||||
|
{
|
||||||
|
public UserAccount? Account { get; } = account;
|
||||||
|
public UserProfile? Profile { get; } = profile;
|
||||||
|
public string? Secret { get; } = secret;
|
||||||
|
}
|
||||||
7
OwnChar/Api/Packets/General/SetOwnerRequest.cs
Normal file
7
OwnChar/Api/Packets/General/SetOwnerRequest.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace OwnChar.Api.Packets.General;
|
||||||
|
|
||||||
|
public class SetOwnerRequest : OwnCharRequest
|
||||||
|
{
|
||||||
|
public long ObjectId { get; set; }
|
||||||
|
public bool Enforce { get; set; }
|
||||||
|
}
|
||||||
9
OwnChar/Api/Packets/General/UpdateRequest.cs
Normal file
9
OwnChar/Api/Packets/General/UpdateRequest.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using OwnChar.Api.Packets;
|
||||||
|
using OwnChar.Api.Updates;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets.General;
|
||||||
|
|
||||||
|
public class UpdateRequest(OwnCharObjectUpdate update) : OwnCharRequest
|
||||||
|
{
|
||||||
|
public OwnCharObjectUpdate Update { get; } = update;
|
||||||
|
}
|
||||||
8
OwnChar/Api/Packets/Groups/CreateGroupRequest.cs
Normal file
8
OwnChar/Api/Packets/Groups/CreateGroupRequest.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using OwnChar.Api.Packets;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets.Groups;
|
||||||
|
|
||||||
|
public class CreateGroupRequest : OwnCharRequest
|
||||||
|
{
|
||||||
|
public string? Name { get; set; }
|
||||||
|
}
|
||||||
9
OwnChar/Api/Packets/Groups/CreateGroupResponse.cs
Normal file
9
OwnChar/Api/Packets/Groups/CreateGroupResponse.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using OwnChar.Api.Packets;
|
||||||
|
using OwnChar.Data.Model.Client;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets.Groups;
|
||||||
|
|
||||||
|
public class CreateGroupResponse(Group? group) : OwnCharResponse
|
||||||
|
{
|
||||||
|
public Group? Group { get; } = group;
|
||||||
|
}
|
||||||
8
OwnChar/Api/Packets/Groups/GetGroupMembersRequest.cs
Normal file
8
OwnChar/Api/Packets/Groups/GetGroupMembersRequest.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using OwnChar.Api.Packets;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets.Groups;
|
||||||
|
|
||||||
|
public class GetGroupMembersRequest(long groupId) : OwnCharRequest
|
||||||
|
{
|
||||||
|
public long GroupId { get; } = groupId;
|
||||||
|
}
|
||||||
9
OwnChar/Api/Packets/Groups/GetGroupMembersResponse.cs
Normal file
9
OwnChar/Api/Packets/Groups/GetGroupMembersResponse.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using OwnChar.Data;
|
||||||
|
using OwnChar.Data.Model.Client;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets.Groups;
|
||||||
|
|
||||||
|
public class GetGroupMembersResponse(List<MemberEntry> members) : OwnCharResponse
|
||||||
|
{
|
||||||
|
public List<MemberEntry> Members { get; } = members;
|
||||||
|
}
|
||||||
10
OwnChar/Api/Packets/Groups/GetGroupsRequest.cs
Normal file
10
OwnChar/Api/Packets/Groups/GetGroupsRequest.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using OwnChar.Api.Packets;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets.Groups;
|
||||||
|
|
||||||
|
public class GetGroupsRequest : OwnCharRequest
|
||||||
|
{
|
||||||
|
public long ProfileId { get; set; } = -1;
|
||||||
|
public bool UseProfileId { get; set; }
|
||||||
|
public bool IncludeNonPublic { get; set; }
|
||||||
|
}
|
||||||
9
OwnChar/Api/Packets/Groups/GetGroupsResponse.cs
Normal file
9
OwnChar/Api/Packets/Groups/GetGroupsResponse.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using OwnChar.Api.Packets;
|
||||||
|
using OwnChar.Data.Model.Client;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets.Groups;
|
||||||
|
|
||||||
|
public class GetGroupsResponse(List<Group> groups) : OwnCharResponse
|
||||||
|
{
|
||||||
|
public List<Group> Groups { get; } = groups;
|
||||||
|
}
|
||||||
9
OwnChar/Api/Packets/Groups/GroupMemberAddRequest.cs
Normal file
9
OwnChar/Api/Packets/Groups/GroupMemberAddRequest.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using OwnChar.Data;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets.Groups;
|
||||||
|
|
||||||
|
public class GroupMemberAddRequest() : OwnCharRequest
|
||||||
|
{
|
||||||
|
public long GroupId { get; set; } = -1;
|
||||||
|
public Dictionary<long, MemberLevel> Members { get; set; } = [];
|
||||||
|
}
|
||||||
8
OwnChar/Api/Packets/Groups/GroupMemberAddResponse.cs
Normal file
8
OwnChar/Api/Packets/Groups/GroupMemberAddResponse.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using OwnChar.Data.Model.Client;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets.Groups;
|
||||||
|
|
||||||
|
public class GroupMemberAddResponse(List<MemberEntry> addedMembers) : OwnCharResponse
|
||||||
|
{
|
||||||
|
public List<MemberEntry> AddedMembers { get; } = addedMembers;
|
||||||
|
}
|
||||||
7
OwnChar/Api/Packets/OwnCharRequest.cs
Normal file
7
OwnChar/Api/Packets/OwnCharRequest.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
using Pilz.Net.Api;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets;
|
||||||
|
|
||||||
|
public class OwnCharRequest : ApiMessage
|
||||||
|
{
|
||||||
|
}
|
||||||
7
OwnChar/Api/Packets/OwnCharResponse.cs
Normal file
7
OwnChar/Api/Packets/OwnCharResponse.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
using Pilz.Net.Api;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets;
|
||||||
|
|
||||||
|
public class OwnCharResponse : ApiMessage
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using OwnChar.Api.Packets;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets.UserProfiles;
|
||||||
|
|
||||||
|
public class GetUserProfileRequest(long userProfileId) : OwnCharRequest
|
||||||
|
{
|
||||||
|
public long UserProfileId { get; } = userProfileId;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using OwnChar.Api.Packets;
|
||||||
|
using OwnChar.Data.Model.Client;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets.UserProfiles;
|
||||||
|
|
||||||
|
public class GetUserProfileResponse(UserProfile? profile) : OwnCharResponse
|
||||||
|
{
|
||||||
|
public UserProfile? Profile { get; } = profile;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using OwnChar.Api.Packets;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets.UserProfiles;
|
||||||
|
|
||||||
|
public class GetUserProfilesRequest : OwnCharRequest
|
||||||
|
{
|
||||||
|
public bool AllProfiles { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using OwnChar.Api.Packets;
|
||||||
|
using OwnChar.Data.Model.Client;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Packets.UserProfiles;
|
||||||
|
|
||||||
|
public class GetUserProfilesResponse(List<UserProfile> profiles) : OwnCharResponse
|
||||||
|
{
|
||||||
|
public List<UserProfile> Profiles { get; } = profiles;
|
||||||
|
}
|
||||||
19
OwnChar/Api/Updates/GroupUpdate.cs
Normal file
19
OwnChar/Api/Updates/GroupUpdate.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using OwnChar.Data.Model.Client;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Updates;
|
||||||
|
|
||||||
|
public class GroupUpdate : OwnCharObjectUpdate
|
||||||
|
{
|
||||||
|
public string? Name { get; set; }
|
||||||
|
public string? Fandom { get; set; }
|
||||||
|
|
||||||
|
public GroupUpdate() : base()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupUpdate(Group group) : base(group)
|
||||||
|
{
|
||||||
|
Name = group.Name;
|
||||||
|
Fandom = group.Fandom;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
OwnChar/Api/Updates/MemberUpdate.cs
Normal file
9
OwnChar/Api/Updates/MemberUpdate.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using OwnChar.Data;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Updates;
|
||||||
|
|
||||||
|
public class MemberUpdate : OwnCharObjectUpdate
|
||||||
|
{
|
||||||
|
public long GroupId { get; set; }
|
||||||
|
public MemberLevel Level { get; set; }
|
||||||
|
}
|
||||||
17
OwnChar/Api/Updates/OwnCharObjectUpdate.cs
Normal file
17
OwnChar/Api/Updates/OwnCharObjectUpdate.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using OwnChar.Data;
|
||||||
|
|
||||||
|
namespace OwnChar.Api.Updates;
|
||||||
|
|
||||||
|
public abstract class OwnCharObjectUpdate
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
public OwnCharObjectUpdate()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public OwnCharObjectUpdate(OwnCharObject obj) : this()
|
||||||
|
{
|
||||||
|
Id = obj.Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
3
OwnChar/AssemblyInfo.cs
Normal file
3
OwnChar/AssemblyInfo.cs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
[assembly: InternalsVisibleTo("OwnChar.Server")]
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
namespace OwnChar.Data;
|
|
||||||
|
|
||||||
public class DataManagerAction(string id)
|
|
||||||
{
|
|
||||||
public DataManagerAction? BaseAction { get; }
|
|
||||||
|
|
||||||
public string ActionId
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (BaseAction != null)
|
|
||||||
return $"{BaseAction.ActionId}.{id}";
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public DataManagerAction(DataManagerAction baseAction, string id) : this(id)
|
|
||||||
{
|
|
||||||
BaseAction = baseAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator ==(DataManagerAction? a, DataManagerAction? b)
|
|
||||||
{
|
|
||||||
if (a is null || b is null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (a.ActionId == b.ActionId)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (a.BaseAction != null && a.BaseAction.ActionId == b.ActionId)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (b.BaseAction != null && a.ActionId == b.BaseAction.ActionId)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator !=(DataManagerAction? a, DataManagerAction? b)
|
|
||||||
{
|
|
||||||
return !(a == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
|
||||||
{
|
|
||||||
if (ReferenceEquals(this, obj))
|
|
||||||
return true;
|
|
||||||
if (obj is not DataManagerAction action)
|
|
||||||
return false;
|
|
||||||
return action == this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return ActionId.GetHashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace OwnChar.Data;
|
|
||||||
|
|
||||||
public record class DataManagerActionResult(bool HasSuccess, object? Result)
|
|
||||||
{
|
|
||||||
public static DataManagerActionResult NonSuccess { get; } = new(false, null);
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace OwnChar.Data;
|
|
||||||
|
|
||||||
public enum DataManagerActionType
|
|
||||||
{
|
|
||||||
Default,
|
|
||||||
Get,
|
|
||||||
Set,
|
|
||||||
Delete,
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
namespace OwnChar.Data;
|
|
||||||
|
|
||||||
public static class DataManagerActions
|
|
||||||
{
|
|
||||||
public static DataManagerAction Get { get; } = new("get");
|
|
||||||
public static DataManagerAction Save { get; } = new("save");
|
|
||||||
public static DataManagerAction Delete { get; } = new("delete");
|
|
||||||
public static DataManagerAction Associate { get; } = new("associate");
|
|
||||||
|
|
||||||
public static class Getter
|
|
||||||
{
|
|
||||||
public static DataManagerAction UserAccount { get; } = new(Get, "useraccount");
|
|
||||||
public static DataManagerAction Group { get; } = new(Get, "group");
|
|
||||||
public static DataManagerAction Character { get; } = new(Get, "character");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Association
|
|
||||||
{
|
|
||||||
public static DataManagerAction Owner { get; } = new(Associate, "owner");
|
|
||||||
public static DataManagerAction Parent { get; } = new(Associate, "parent");
|
|
||||||
public static DataManagerAction Members { get; } = new(Associate, "members");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,315 +0,0 @@
|
|||||||
using OwnChar.Api;
|
|
||||||
using OwnChar.Model;
|
|
||||||
|
|
||||||
namespace OwnChar.Data.Managers;
|
|
||||||
|
|
||||||
public class DefaultDataManager : IDataManager
|
|
||||||
{
|
|
||||||
public event IDataManager.OnActionEventHandler? OnAction;
|
|
||||||
public event IDataManager.OnCallbackEventHandler? OnCallback;
|
|
||||||
|
|
||||||
private const string defaultUsername = "admin";
|
|
||||||
private const string defaultPassword = "admin";
|
|
||||||
|
|
||||||
public IDataProvider DataProvider { get; }
|
|
||||||
|
|
||||||
public DefaultDataManager(IDataProvider dataProvider)
|
|
||||||
{
|
|
||||||
DataProvider = dataProvider;
|
|
||||||
Initialize(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual DataManagerActionResult ExecuteAction(DataManagerAction action, DataManagerActionType actionType, UserAccount currentUser, object? obj, params object?[] parameters)
|
|
||||||
{
|
|
||||||
var success = false;
|
|
||||||
var e = new OnActionEventArgs(action, actionType, currentUser, obj, parameters);
|
|
||||||
OnAction?.Invoke(this, e);
|
|
||||||
|
|
||||||
if (e.IsHandled)
|
|
||||||
return new(true, e.Result);
|
|
||||||
|
|
||||||
if (HandleGet(e)
|
|
||||||
|| HandleDelete(e)
|
|
||||||
|| HandleSave(e)
|
|
||||||
|| HandleAssociation(e))
|
|
||||||
success = true;
|
|
||||||
|
|
||||||
OnCallback?.Invoke(this, new(action, actionType, success, e.Result));
|
|
||||||
|
|
||||||
return new(success, e.Result);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual bool HandleGet(OnActionEventArgs e)
|
|
||||||
{
|
|
||||||
if (!e.Is(DataManagerActions.Get))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Character
|
|
||||||
if (e.Is(DataManagerActions.Getter.Character))
|
|
||||||
{
|
|
||||||
// Get
|
|
||||||
if (e.Is(DataManagerActionType.Set))
|
|
||||||
{
|
|
||||||
if (e.Object is Group group && e.GetParam(0, out string? name))
|
|
||||||
return e.SetResult(CreateCharacter(e.CurrentUser, name, group));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Group
|
|
||||||
if (e.Is(DataManagerActions.Getter.Group))
|
|
||||||
{
|
|
||||||
// Get
|
|
||||||
if (e.Is(DataManagerActionType.Get))
|
|
||||||
{
|
|
||||||
if (e.GetParam(0, out string? name))
|
|
||||||
return e.SetResult(CreateGroup(e.CurrentUser, name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// User
|
|
||||||
if (e.Is(DataManagerActions.Getter.UserAccount))
|
|
||||||
{
|
|
||||||
// Get
|
|
||||||
if (e.Is(DataManagerActionType.Get))
|
|
||||||
{
|
|
||||||
if (e.GetParam(0, out string? username) && e.GetParam(1, out string? password))
|
|
||||||
return e.SetResult(CreateUserAccount(username, password));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create
|
|
||||||
//else if (e.ActionType == DataManagerActionType.Set(
|
|
||||||
// return e.SetResult(DataProvider.GetUserAccounts());
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual bool HandleSave(OnActionEventArgs e)
|
|
||||||
{
|
|
||||||
if (!e.Is(DataManagerActions.Save))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// ...
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual bool HandleDelete(OnActionEventArgs e)
|
|
||||||
{
|
|
||||||
if (!e.Is(DataManagerActions.Delete))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Character
|
|
||||||
if (e.Object is Character character)
|
|
||||||
return DeleteCharacter(e.CurrentUser, character);
|
|
||||||
|
|
||||||
// Group
|
|
||||||
if (e.Object is Group group)
|
|
||||||
return DeleteGroup(e.CurrentUser, group);
|
|
||||||
|
|
||||||
// User
|
|
||||||
if (e.Object is UserAccount userAccount)
|
|
||||||
return DeleteUserAccount(userAccount);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual bool HandleAssociation(OnActionEventArgs e)
|
|
||||||
{
|
|
||||||
if (!e.Is(DataManagerActions.Associate))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (e.Is(DataManagerActions.Association.Owner))
|
|
||||||
{
|
|
||||||
if (e.Object is Group group)
|
|
||||||
{
|
|
||||||
switch (e.ActionType)
|
|
||||||
{
|
|
||||||
case DataManagerActionType.Get:
|
|
||||||
return e.SetResultT(DataProvider.GetOwner(group));
|
|
||||||
case DataManagerActionType.Set:
|
|
||||||
if (e.GetParam(0, out UserProfile? profile))
|
|
||||||
return DataProvider.SetOwner(group, profile);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.Object is Character character)
|
|
||||||
{
|
|
||||||
switch (e.ActionType)
|
|
||||||
{
|
|
||||||
case DataManagerActionType.Get:
|
|
||||||
return e.SetResultT(DataProvider.GetOwner(character));
|
|
||||||
case DataManagerActionType.Set:
|
|
||||||
if (e.GetParam(0, out UserProfile? profile))
|
|
||||||
return DataProvider.SetOwner(character, profile);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<UserProfile>? GetMembers(UserAccount account, Group group)
|
|
||||||
{
|
|
||||||
if (!account.HasPermission(UserType.Guest))
|
|
||||||
return null;
|
|
||||||
return DataProvider.GetMembers(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserProfile? GetOwner(UserAccount account, Group group)
|
|
||||||
{
|
|
||||||
if (!account.HasPermission(UserType.Guest))
|
|
||||||
return null;
|
|
||||||
return DataProvider.GetOwner(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserProfile? GetOwner(UserAccount account, Character character)
|
|
||||||
{
|
|
||||||
if (!account.HasPermission(UserType.Guest))
|
|
||||||
return null;
|
|
||||||
return DataProvider.GetOwner(character);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (account != null && account.HasPermission(UserType.User))
|
|
||||||
DataProvider.SaveDatabase();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Initialize(bool force)
|
|
||||||
{
|
|
||||||
var result = false;
|
|
||||||
|
|
||||||
if (force || !DataProvider.IsInitialized())
|
|
||||||
{
|
|
||||||
result = CreateUserAccount(defaultUsername, Utils.HashPassword(defaultUsername, defaultPassword)) != null;
|
|
||||||
DataProvider.SetInitialized();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual bool DeleteUserAccount(UserAccount account)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(account.Username) && DataProvider.GetUserProfile(account.Username) is UserProfile userProfile)
|
|
||||||
userProfile.Name = "Deleted user";
|
|
||||||
DataProvider.Delete(account);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<Character>? GetCharacters(UserAccount account, Group group)
|
|
||||||
{
|
|
||||||
if (!account.HasPermission(UserType.Guest))
|
|
||||||
return null;
|
|
||||||
return DataProvider.GetCharacters(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<Character>? GetCharacters(UserAccount account, UserProfile profile)
|
|
||||||
{
|
|
||||||
if (!account.HasPermission(UserType.Guest))
|
|
||||||
return null;
|
|
||||||
return DataProvider.GetCharacters(profile);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool AddMember(UserAccount account, Group group, UserProfile user)
|
|
||||||
{
|
|
||||||
if (GetUserProfile(account) is not UserProfile profile || DataProvider.GetOwner(group) is not UserProfile owner || !account.HasPermission(profile == owner ? UserType.User : UserType.Admin))
|
|
||||||
return false;
|
|
||||||
return DataProvider.AddMember(group, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool RemoveMember(UserAccount account, Group group, UserProfile user)
|
|
||||||
{
|
|
||||||
if (GetUserProfile(account) is not UserProfile profile || DataProvider.GetOwner(group) is not UserProfile owner || !account.HasPermission(profile == owner ? UserType.User : UserType.Admin))
|
|
||||||
return false;
|
|
||||||
return DataProvider.RemoveMember(group, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual Group? CreateGroup(UserAccount account, string name)
|
|
||||||
{
|
|
||||||
if (!account.HasPermission(UserType.User) || GetUserProfile(account) is not UserProfile profile || DataProvider.Create<Group>() is not Group group)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
group.Name = name;
|
|
||||||
|
|
||||||
DataProvider.Save(group);
|
|
||||||
|
|
||||||
DataProvider.SetOwner(group, profile);
|
|
||||||
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual bool DeleteGroup(UserAccount account, Group group)
|
|
||||||
{
|
|
||||||
if (GetUserProfile(account) is not UserProfile profile || DataProvider.GetOwner(group) is not UserProfile owner || !account.HasPermission(profile == owner ? UserType.User : UserType.Admin))
|
|
||||||
return false;
|
|
||||||
return DataProvider.Delete(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual Character? CreateCharacter(UserAccount account, string name, Group? group)
|
|
||||||
{
|
|
||||||
if (!account.HasPermission(UserType.User) || GetUserProfile(account) is not UserProfile profile || DataProvider.Create<Character>() is not Character character)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
character.Name = name;
|
|
||||||
|
|
||||||
DataProvider.Save(character);
|
|
||||||
|
|
||||||
DataProvider.SetOwner(character, profile);
|
|
||||||
|
|
||||||
if (group != null)
|
|
||||||
DataProvider.SetParent(character, group);
|
|
||||||
|
|
||||||
return character;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual bool DeleteCharacter(UserAccount account, Character character)
|
|
||||||
{
|
|
||||||
if (GetUserProfile(account) is not UserProfile profile || DataProvider.GetOwner(character) is not UserProfile owner || !account.HasPermission(profile == owner ? UserType.User : UserType.Admin))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
DataProvider.Delete(character);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
namespace OwnChar.Data.Managers;
|
|
||||||
|
|
||||||
public class HttpClientDataManager
|
|
||||||
{
|
|
||||||
}
|
|
||||||
10
OwnChar/Data/MemberLevel.cs
Normal file
10
OwnChar/Data/MemberLevel.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace OwnChar.Data;
|
||||||
|
|
||||||
|
public enum MemberLevel
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Guest,
|
||||||
|
Member,
|
||||||
|
Admin,
|
||||||
|
Owner,
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace OwnChar.Model;
|
namespace OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
public abstract class Character : OwnCharObject
|
public abstract class CharacterBase : OwnCharObject
|
||||||
{
|
{
|
||||||
public virtual string? Name { get; set; }
|
public virtual string? Name { get; set; }
|
||||||
public virtual string? Fandom { get; set; }
|
public virtual string? Fandom { get; set; }
|
||||||
8
OwnChar/Data/Model.Base/GroupBase.cs
Normal file
8
OwnChar/Data/Model.Base/GroupBase.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
|
public abstract class GroupBase : OwnCharObject
|
||||||
|
{
|
||||||
|
public virtual string? Name { get; set; }
|
||||||
|
public virtual string? Fandom { get; set; }
|
||||||
|
public virtual bool IsInternal { get; set; }
|
||||||
|
}
|
||||||
6
OwnChar/Data/Model.Base/MemberEntryBase.cs
Normal file
6
OwnChar/Data/Model.Base/MemberEntryBase.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
|
public abstract class MemberEntryBase : OwnCharObject
|
||||||
|
{
|
||||||
|
public virtual MemberLevel Level { get; set; }
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace OwnChar.Model;
|
namespace OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
public abstract class Property : OwnCharObject
|
public abstract class PropertyBase : OwnCharObject
|
||||||
{
|
{
|
||||||
public virtual string? Name { get; set; }
|
public virtual string? Name { get; set; }
|
||||||
public virtual object? Value { get; set; }
|
public virtual object? Value { get; set; }
|
||||||
6
OwnChar/Data/Model.Base/PropertyCategoryBase.cs
Normal file
6
OwnChar/Data/Model.Base/PropertyCategoryBase.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
|
public abstract class PropertyCategoryBase : OwnCharObject
|
||||||
|
{
|
||||||
|
public virtual string? Name { get; set; }
|
||||||
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
namespace OwnChar.Model;
|
namespace OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
public abstract class UserAccount : OwnCharObject
|
public abstract class UserAccountBase : OwnCharObject
|
||||||
{
|
{
|
||||||
public virtual string? Username { get; set; }
|
public virtual string? Username { get; set; }
|
||||||
public virtual string? Password { get; set; }
|
|
||||||
public virtual string? Email { get; set; }
|
public virtual string? Email { get; set; }
|
||||||
public virtual UserType Type { get; set; }
|
public virtual UserType Type { get; set; }
|
||||||
}
|
}
|
||||||
6
OwnChar/Data/Model.Base/UserProfileBase.cs
Normal file
6
OwnChar/Data/Model.Base/UserProfileBase.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
|
public abstract class UserProfileBase : OwnCharObject
|
||||||
|
{
|
||||||
|
public virtual string? Name { get; set; }
|
||||||
|
}
|
||||||
13
OwnChar/Data/Model.Client/Character.cs
Normal file
13
OwnChar/Data/Model.Client/Character.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
|
namespace OwnChar.Data.Model.Client;
|
||||||
|
|
||||||
|
public class Character() : CharacterBase
|
||||||
|
{
|
||||||
|
internal Character(CharacterBase character) : this()
|
||||||
|
{
|
||||||
|
Id = character.Id;
|
||||||
|
Name = character.Name;
|
||||||
|
Fandom = character.Fandom;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
OwnChar/Data/Model.Client/Group.cs
Normal file
7
OwnChar/Data/Model.Client/Group.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
using OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
|
namespace OwnChar.Data.Model.Client;
|
||||||
|
|
||||||
|
public class Group : GroupBase
|
||||||
|
{
|
||||||
|
}
|
||||||
8
OwnChar/Data/Model.Client/MemberEntry.cs
Normal file
8
OwnChar/Data/Model.Client/MemberEntry.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
|
namespace OwnChar.Data.Model.Client;
|
||||||
|
|
||||||
|
public class MemberEntry() : MemberEntryBase
|
||||||
|
{
|
||||||
|
public long UserProfileId { get; set; }
|
||||||
|
}
|
||||||
13
OwnChar/Data/Model.Client/Property.cs
Normal file
13
OwnChar/Data/Model.Client/Property.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
|
namespace OwnChar.Data.Model.Client;
|
||||||
|
|
||||||
|
public class Property() : PropertyBase
|
||||||
|
{
|
||||||
|
internal Property(PropertyBase prop) : this()
|
||||||
|
{
|
||||||
|
Id = prop.Id;
|
||||||
|
Name = prop.Name;
|
||||||
|
Value = prop.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
OwnChar/Data/Model.Client/PropertyCategory.cs
Normal file
12
OwnChar/Data/Model.Client/PropertyCategory.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
|
namespace OwnChar.Data.Model.Client;
|
||||||
|
|
||||||
|
public class PropertyCategory() : PropertyCategoryBase
|
||||||
|
{
|
||||||
|
internal PropertyCategory(PropertyCategoryBase propCat) : this()
|
||||||
|
{
|
||||||
|
Id = propCat.Id;
|
||||||
|
Name = propCat.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
OwnChar/Data/Model.Client/UserAccount.cs
Normal file
7
OwnChar/Data/Model.Client/UserAccount.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
using OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
|
namespace OwnChar.Data.Model.Client;
|
||||||
|
|
||||||
|
public class UserAccount() : UserAccountBase
|
||||||
|
{
|
||||||
|
}
|
||||||
7
OwnChar/Data/Model.Client/UserProfile.cs
Normal file
7
OwnChar/Data/Model.Client/UserProfile.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
using OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
|
namespace OwnChar.Data.Model.Client;
|
||||||
|
|
||||||
|
public class UserProfile() : UserProfileBase
|
||||||
|
{
|
||||||
|
}
|
||||||
10
OwnChar/Data/Model.Server/CharacterDb.cs
Normal file
10
OwnChar/Data/Model.Server/CharacterDb.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
|
namespace OwnChar.Data.Model.Server;
|
||||||
|
|
||||||
|
public class CharacterDb : CharacterBase
|
||||||
|
{
|
||||||
|
public UserProfileDb? Owner { get; set; }
|
||||||
|
public List<PropertyCategoryDb> PropCats { get; } = [];
|
||||||
|
public List<PropertyDb> Props { get; } = [];
|
||||||
|
}
|
||||||
17
OwnChar/Data/Model.Server/DatabaseContext.cs
Normal file
17
OwnChar/Data/Model.Server/DatabaseContext.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Pilz.Cryptography;
|
||||||
|
|
||||||
|
namespace OwnChar.Server.Data;
|
||||||
|
|
||||||
|
public class DatabaseContext(string dbHost, string dbDatabase, string dbUser, SecureString dbPassword) : DbContext
|
||||||
|
{
|
||||||
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
|
{
|
||||||
|
base.OnConfiguring(optionsBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
base.OnModelCreating(modelBuilder);
|
||||||
|
}
|
||||||
|
}
|
||||||
9
OwnChar/Data/Model.Server/GroupDb.cs
Normal file
9
OwnChar/Data/Model.Server/GroupDb.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
|
namespace OwnChar.Data.Model.Server;
|
||||||
|
|
||||||
|
public class GroupDb : GroupBase
|
||||||
|
{
|
||||||
|
public List<CharacterDb> Characters { get; } = [];
|
||||||
|
public List<MemberEntryDb> Members { get; } = [];
|
||||||
|
}
|
||||||
8
OwnChar/Data/Model.Server/MemberEntryDb.cs
Normal file
8
OwnChar/Data/Model.Server/MemberEntryDb.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
|
namespace OwnChar.Data.Model.Server;
|
||||||
|
|
||||||
|
public class MemberEntryDb() : MemberEntryBase
|
||||||
|
{
|
||||||
|
public virtual UserProfileDb? User { get; set; }
|
||||||
|
}
|
||||||
7
OwnChar/Data/Model.Server/PropertyCategoryDb.cs
Normal file
7
OwnChar/Data/Model.Server/PropertyCategoryDb.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
using OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
|
namespace OwnChar.Data.Model.Server;
|
||||||
|
|
||||||
|
public class PropertyCategoryDb : PropertyCategoryBase
|
||||||
|
{
|
||||||
|
}
|
||||||
7
OwnChar/Data/Model.Server/PropertyDb.cs
Normal file
7
OwnChar/Data/Model.Server/PropertyDb.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
using OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
|
namespace OwnChar.Data.Model.Server;
|
||||||
|
|
||||||
|
public class PropertyDb : PropertyBase
|
||||||
|
{
|
||||||
|
}
|
||||||
9
OwnChar/Data/Model.Server/UserAccountDb.cs
Normal file
9
OwnChar/Data/Model.Server/UserAccountDb.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
|
namespace OwnChar.Data.Model.Server;
|
||||||
|
|
||||||
|
public class UserAccountDb : UserAccountBase
|
||||||
|
{
|
||||||
|
public virtual string? Password { get; set; }
|
||||||
|
public UserProfileDb? Profile { get; set; }
|
||||||
|
}
|
||||||
8
OwnChar/Data/Model.Server/UserProfileDb.cs
Normal file
8
OwnChar/Data/Model.Server/UserProfileDb.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using OwnChar.Data.Model.Base;
|
||||||
|
|
||||||
|
namespace OwnChar.Data.Model.Server;
|
||||||
|
|
||||||
|
public class UserProfileDb : UserProfileBase
|
||||||
|
{
|
||||||
|
public List<CharacterDb> Characters { get; } = [];
|
||||||
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
using OwnChar.Model;
|
|
||||||
|
|
||||||
namespace OwnChar.Data;
|
|
||||||
|
|
||||||
public class OnActionEventArgs(DataManagerAction action, DataManagerActionType actionType, UserAccount currentUser, object? obj, object?[] parameters) : EventArgs
|
|
||||||
{
|
|
||||||
public DataManagerAction Action { get; } = action;
|
|
||||||
public DataManagerActionType ActionType { get; } = actionType;
|
|
||||||
public UserAccount CurrentUser { get; } = currentUser;
|
|
||||||
public object? Object { get; } = obj;
|
|
||||||
public object?[] Parameters { get; } = parameters;
|
|
||||||
public bool IsHandled { get; set; }
|
|
||||||
public object? Result { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using OwnChar.Model;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace OwnChar.Data;
|
|
||||||
|
|
||||||
public class OnCallbackEventArgs(DataManagerAction action, DataManagerActionType actionType, bool success, object? result) : EventArgs
|
|
||||||
{
|
|
||||||
public DataManagerAction Action { get; } = action;
|
|
||||||
public DataManagerActionType ActionType { get; } = actionType;
|
|
||||||
public bool Success { get; } = success;
|
|
||||||
public object? Result { get; } = result;
|
|
||||||
}
|
|
||||||
6
OwnChar/Data/OwnCharObject.cs
Normal file
6
OwnChar/Data/OwnCharObject.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace OwnChar.Data;
|
||||||
|
|
||||||
|
public class OwnCharObject
|
||||||
|
{
|
||||||
|
public virtual long Id { get; set; }
|
||||||
|
}
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using OwnChar.Data.Providers.JsonFile.Model;
|
|
||||||
|
|
||||||
namespace OwnChar.Data.Providers.JsonFile;
|
|
||||||
|
|
||||||
public class JsonFile
|
|
||||||
{
|
|
||||||
public bool IsInitialized { get; set; }
|
|
||||||
public List<JsonUserAccount> UserAccounts { get; } = [];
|
|
||||||
public List<JsonCharacter> Characters { get; } = [];
|
|
||||||
public List<JsonGroup> Groups { get; } = [];
|
|
||||||
}
|
|
||||||
@@ -1,266 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using OwnChar.Api;
|
|
||||||
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 (File.Exists(JsonFilePath) && 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, OwnCharObject
|
|
||||||
{
|
|
||||||
var t = typeof(T);
|
|
||||||
OwnCharObject? 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, OwnCharObject
|
|
||||||
{
|
|
||||||
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.IsInitialized;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetInitialized()
|
|
||||||
{
|
|
||||||
JsonFile.IsInitialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Delete<T>(T obj) where T : class, OwnCharObject
|
|
||||||
{
|
|
||||||
if (obj is JsonCharacter character)
|
|
||||||
{
|
|
||||||
JsonFile.Groups.ForEach(n => n.Characters.Remove(character));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (obj is JsonProp prop)
|
|
||||||
{
|
|
||||||
JsonFile.Characters.ForEach(n => n.Properties.Remove(prop));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (obj is JsonPropCat propCat)
|
|
||||||
{
|
|
||||||
JsonFile.Characters.ForEach(n => n.Properties.ForEach(m =>
|
|
||||||
{
|
|
||||||
if (m.Category == propCat)
|
|
||||||
m.Category = null;
|
|
||||||
}));
|
|
||||||
JsonFile.Characters.ForEach(n => n.PropertyCategories.Remove(propCat));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (obj is JsonGroup group)
|
|
||||||
{
|
|
||||||
JsonFile.Groups.Remove(group);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (obj is JsonUserAccount account)
|
|
||||||
{
|
|
||||||
JsonFile.UserAccounts.Remove(account);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (obj is JsonUserProfile profile)
|
|
||||||
{
|
|
||||||
// We don't delete profiles at the moment!
|
|
||||||
profile.Name = "Deleted user";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetParent(UserProfile profile, UserAccount parent)
|
|
||||||
{
|
|
||||||
if (parent is JsonUserAccount jaccount && profile is JsonUserProfile jprofile)
|
|
||||||
{
|
|
||||||
jaccount.Profile = jprofile;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetParent(Character character, Group parent)
|
|
||||||
{
|
|
||||||
if (character is JsonCharacter jcharacter && parent is JsonGroup jgroup)
|
|
||||||
{
|
|
||||||
if (!jgroup.Characters.Contains(jcharacter))
|
|
||||||
jgroup.Characters.Add(jcharacter);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetParent(Property property, Character character)
|
|
||||||
{
|
|
||||||
if (property is JsonProp jprop && character is JsonCharacter jcharacter)
|
|
||||||
{
|
|
||||||
if (!jcharacter.Properties.Contains(jprop))
|
|
||||||
jcharacter.Properties.Add(jprop);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetOwner(Group group, UserProfile owner)
|
|
||||||
{
|
|
||||||
if (group is JsonGroup jgroup && owner is JsonUserProfile jprofile)
|
|
||||||
{
|
|
||||||
jgroup.Owner = jprofile;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetOwner(Character character, UserProfile owner)
|
|
||||||
{
|
|
||||||
if (character is JsonCharacter jcharacter && owner is JsonUserProfile jprofile)
|
|
||||||
{
|
|
||||||
jcharacter.Owner = jprofile;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserAccount? GetUserAccount(string username, string password)
|
|
||||||
{
|
|
||||||
ArgumentException.ThrowIfNullOrWhiteSpace(username, nameof(username));
|
|
||||||
ArgumentException.ThrowIfNullOrWhiteSpace(password, nameof(password));
|
|
||||||
return JsonFile.UserAccounts.FirstOrDefault(n => n.Username == username && n.Password == password);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserProfile? GetUserProfile(string username)
|
|
||||||
{
|
|
||||||
return JsonFile.UserAccounts.FirstOrDefault(n => n.Username == username)?.Profile;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<UserProfile>? GetMembers(Group group)
|
|
||||||
{
|
|
||||||
if (group is JsonGroup jgroup)
|
|
||||||
return jgroup.Members;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserProfile? GetOwner(Group group)
|
|
||||||
{
|
|
||||||
if (group is JsonGroup jgroup)
|
|
||||||
return jgroup.Owner;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserProfile? GetOwner(Character character)
|
|
||||||
{
|
|
||||||
if (character is JsonCharacter jcharacter)
|
|
||||||
return jcharacter.Owner;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<Character>? GetCharacters(Group group)
|
|
||||||
{
|
|
||||||
if (group is JsonGroup jgroup)
|
|
||||||
return jgroup.Characters;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<Character>? GetCharacters(UserProfile profile)
|
|
||||||
{
|
|
||||||
if (profile is UserProfile jprofile)
|
|
||||||
return JsonFile.Characters.Where(n => n.Owner == profile);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool AddMember(Group group, UserProfile user)
|
|
||||||
{
|
|
||||||
if (group is JsonGroup jgroup && user is JsonUserProfile jprofile)
|
|
||||||
{
|
|
||||||
if (!jgroup.Members.Contains(jprofile))
|
|
||||||
jgroup.Members.Add(jprofile);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool RemoveMember(Group group, UserProfile user)
|
|
||||||
{
|
|
||||||
if (group is JsonGroup jgroup && user is JsonUserProfile jprofile)
|
|
||||||
{
|
|
||||||
jgroup.Members.Remove(jprofile);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SaveDatabase()
|
|
||||||
{
|
|
||||||
SaveFile();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
using OwnChar.Model;
|
|
||||||
|
|
||||||
namespace OwnChar.Data.Providers.JsonFile.Model;
|
|
||||||
|
|
||||||
public class JsonCharacter : Character
|
|
||||||
{
|
|
||||||
public virtual JsonUserProfile? Owner { get; set; }
|
|
||||||
public virtual List<JsonProp> Properties { get; } = [];
|
|
||||||
public virtual List<JsonPropCat> PropertyCategories { get; } = [];
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
using OwnChar.Model;
|
|
||||||
|
|
||||||
namespace OwnChar.Data.Providers.JsonFile.Model;
|
|
||||||
|
|
||||||
public class JsonGroup : Group
|
|
||||||
{
|
|
||||||
public virtual JsonUserProfile? Owner { get; set; }
|
|
||||||
public virtual List<JsonUserProfile> Members { get; } = [];
|
|
||||||
public virtual List<JsonCharacter> Characters { get; } = [];
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
using OwnChar.Model;
|
|
||||||
|
|
||||||
namespace OwnChar.Data.Providers.JsonFile.Model;
|
|
||||||
|
|
||||||
public class JsonProp : Property
|
|
||||||
{
|
|
||||||
public virtual JsonPropCat? Category { get; set; } = null;
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
using OwnChar.Model;
|
|
||||||
|
|
||||||
namespace OwnChar.Data.Providers.JsonFile.Model;
|
|
||||||
|
|
||||||
public class JsonPropCat : PropertyCategory
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Converters;
|
|
||||||
using OwnChar.Model;
|
|
||||||
|
|
||||||
namespace OwnChar.Data.Providers.JsonFile.Model;
|
|
||||||
|
|
||||||
public class JsonUserAccount : UserAccount
|
|
||||||
{
|
|
||||||
public virtual JsonUserProfile? Profile { get; set; }
|
|
||||||
|
|
||||||
[JsonConverter(typeof(StringEnumConverter))]
|
|
||||||
public override UserType Type { get => base.Type; set => base.Type = value; }
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
using OwnChar.Model;
|
|
||||||
|
|
||||||
namespace OwnChar.Data.Providers.JsonFile.Model;
|
|
||||||
|
|
||||||
public class JsonUserProfile : UserProfile
|
|
||||||
{
|
|
||||||
}
|
|
||||||
9
OwnChar/Data/UserType.cs
Normal file
9
OwnChar/Data/UserType.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace OwnChar.Data;
|
||||||
|
|
||||||
|
public enum UserType
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Guest,
|
||||||
|
User,
|
||||||
|
Admin,
|
||||||
|
}
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
using OwnChar.Data;
|
|
||||||
using OwnChar.Model;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace OwnChar;
|
|
||||||
|
|
||||||
public static class Extensions
|
|
||||||
{
|
|
||||||
public static bool GetAt<T>(this object?[] @this, int index, [NotNullWhen(true)] out T? result)
|
|
||||||
{
|
|
||||||
if (@this.ElementAtOrDefault(index) is T obj)
|
|
||||||
{
|
|
||||||
result = obj;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
result = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool HasPermission(this UserAccount account, UserType permissions)
|
|
||||||
{
|
|
||||||
return account.Type >= permissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region OnActionEventArgs
|
|
||||||
|
|
||||||
public static bool SetResult(this OnActionEventArgs @this, object? data)
|
|
||||||
{
|
|
||||||
@this.Result = data;
|
|
||||||
return @this.Result != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool SetResultT(this OnActionEventArgs @this, object? data)
|
|
||||||
{
|
|
||||||
@this.Result = data;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool GetParam<T>(this OnActionEventArgs @this, int index, [NotNullWhen(true)] out T? result)
|
|
||||||
{
|
|
||||||
return @this.Parameters.GetAt(index, out result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool Is(this OnActionEventArgs @this, UserType minLevel)
|
|
||||||
{
|
|
||||||
return @this.CurrentUser.HasPermission(minLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool Is(this OnActionEventArgs @this, DataManagerActionType actionType)
|
|
||||||
{
|
|
||||||
return @this.ActionType == actionType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool Is(this OnActionEventArgs @this, DataManagerAction action)
|
|
||||||
{
|
|
||||||
return @this.Action == action;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
11
OwnChar/Extensions/ApiRequestInfoExtensions.cs
Normal file
11
OwnChar/Extensions/ApiRequestInfoExtensions.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using Pilz.Net.Api;
|
||||||
|
|
||||||
|
namespace OwnChar.Extensions;
|
||||||
|
|
||||||
|
public static class ApiRequestInfoExtensions
|
||||||
|
{
|
||||||
|
public static string? GetUsername(this ApiRequestInfo @this)
|
||||||
|
{
|
||||||
|
return @this.AuthKey?.Split(':').ElementAtOrDefault(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
48
OwnChar/Extensions/ModelExtensions.cs
Normal file
48
OwnChar/Extensions/ModelExtensions.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using OwnChar.Data.Model.Client;
|
||||||
|
using OwnChar.Data.Model.Server;
|
||||||
|
|
||||||
|
namespace OwnChar.Server.Extensions;
|
||||||
|
|
||||||
|
public static class ModelExtensions
|
||||||
|
{
|
||||||
|
public static Group ToClient(this GroupDb @this)
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
Id = @this.Id,
|
||||||
|
Name = @this.Name,
|
||||||
|
Fandom = @this.Fandom,
|
||||||
|
IsInternal = @this.IsInternal,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UserAccount ToClient(this UserAccountDb @this)
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
Id = @this.Id,
|
||||||
|
Email = @this.Email,
|
||||||
|
Type = @this.Type,
|
||||||
|
Username = @this.Username,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UserProfile ToClient(this UserProfileDb @this)
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
Id = @this.Id,
|
||||||
|
Name = @this.Name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MemberEntry ToClient(this MemberEntryDb @this)
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
Id = @this.Id,
|
||||||
|
UserProfileId = @this.User!.Id,
|
||||||
|
Level = @this.Level,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
47
OwnChar/Extensions/OwnCharApiServerExtensions.cs
Normal file
47
OwnChar/Extensions/OwnCharApiServerExtensions.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using OwnChar.Api;
|
||||||
|
using OwnChar.Data;
|
||||||
|
using OwnChar.Data.Model.Base;
|
||||||
|
using OwnChar.Data.Model.Server;
|
||||||
|
using Pilz.Net.Api;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace OwnChar.Server.Extensions;
|
||||||
|
|
||||||
|
public static class OwnCharApiServerExtensions
|
||||||
|
{
|
||||||
|
public static bool CheckLogin(this IOwnCharApiServer server, ApiRequestInfo request, UserType userType)
|
||||||
|
{
|
||||||
|
if (server.Data is null
|
||||||
|
|| !request.IsAuthenticated
|
||||||
|
|| request.AuthKey.Split(":") is not string[] authKey
|
||||||
|
|| authKey.ElementAtOrDefault(0) is not string username
|
||||||
|
|| authKey.ElementAtOrDefault(1) is not string secret
|
||||||
|
|| string.IsNullOrWhiteSpace(username)
|
||||||
|
|| string.IsNullOrWhiteSpace(secret)
|
||||||
|
|| !server.IsLoggedIn(secret)
|
||||||
|
|| server.GetUser(secret) is not UserAccountBase usr
|
||||||
|
|| usr.Type < userType)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool CheckLogin(this IOwnCharApiServer server, ApiRequestInfo request, UserType userType, [NotNullWhen(true)] out UserAccountDb? user)
|
||||||
|
{
|
||||||
|
if (server.Data is null
|
||||||
|
|| !request.IsAuthenticated
|
||||||
|
|| request.AuthKey.Split(":") is not string[] authKey
|
||||||
|
|| authKey.ElementAtOrDefault(0) is not string username
|
||||||
|
|| authKey.ElementAtOrDefault(1) is not string secret
|
||||||
|
|| string.IsNullOrWhiteSpace(username)
|
||||||
|
|| string.IsNullOrWhiteSpace(secret)
|
||||||
|
|| !server.IsLoggedIn(secret)
|
||||||
|
|| server.GetUser(secret) is not UserAccountDb usr
|
||||||
|
|| usr.Type < userType)
|
||||||
|
{
|
||||||
|
user = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
user = usr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
23
OwnChar/IOwnCharManager.cs
Normal file
23
OwnChar/IOwnCharManager.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using OwnChar.Api;
|
||||||
|
using OwnChar.Data.Model.Client;
|
||||||
|
using OwnChar.Modules;
|
||||||
|
using Pilz.Cryptography;
|
||||||
|
|
||||||
|
namespace OwnChar;
|
||||||
|
|
||||||
|
public interface IOwnCharManager
|
||||||
|
{
|
||||||
|
bool IsLoggedIn { get; }
|
||||||
|
|
||||||
|
IOwnCharApiClient? Api { get; }
|
||||||
|
|
||||||
|
IUserManager Users { get; }
|
||||||
|
|
||||||
|
IGroupsManager Groups { get; }
|
||||||
|
|
||||||
|
ICharacterManager Characters { get; }
|
||||||
|
|
||||||
|
Task<UserProfile?> Login(string? username, SecureString? password);
|
||||||
|
|
||||||
|
Task<bool> Logout();
|
||||||
|
}
|
||||||
39
OwnChar/JsonHelpers.cs
Normal file
39
OwnChar/JsonHelpers.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using OwnChar.Api.Packets;
|
||||||
|
|
||||||
|
namespace OwnChar;
|
||||||
|
|
||||||
|
public static class JsonHelpers
|
||||||
|
{
|
||||||
|
private static JsonSerializerSettings? defaultSerializerSettings;
|
||||||
|
|
||||||
|
public static JsonSerializerSettings DefaultSerializerSettings => defaultSerializerSettings ??= CreateDefaultSerializerSettings();
|
||||||
|
|
||||||
|
private static JsonSerializerSettings CreateDefaultSerializerSettings()
|
||||||
|
{
|
||||||
|
return new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
TypeNameHandling = TypeNameHandling.Auto,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? SerializeRequest<T>(T request) where T : OwnCharRequest
|
||||||
|
{
|
||||||
|
return JsonConvert.SerializeObject(request, DefaultSerializerSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? SerializeResponse<T>(T request) where T : OwnCharResponse
|
||||||
|
{
|
||||||
|
return JsonConvert.SerializeObject(request, DefaultSerializerSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T? DeserializeRequest<T>(string request) where T : OwnCharRequest
|
||||||
|
{
|
||||||
|
return JsonConvert.DeserializeObject<T>(request, DefaultSerializerSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T? DeserializeResponse<T>(string request) where T : OwnCharResponse
|
||||||
|
{
|
||||||
|
return JsonConvert.DeserializeObject<T>(request, DefaultSerializerSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
using OwnChar.Api;
|
|
||||||
using OwnChar.Model;
|
|
||||||
|
|
||||||
namespace OwnChar.Manager.Modules;
|
|
||||||
|
|
||||||
public class CharacterManager(OwnCharManager manager) : OwnCharManagerModule(manager), ICharacterManager
|
|
||||||
{
|
|
||||||
public IEnumerable<Character>? GetCharacters(Group? group)
|
|
||||||
{
|
|
||||||
Manager.CheckLogin();
|
|
||||||
|
|
||||||
if (group != null)
|
|
||||||
return Manager.DataManager?.GetCharacters(Manager.CurrentUser!, group);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<Character>? GetCharacters(UserProfile? profile)
|
|
||||||
{
|
|
||||||
Manager.CheckLogin();
|
|
||||||
|
|
||||||
if (profile != null)
|
|
||||||
return Manager.DataManager?.GetCharacters(Manager.CurrentUser!, profile);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Character? CreateCharacter(string? name)
|
|
||||||
{
|
|
||||||
return CreateCharacter(name, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Character? CreateCharacter(string? name, Group? destination)
|
|
||||||
{
|
|
||||||
ArgumentException.ThrowIfNullOrWhiteSpace(name, nameof(name));
|
|
||||||
|
|
||||||
Manager.CheckLogin();
|
|
||||||
|
|
||||||
return Manager.DataManager?.CreateCharacter(Manager.CurrentUser!, name, destination);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DeleteCharacter(Character? character)
|
|
||||||
{
|
|
||||||
ArgumentNullException.ThrowIfNull(character, nameof(character));
|
|
||||||
|
|
||||||
Manager.CheckLogin();
|
|
||||||
|
|
||||||
return Manager.DataManager?.DeleteCharacter(Manager.CurrentUser!, character) ?? false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
using OwnChar.Api;
|
|
||||||
using OwnChar.Model;
|
|
||||||
using Pilz.Cryptography;
|
|
||||||
|
|
||||||
namespace OwnChar.Manager.Modules;
|
|
||||||
|
|
||||||
public class UserManager(OwnCharManager manager) : OwnCharManagerModule(manager), IUserManager
|
|
||||||
{
|
|
||||||
public UserProfile? GetOwnUserProfile()
|
|
||||||
{
|
|
||||||
Manager.CheckLogin();
|
|
||||||
return Manager.DataManager!.GetUserProfile(Manager.CurrentUser!);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserAccount? CreateUserAccount(string? username, SecureString? password)
|
|
||||||
{
|
|
||||||
ArgumentException.ThrowIfNullOrWhiteSpace(username, nameof(username));
|
|
||||||
ArgumentException.ThrowIfNullOrWhiteSpace(password, nameof(password));
|
|
||||||
username = username.Trim().ToLower();
|
|
||||||
return Manager.DataManager?.CreateUserAccount(username, Utils.HashPassword(username, password));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DeleteUserAccount(UserAccount? account)
|
|
||||||
{
|
|
||||||
ArgumentNullException.ThrowIfNull(account, nameof(account));
|
|
||||||
return Manager.DataManager?.DeleteUserAccount(account) ?? false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace OwnChar.Manager;
|
|
||||||
|
|
||||||
public abstract class OwnCharManagerModule(OwnCharManager manager)
|
|
||||||
{
|
|
||||||
public OwnCharManager Manager { get; } = manager;
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
namespace OwnChar.Model;
|
|
||||||
|
|
||||||
public abstract class Group : OwnCharObject
|
|
||||||
{
|
|
||||||
public virtual string? Name { get; set; }
|
|
||||||
public virtual string? Fandom { get; set; }
|
|
||||||
public virtual bool IsInternal { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace OwnChar.Model;
|
|
||||||
|
|
||||||
public class OwnCharObject
|
|
||||||
{
|
|
||||||
public virtual int Id { get; set; }
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user