feat: introduce IConceptsMapService abstraction with server and WASM implementations and update knowledge processing flow
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
using FluentResults;
|
||||
using NexusReader.Application.Queries.Concepts;
|
||||
|
||||
namespace NexusReader.Application.Abstractions.Services;
|
||||
|
||||
public interface IConceptsMapService
|
||||
{
|
||||
Task<Result<BookConceptsMapResultDto>> GetConceptsMapAsync(Guid bookId);
|
||||
}
|
||||
@@ -103,7 +103,7 @@
|
||||
_isInteractive = true;
|
||||
if (ViewModel != null)
|
||||
{
|
||||
await Coordinator.ProcessFullPageAsync(GetFullPageContent());
|
||||
await Coordinator.ProcessFullPageAsync(GetFullPageContent(), ebookId: ViewModel.EbookId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@
|
||||
|
||||
if (_isInteractive)
|
||||
{
|
||||
await Coordinator.ProcessFullPageAsync(GetFullPageContent());
|
||||
await Coordinator.ProcessFullPageAsync(GetFullPageContent(), ebookId: ViewModel.EbookId);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
@using NexusReader.Application.Queries.Graph
|
||||
@using NexusReader.Application.Queries.Concepts
|
||||
@using System.Net.Http.Json
|
||||
@inject HttpClient Http
|
||||
@using NexusReader.Application.Abstractions.Services
|
||||
@inject IConceptsMapService ConceptsMapService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IIdentityService IdentityService
|
||||
@inject ISyncService SyncService
|
||||
@@ -203,11 +204,11 @@
|
||||
|
||||
if (BookId.HasValue && BookId.Value != Guid.Empty)
|
||||
{
|
||||
var result = await Http.GetFromJsonAsync<BookConceptsMapResultDto>($"api/book/{BookId}/concepts-map");
|
||||
if (result != null)
|
||||
var result = await ConceptsMapService.GetConceptsMapAsync(BookId.Value);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
Nodes = result.Nodes;
|
||||
LastReadBlockId = result.LastReadBlockId;
|
||||
Nodes = result.Value.Nodes;
|
||||
LastReadBlockId = result.Value.LastReadBlockId;
|
||||
|
||||
if (Nodes.Any())
|
||||
{
|
||||
@@ -216,7 +217,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
_errorMessage = "Brak odpowiedzi od serwera.";
|
||||
_errorMessage = result.Errors.FirstOrDefault()?.Message ?? "Brak odpowiedzi od serwera.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public sealed partial class KnowledgeCoordinator : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ProcessFullPageAsync(string fullContent, string tenantId = "global")
|
||||
public async Task ProcessFullPageAsync(string fullContent, string tenantId = "global", Guid? ebookId = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(fullContent)) return;
|
||||
|
||||
@@ -87,7 +87,7 @@ public sealed partial class KnowledgeCoordinator : IDisposable
|
||||
|
||||
try
|
||||
{
|
||||
var result = await _knowledgeService.GetGraphDataAsync(fullContent, tenantId);
|
||||
var result = await _knowledgeService.GetGraphDataAsync(fullContent, tenantId, ebookId);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
var packet = result.Value;
|
||||
|
||||
@@ -36,6 +36,7 @@ builder.Services.AddCascadingAuthenticationState();
|
||||
|
||||
// AI & Content Services
|
||||
builder.Services.AddScoped<IKnowledgeService, WasmKnowledgeService>();
|
||||
builder.Services.AddScoped<IConceptsMapService, WasmConceptsMapService>();
|
||||
|
||||
builder.Services.AddTransient<NexusReader.Web.Client.Handlers.AuthenticationHeaderHandler>();
|
||||
builder.Services.AddHttpClient("NexusAPI", client =>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Net.Http.Json;
|
||||
using FluentResults;
|
||||
using NexusReader.Application.Abstractions.Services;
|
||||
using NexusReader.Application.Queries.Concepts;
|
||||
|
||||
namespace NexusReader.Web.Client.Services;
|
||||
|
||||
public class WasmConceptsMapService : IConceptsMapService
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
public WasmConceptsMapService(HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public async Task<Result<BookConceptsMapResultDto>> GetConceptsMapAsync(Guid bookId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.GetAsync($"api/book/{bookId}/concepts-map");
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var result = await response.Content.ReadFromJsonAsync<BookConceptsMapResultDto>();
|
||||
return result != null ? Result.Ok(result) : Result.Fail<BookConceptsMapResultDto>("Błąd deserializacji mapy pojęć.");
|
||||
}
|
||||
|
||||
var errorContent = await response.Content.ReadAsStringAsync();
|
||||
return Result.Fail<BookConceptsMapResultDto>($"Błąd serwera ({response.StatusCode}): {errorContent}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result.Fail<BookConceptsMapResultDto>(new Error("Błąd sieci przy pobieraniu mapy pojęć.").CausedBy(ex));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,6 +74,7 @@ builder.Services.AddHttpClient("NexusAPI", (sp, client) =>
|
||||
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("NexusAPI"));
|
||||
|
||||
builder.Services.AddScoped<IIdentityService, NexusReader.Web.Services.ServerIdentityService>();
|
||||
builder.Services.AddScoped<IConceptsMapService, NexusReader.Web.Services.ServerConceptsMapService>();
|
||||
builder.Services.AddCascadingAuthenticationState();
|
||||
|
||||
builder.Services.AddApplication();
|
||||
@@ -87,6 +88,11 @@ builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(
|
||||
// Authorization Policies
|
||||
builder.Services.AddScoped<IAuthorizationHandler, TokenLimitHandler>();
|
||||
builder.Services.AddAuthorizationBuilder()
|
||||
.SetDefaultPolicy(new Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder(
|
||||
IdentityConstants.ApplicationScheme,
|
||||
IdentityConstants.BearerScheme)
|
||||
.RequireAuthenticatedUser()
|
||||
.Build())
|
||||
.AddPolicy("ProUser", policy => policy.RequireClaim("Plan", SubscriptionPlan.ProName, SubscriptionPlan.EnterpriseName))
|
||||
.AddPolicy("HasAvailableTokens", policy => policy.AddRequirements(new TokenLimitRequirement()));
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
using System.Security.Claims;
|
||||
using FluentResults;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using NexusReader.Application.Abstractions.Services;
|
||||
using NexusReader.Application.Queries.Concepts;
|
||||
|
||||
namespace NexusReader.Web.Services;
|
||||
|
||||
public class ServerConceptsMapService : IConceptsMapService
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
private readonly AuthenticationStateProvider _authStateProvider;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public ServerConceptsMapService(
|
||||
IMediator mediator,
|
||||
AuthenticationStateProvider authStateProvider,
|
||||
IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_mediator = mediator;
|
||||
_authStateProvider = authStateProvider;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public async Task<Result<BookConceptsMapResultDto>> GetConceptsMapAsync(Guid bookId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var authState = await _authStateProvider.GetAuthenticationStateAsync();
|
||||
var user = authState.User;
|
||||
|
||||
if (user == null || !user.Identity?.IsAuthenticated == true)
|
||||
{
|
||||
user = _httpContextAccessor.HttpContext?.User;
|
||||
}
|
||||
|
||||
if (user == null || !user.Identity?.IsAuthenticated == true)
|
||||
{
|
||||
return Result.Fail<BookConceptsMapResultDto>("Użytkownik nie jest uwierzytelniony.");
|
||||
}
|
||||
|
||||
var userId = user.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
var tenantId = user.FindFirstValue("TenantId") ?? "global";
|
||||
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
return Result.Fail<BookConceptsMapResultDto>("Nie znaleziono identyfikatora użytkownika.");
|
||||
}
|
||||
|
||||
return await _mediator.Send(new GetBookConceptsMapQuery(bookId, userId, tenantId));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result.Fail<BookConceptsMapResultDto>(new Error("Błąd pobierania mapy pojęć na serwerze.").CausedBy(ex));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ using NexusReader.Application.Queries.User;
|
||||
using MediatR;
|
||||
using NexusReader.Application.Constants;
|
||||
using NexusReader.Application.Abstractions.Services;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
|
||||
namespace NexusReader.Web.Services;
|
||||
|
||||
@@ -19,6 +20,7 @@ public class ServerIdentityService : IIdentityService
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly IMediator _mediator;
|
||||
private readonly INativeStorageService _storageService;
|
||||
private readonly AuthenticationStateProvider _authStateProvider;
|
||||
|
||||
public event Func<Task>? OnStateInvalidated;
|
||||
|
||||
@@ -27,13 +29,15 @@ public class ServerIdentityService : IIdentityService
|
||||
SignInManager<NexusUser> signInManager,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
IMediator mediator,
|
||||
INativeStorageService storageService)
|
||||
INativeStorageService storageService,
|
||||
AuthenticationStateProvider authStateProvider)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_mediator = mediator;
|
||||
_storageService = storageService;
|
||||
_authStateProvider = authStateProvider;
|
||||
}
|
||||
|
||||
public async Task<Result> LoginAsync(string email, string password, bool rememberMe = false)
|
||||
@@ -107,7 +111,14 @@ public class ServerIdentityService : IIdentityService
|
||||
|
||||
public async Task<Result<UserProfileDto>> GetProfileAsync()
|
||||
{
|
||||
var user = _httpContextAccessor.HttpContext?.User;
|
||||
var authState = await _authStateProvider.GetAuthenticationStateAsync();
|
||||
var user = authState.User;
|
||||
|
||||
if (user == null || !user.Identity?.IsAuthenticated == true)
|
||||
{
|
||||
user = _httpContextAccessor.HttpContext?.User;
|
||||
}
|
||||
|
||||
if (user == null || !user.Identity?.IsAuthenticated == true) return Result.Fail("Not authenticated.");
|
||||
|
||||
var userId = user.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
|
||||
Reference in New Issue
Block a user