diff --git a/src/NexusReader.Web.New/Services/ServerIdentityService.cs b/src/NexusReader.Web.New/Services/ServerIdentityService.cs index f8f5e2a..2a9db44 100644 --- a/src/NexusReader.Web.New/Services/ServerIdentityService.cs +++ b/src/NexusReader.Web.New/Services/ServerIdentityService.cs @@ -1,98 +1,70 @@ using System.Security.Claims; using FluentResults; using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; -using NexusReader.Application.DTOs.User; -using NexusReader.Data.Persistence; -using NexusReader.Domain.Entities; -using NexusReader.Application.Queries.User; -using MediatR; -using NexusReader.UI.Shared.Constants; -using NexusReader.UI.Shared.Services; using NexusReader.Application.Abstractions.Services; +using NexusReader.Application.DTOs.User; +using NexusReader.Domain.Entities; +using Mapster; +using Microsoft.EntityFrameworkCore; +using NexusReader.Data.Persistence; namespace NexusReader.Web.New.Services; public class ServerIdentityService : IIdentityService { private readonly UserManager _userManager; - private readonly IHttpContextAccessor _httpContextAccessor; - private readonly IMediator _mediator; + private readonly SignInManager _signInManager; private readonly INativeStorageService _storageService; + private readonly IDbContextFactory _contextFactory; public event Func? OnStateInvalidated; public ServerIdentityService( UserManager userManager, - IHttpContextAccessor httpContextAccessor, - IMediator mediator, - INativeStorageService storageService) + SignInManager signInManager, + INativeStorageService storageService, + IDbContextFactory contextFactory) { _userManager = userManager; - _httpContextAccessor = httpContextAccessor; - _mediator = mediator; + _signInManager = signInManager; _storageService = storageService; + _contextFactory = contextFactory; } - public Task LoginAsync(string email, string password, bool rememberMe = false) - => throw new NotSupportedException("Use standard Identity endpoints for login on server."); - - public async Task LogoutAsync() + public async Task RegisterAsync(string email, string password) { - try - { - // Clear storage if available (Interactive Server mode) - try - { - await _storageService.SaveSecureString(StorageKeys.AuthToken, ""); - await _storageService.SaveSecureString(StorageKeys.RefreshToken, ""); - await _storageService.SaveSecureString(StorageKeys.UserEmail, ""); - await _storageService.SaveSecureString(StorageKeys.UserTenant, ""); - await _storageService.SaveSecureString(StorageKeys.UserRoles, ""); - } - catch - { - // Ignore errors during prerendering where JS interop isn't available - } + var user = new NexusUser { UserName = email, Email = email }; + var result = await _userManager.CreateAsync(user, password); + return result.Succeeded ? Result.Ok() : Result.Fail(result.Errors.Select(e => e.Description)); + } + public async Task LoginAsync(string email, string password, bool rememberMe = false) + { + var result = await _signInManager.PasswordSignInAsync(email, password, rememberMe, lockoutOnFailure: false); + if (result.Succeeded) + { if (OnStateInvalidated != null) await OnStateInvalidated.Invoke(); return Result.Ok(); } - catch (Exception ex) - { - return Result.Fail(new Error("Logout failed.").CausedBy(ex)); - } + return Result.Fail("Login failed"); } - public Task RegisterAsync(string email, string password) - => throw new NotSupportedException("Use standard Identity endpoints for registration on server."); - - public Task RefreshTokenAsync() => Task.FromResult(Result.Ok()); - - public async Task> GetProfileAsync() + public async Task LogoutAsync() { - var user = _httpContextAccessor.HttpContext?.User; - if (user == null || !user.Identity?.IsAuthenticated == true) return Result.Fail("Not authenticated."); + await _signInManager.SignOutAsync(); + if (OnStateInvalidated != null) await OnStateInvalidated.Invoke(); + return Result.Ok(); + } - var userId = user.FindFirstValue(ClaimTypes.NameIdentifier); - if (userId == null) return Result.Fail("User ID not found."); + public async Task> GetProfileAsync() + { + // This is a simplified server-side profile fetch + // In a real app, you'd get the current user from HttpContext + return Result.Fail("Profile fetch not implemented on server identity service yet"); + } - var result = await _mediator.Send(new GetUserProfileQuery(userId)); - if (result.IsFailed) return Result.Fail(result.Errors); - - var dto = result.Value; - - // Map DTO to UI record - var profile = new UserProfile( - dto.Email, - dto.AITokensUsed, - dto.TenantId, - dto.Plan, - dto.AverageQuizScore, - dto.LastReadBook, - dto.Roles - ); - - return Result.Ok(profile); + public Task RefreshTokenAsync() + { + return Task.FromResult(Result.Ok()); } }