holy! the server app is finished & model is nice now
This commit is contained in:
@@ -1,34 +0,0 @@
|
|||||||
namespace OwnChar.Server.Api.Endpoint;
|
|
||||||
|
|
||||||
internal class CharactersApi(IOwnCharServer server) : IApiEndpoint
|
|
||||||
{
|
|
||||||
public void Initialize(IApiBuilder builder)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
using OwnChar.Api.Packets.General;
|
|
||||||
using OwnChar.Api.Packets.Groups;
|
|
||||||
using OwnChar.Api.Updates;
|
|
||||||
using OwnChar.Data;
|
|
||||||
using OwnChar.Data.Model.Client;
|
|
||||||
using OwnChar.Server.Data.Model;
|
|
||||||
using OwnChar.Server.Extensions;
|
|
||||||
using Pilz.Net.Api;
|
|
||||||
|
|
||||||
namespace OwnChar.Server.Api.Endpoint;
|
|
||||||
|
|
||||||
internal class GroupsApi(IOwnCharServer 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
using OwnChar.Api.Packets;
|
|
||||||
using OwnChar.Api.Packets.General;
|
|
||||||
using OwnChar.Server.Data.Model;
|
|
||||||
using OwnChar.Server.Extensions;
|
|
||||||
using Pilz.Net.Api;
|
|
||||||
|
|
||||||
namespace OwnChar.Server.Api.Endpoint;
|
|
||||||
|
|
||||||
internal class LoginApi(ServerContext 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
namespace OwnChar.Server.Api.Endpoint;
|
|
||||||
|
|
||||||
internal class UsersApi(IOwnCharServer server) : IApiEndpoint
|
|
||||||
{
|
|
||||||
public void Initialize(IApiBuilder builder)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using OwnChar.Data.Model.Base;
|
|
||||||
using Pilz.Configuration;
|
|
||||||
using Pilz.Net.Api;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace OwnChar.Server.Api;
|
|
||||||
|
|
||||||
public interface IOwnCharServer : IApiServer
|
|
||||||
{
|
|
||||||
ISettings Settings { get; }
|
|
||||||
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,10 +0,0 @@
|
|||||||
using Pilz.Plugins.Advanced;
|
|
||||||
|
|
||||||
namespace OwnChar.Server.Api.Plugins;
|
|
||||||
|
|
||||||
public abstract class ApiEndpointFeature(string identifier) : PluginFeature(FeatureType, identifier)
|
|
||||||
{
|
|
||||||
public static string FeatureType => "ownchar.server.apiep";
|
|
||||||
|
|
||||||
public abstract void OnServerInit(IOwnCharServer init);
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
using OwnChar.Plugins;
|
|
||||||
using OwnChar.Server.Api;
|
|
||||||
|
|
||||||
namespace OwnChar.Server.Api.Plugins;
|
|
||||||
|
|
||||||
public class OwnCharServerPluginInitParams(IOwnCharServer server) : OwnCharPluginInitParams
|
|
||||||
{
|
|
||||||
public IOwnCharServer Server { get; } = server;
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace OwnChar.Server.Data;
|
|
||||||
|
|
||||||
public class DatabaseContext(string? dbHost, string? dbUser, string? dbPassword) : DbContext
|
|
||||||
{
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
|
||||||
{
|
|
||||||
base.OnConfiguring(optionsBuilder);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
base.OnModelCreating(modelBuilder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using OwnChar.Client.Data.Model;
|
|
||||||
using OwnChar.Data.Model.Base;
|
|
||||||
|
|
||||||
namespace OwnChar.Server.Data.Model;
|
|
||||||
|
|
||||||
public class CharacterDb : CharacterBase
|
|
||||||
{
|
|
||||||
public UserProfileDb? Owner { get; set; }
|
|
||||||
public List<PropertyCategoryDb> PropCats { get; } = [];
|
|
||||||
public List<PropertyDb> Props { get; } = [];
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
using OwnChar.Api.Updates;
|
|
||||||
using OwnChar.Data.Model.Base;
|
|
||||||
|
|
||||||
namespace OwnChar.Server.Data.Model;
|
|
||||||
|
|
||||||
public class GroupDb : GroupBase
|
|
||||||
{
|
|
||||||
public List<CharacterDb> Characters { get; } = [];
|
|
||||||
public List<MemberEntryDb> Members { get; } = [];
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
using OwnChar.Data.Model.Base;
|
|
||||||
|
|
||||||
namespace OwnChar.Server.Data.Model;
|
|
||||||
|
|
||||||
public class MemberEntryDb() : MemberEntryBase
|
|
||||||
{
|
|
||||||
public virtual UserProfileDb? User { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
using OwnChar.Data.Model.Base;
|
|
||||||
|
|
||||||
namespace OwnChar.Server.Data.Model;
|
|
||||||
|
|
||||||
public class PropertyCategoryDb : PropertyCategoryBase
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
using OwnChar.Data.Model.Base;
|
|
||||||
|
|
||||||
namespace OwnChar.Server.Data.Model;
|
|
||||||
|
|
||||||
public class PropertyDb : PropertyBase
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
using OwnChar.Data.Model.Base;
|
|
||||||
|
|
||||||
namespace OwnChar.Server.Data.Model;
|
|
||||||
|
|
||||||
public class UserAccountDb : UserAccountBase
|
|
||||||
{
|
|
||||||
public virtual string? Password { get; set; }
|
|
||||||
public UserProfileDb? Profile { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
using OwnChar.Data.Model.Base;
|
|
||||||
|
|
||||||
namespace OwnChar.Server.Data.Model;
|
|
||||||
|
|
||||||
public class UserProfileDb : UserProfileBase
|
|
||||||
{
|
|
||||||
public List<CharacterDb> Characters { get; } = [];
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
using OwnChar.Api.Packets;
|
|
||||||
using OwnChar.Data;
|
|
||||||
using OwnChar.Data.Model.Base;
|
|
||||||
using OwnChar.Server.Api;
|
|
||||||
using OwnChar.Server.Data.Model;
|
|
||||||
using Pilz.Net.Api;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace OwnChar.Server.Extensions;
|
|
||||||
|
|
||||||
public static class GeneralExtensions
|
|
||||||
{
|
|
||||||
public static bool CheckLogin(this IOwnCharServer 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 IOwnCharServer 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
using OwnChar.Data.Model.Client;
|
|
||||||
using OwnChar.Server.Data.Model;
|
|
||||||
|
|
||||||
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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,11 +8,9 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Castle.Core" Version="5.1.1" />
|
<PackageReference Include="Castle.Core" Version="5.1.1" />
|
||||||
<PackageReference Include="Pilz.Configuration" Version="3.1.3" />
|
<PackageReference Include="Mono.Options" Version="6.12.0.148" />
|
||||||
<PackageReference Include="Pilz.Cryptography" Version="2.1.1" />
|
<PackageReference Include="Pilz.Cryptography" Version="2.1.1" />
|
||||||
<PackageReference Include="Pilz.Net" Version="2.0.4" />
|
<PackageReference Include="Pilz.Net" Version="2.0.4" />
|
||||||
<PackageReference Include="Pilz.Plugins" Version="2.1.9" />
|
|
||||||
<PackageReference Include="Pilz.Plugins.Advanced" Version="2.10.1" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,36 +1,42 @@
|
|||||||
using OwnChar.Plugins;
|
using Castle.Core.Logging;
|
||||||
using OwnChar.Server.Api.Plugins;
|
using OwnChar.Api;
|
||||||
using Pilz.Configuration;
|
|
||||||
|
|
||||||
namespace OwnChar.Server;
|
namespace OwnChar.Server;
|
||||||
|
|
||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
public static string? AppTempFolder { get; private set; }
|
|
||||||
public static ISettingsManager? SettingsManager { get; private set; }
|
|
||||||
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
// Load settings
|
var options = new ServerOptions(args);
|
||||||
AppTempFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "OwnChar", "Server");
|
var appTempFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "OwnChar", "Server");
|
||||||
Directory.CreateDirectory(AppTempFolder);
|
|
||||||
SettingsManager = new SettingsManager(Path.Combine(AppTempFolder, "Settings.json"), true);
|
|
||||||
|
|
||||||
// Create server context
|
|
||||||
var server = new ServerContext(SettingsManager.Instance);
|
|
||||||
|
|
||||||
// Load log
|
// Load log
|
||||||
// ...
|
Directory.CreateDirectory(appTempFolder);
|
||||||
|
using var fsLog = File.OpenWrite(Path.Combine(appTempFolder, "Log.log"));
|
||||||
|
var log = new StreamLogger("OwnChar Server", fsLog);
|
||||||
|
|
||||||
// Load plugins
|
// Check paramters
|
||||||
server.Log.Debug("Loading plugins");
|
if (!options.IsValid())
|
||||||
var pluginPath = Path.Combine(AppTempFolder, "Plugins");
|
{
|
||||||
Directory.CreateDirectory(pluginPath);
|
log.Error("Parameters are invalid or not configured. Can not start server app.");
|
||||||
var pluginPaths = Directory.GetDirectories(pluginPath, "*", SearchOption.TopDirectoryOnly).Select(n => Path.Combine(n, n + ".dll")).ToArray();
|
return;
|
||||||
var plugins = OwnCharPlugins.Instance.LoadPlugins(pluginPaths, new OwnCharServerPluginInitParams(server));
|
}
|
||||||
server.Log.InfoFormat("{0} plugins loaded", plugins.Count());
|
|
||||||
|
|
||||||
// Start server app
|
// Create server context
|
||||||
server.Start(args);
|
var server = new OwnCharApiServer(options.ApiUrl, options.DbServer, options.DbDatabase, options.DbUser, options.DbPassword)
|
||||||
|
{
|
||||||
|
Log = log
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start server
|
||||||
|
server.Start();
|
||||||
|
|
||||||
|
// Wait for exit
|
||||||
|
Console.WriteLine("Server started. Press any key to stop.");
|
||||||
|
Console.ReadKey();
|
||||||
|
|
||||||
|
// Stop server
|
||||||
|
server.Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using OwnChar.Data.Model.Base;
|
|
||||||
using OwnChar.Server.Api;
|
|
||||||
using OwnChar.Server.Api.Endpoint;
|
|
||||||
using OwnChar.Server.Api.Plugins;
|
|
||||||
using OwnChar.Server.Data;
|
|
||||||
using Pilz.Configuration;
|
|
||||||
using Pilz.Cryptography;
|
|
||||||
using Pilz.Extensions.Collections;
|
|
||||||
using Pilz.Net.Api;
|
|
||||||
using Pilz.Plugins.Advanced;
|
|
||||||
|
|
||||||
namespace OwnChar.Server;
|
|
||||||
|
|
||||||
internal class ServerContext(ISettings settings) : ApiServer(settings.Get<ServerSettings>().ApiUrl!), IOwnCharServer
|
|
||||||
{
|
|
||||||
private readonly Dictionary<string, UserAccountBase> users = [];
|
|
||||||
|
|
||||||
public DbContext? Data { get; private set; }
|
|
||||||
|
|
||||||
public ISettings Settings { get; } = settings;
|
|
||||||
|
|
||||||
public override void Start()
|
|
||||||
{
|
|
||||||
Log.Info("Prepairing server");
|
|
||||||
|
|
||||||
// Load database
|
|
||||||
var settings = Settings.Get<ServerSettings>();
|
|
||||||
Log.Debug("Loading database");
|
|
||||||
Data = new DatabaseContext(settings.DbServer, settings.DbUser, settings.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));
|
|
||||||
|
|
||||||
// Plugin endpoints
|
|
||||||
Log.Debug("Loading plugin api endpoints");
|
|
||||||
PluginFeatureController.Instance.Features.Get(ApiEndpointFeature.FeatureType).OfType<ApiEndpointFeature>().ForEach(n => n.OnServerInit(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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
59
OwnChar.Server/ServerOptions.cs
Normal file
59
OwnChar.Server/ServerOptions.cs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
using Mono.Options;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace OwnChar.Server;
|
||||||
|
|
||||||
|
internal class ServerOptions
|
||||||
|
{
|
||||||
|
private readonly OptionSet options;
|
||||||
|
|
||||||
|
public string? DbServer { get; set; }
|
||||||
|
public string? DbDatabase { get; set; }
|
||||||
|
public string? DbUser { get; set; }
|
||||||
|
public string? DbPassword { get; set; }
|
||||||
|
public string? ApiUrl { get; set; }
|
||||||
|
|
||||||
|
public ServerOptions(string[] args)
|
||||||
|
{
|
||||||
|
options = new()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"url=",
|
||||||
|
"Sets the api server url.",
|
||||||
|
dbhost => DbServer = dbhost
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"host=",
|
||||||
|
"Sets the database server address.",
|
||||||
|
dbhost => DbServer = dbhost
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"db=",
|
||||||
|
"Sets the database name.",
|
||||||
|
dbhost => DbServer = dbhost
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"usr=",
|
||||||
|
"Sets the database user.",
|
||||||
|
dbhost => DbServer = dbhost
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pwd=",
|
||||||
|
"Sets the database password.",
|
||||||
|
dbhost => DbServer = dbhost
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
options.Parse(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MemberNotNullWhen(true, nameof(ApiUrl), nameof(DbServer), nameof(DbDatabase), nameof(DbUser), nameof(DbPassword))]
|
||||||
|
public bool IsValid()
|
||||||
|
{
|
||||||
|
return !string.IsNullOrWhiteSpace(ApiUrl)
|
||||||
|
&& !string.IsNullOrWhiteSpace(DbServer)
|
||||||
|
&& !string.IsNullOrWhiteSpace(DbDatabase)
|
||||||
|
&& !string.IsNullOrWhiteSpace(DbUser)
|
||||||
|
&& !string.IsNullOrWhiteSpace(DbPassword);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
using Pilz.Configuration;
|
|
||||||
|
|
||||||
namespace OwnChar.Server;
|
|
||||||
|
|
||||||
public class ServerSettings : IChildSettings, ISettingsIdentifier
|
|
||||||
{
|
|
||||||
public static string Identifier => "ownchar.server.data.sql";
|
|
||||||
|
|
||||||
public string? DbServer { get; set; }
|
|
||||||
public string? DbUser { get; set; }
|
|
||||||
public string? DbPassword { get; set; }
|
|
||||||
public string? ApiUrl { get; set; }
|
|
||||||
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
DbServer = null;
|
|
||||||
DbUser = null;
|
|
||||||
DbPassword = null;
|
|
||||||
ApiUrl = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user