86 lines
2.9 KiB
C#
86 lines
2.9 KiB
C#
using FluentResults;
|
|
using MediatR;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using NexusReader.Application.Abstractions.Messaging;
|
|
using NexusReader.Application.Abstractions.Services;
|
|
using NexusReader.Data.Persistence;
|
|
using NexusReader.Domain.Entities;
|
|
|
|
namespace NexusReader.Application.Commands.Library;
|
|
|
|
public class IngestEbookCommandHandler : IRequestHandler<IngestEbookCommand, Result<Guid>>
|
|
{
|
|
private readonly IDbContextFactory<AppDbContext> _dbContextFactory;
|
|
private readonly IBookStorageService _storageService;
|
|
|
|
public IngestEbookCommandHandler(
|
|
IDbContextFactory<AppDbContext> dbContextFactory,
|
|
IBookStorageService storageService)
|
|
{
|
|
_dbContextFactory = dbContextFactory;
|
|
_storageService = storageService;
|
|
}
|
|
|
|
public async Task<Result<Guid>> Handle(IngestEbookCommand request, CancellationToken cancellationToken)
|
|
{
|
|
using var context = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
|
|
|
|
string epubPath;
|
|
string? coverUrl;
|
|
|
|
try
|
|
{
|
|
// 1. Save Files
|
|
epubPath = await _storageService.SaveEbookAsync(request.EpubData, $"{request.Title}.epub");
|
|
coverUrl = request.CoverImage != null && request.CoverImage.Length > 0
|
|
? await _storageService.SaveCoverAsync(request.CoverImage, $"{request.Title}_cover.jpg")
|
|
: null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Result.Fail(new Error($"Storage failure: {ex.Message}").CausedBy(ex));
|
|
}
|
|
|
|
try
|
|
{
|
|
// 2. Resolve Author
|
|
var authorName = string.IsNullOrWhiteSpace(request.AuthorName) ? "Unknown Author" : request.AuthorName.Trim();
|
|
|
|
// Use case-insensitive comparison
|
|
var author = await context.Authors
|
|
.FirstOrDefaultAsync(a => a.Name.ToLower() == authorName.ToLower(), cancellationToken);
|
|
|
|
if (author == null)
|
|
{
|
|
author = new Author { Name = authorName };
|
|
context.Authors.Add(author);
|
|
}
|
|
|
|
// 3. Create Ebook
|
|
var ebook = new Ebook
|
|
{
|
|
Title = request.Title,
|
|
Author = author,
|
|
FilePath = epubPath, // Relative URL from wwwroot
|
|
CoverUrl = coverUrl,
|
|
UserId = request.UserId,
|
|
TenantId = request.TenantId,
|
|
AddedDate = DateTime.UtcNow
|
|
};
|
|
|
|
context.Ebooks.Add(ebook);
|
|
await context.SaveChangesAsync(cancellationToken);
|
|
|
|
return Result.Ok(ebook.Id);
|
|
}
|
|
catch (DbUpdateException ex)
|
|
{
|
|
return Result.Fail(new Error($"Database error during ingestion: {ex.Message}").CausedBy(ex));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Result.Fail(new Error($"Unexpected error during ingestion: {ex.Message}").CausedBy(ex));
|
|
}
|
|
}
|
|
}
|