diff --git a/src/Voltiq.Application/Common/Interfaces/IAuthenticatedRequest.cs b/src/Voltiq.Application/Common/Interfaces/IAuthenticatedRequest.cs index a218b4d..7b4f292 100644 --- a/src/Voltiq.Application/Common/Interfaces/IAuthenticatedRequest.cs +++ b/src/Voltiq.Application/Common/Interfaces/IAuthenticatedRequest.cs @@ -2,7 +2,7 @@ namespace Voltiq.Application.Common.Interfaces; -public interface IAuthenticatedRequest : IRequest +public interface IAuthenticatedRequest : IRequest { Guid UserId { get; set; } } diff --git a/src/Voltiq.Application/Features/Budgets/Commands/RegisterBudget/RegisterBudgetCommandHandler.cs b/src/Voltiq.Application/Features/Budgets/Commands/RegisterBudget/RegisterBudgetCommandHandler.cs index a88a14e..a04070b 100644 --- a/src/Voltiq.Application/Features/Budgets/Commands/RegisterBudget/RegisterBudgetCommandHandler.cs +++ b/src/Voltiq.Application/Features/Budgets/Commands/RegisterBudget/RegisterBudgetCommandHandler.cs @@ -27,15 +27,15 @@ public async Task> Handle( return Error.NotFound(description: ResourceErrorMessages.CLIENTE_NAO_ENCONTRADO); var materialLookup = new Dictionary(); - foreach (var item in command.Items.Where(i => i.MaterialId.HasValue)) + foreach (var materialId in command.Items.Where(i => i.MaterialId.HasValue).Select(i => i.MaterialId!.Value).Distinct()) { var material = await materialReadOnly.GetByIdAndUserIdAsync( - item.MaterialId!.Value, command.UserId, cancellationToken); + materialId, command.UserId, cancellationToken); if (material is null) return Error.NotFound(description: ResourceErrorMessages.MATERIAL_NAO_ENCONTRADO); - materialLookup[item.MaterialId!.Value] = material; + materialLookup[materialId] = material; } var budget = Budget.Register(command.UserId, command.ClientId); diff --git a/src/Voltiq.Functions/GenerateReportFunction.cs b/src/Voltiq.Functions/GenerateReportFunction.cs index 00596bb..c91937b 100644 --- a/src/Voltiq.Functions/GenerateReportFunction.cs +++ b/src/Voltiq.Functions/GenerateReportFunction.cs @@ -17,7 +17,6 @@ public class GenerateReportMessage public class GenerateReportFunction { private readonly ILogger _logger; - private readonly IBudgetReadOnlyRepository _budgetRepository; private readonly IBudgetUpdateOnlyRepository _budgetUpdateRepository; private readonly IClientReadOnlyRepository _clientRepository; private readonly IReportGenerator _reportGenerator; @@ -26,7 +25,6 @@ public class GenerateReportFunction public GenerateReportFunction( ILogger logger, - IBudgetReadOnlyRepository budgetRepository, IBudgetUpdateOnlyRepository budgetUpdateRepository, IClientReadOnlyRepository clientRepository, IReportGenerator reportGenerator, @@ -34,7 +32,6 @@ public GenerateReportFunction( IUnitOfWork unitOfWork) { _logger = logger; - _budgetRepository = budgetRepository; _budgetUpdateRepository = budgetUpdateRepository; _clientRepository = clientRepository; _reportGenerator = reportGenerator; @@ -45,8 +42,6 @@ public GenerateReportFunction( [Function(nameof(GenerateReportFunction))] public async Task Run([QueueTrigger("budget-reports")] string message, CancellationToken cancellationToken) { - _logger.LogInformation("Processing report generation message: {Message}", message); - try { var msg = JsonSerializer.Deserialize(message); @@ -79,31 +74,25 @@ public async Task Run([QueueTrigger("budget-reports")] string message, Cancellat try { - _logger.LogInformation("Generating PDF for Budget ID: {BudgetId}", budget.Id); var pdfBytes = await _reportGenerator.GenerateAsync(reportData, cancellationToken); var fileName = $"budget-{budget.Id}.pdf"; - _logger.LogInformation("Uploading PDF for Budget ID: {BudgetId} to Blob Storage", budget.Id); var uri = await _storageService.UploadAsync(fileName, pdfBytes, "application/pdf", cancellationToken); budget.SetPdfGenerationSuccess(uri); await _unitOfWork.SaveChangesAsync(cancellationToken); - - _logger.LogInformation("Report generated and budget status updated successfully. URI: {Uri}", uri); } catch (Exception ex) { _logger.LogError(ex, "Error generating report for budget ID: {BudgetId}", budget.Id); budget.SetPdfGenerationFailed(); await _unitOfWork.SaveChangesAsync(CancellationToken.None); - throw; } } catch (Exception ex) { _logger.LogError(ex, "Error processing report generation for message: {Message}", message); - throw; } } } diff --git a/src/Voltiq.Functions/Program.cs b/src/Voltiq.Functions/Program.cs index 855edbe..227dea2 100644 --- a/src/Voltiq.Functions/Program.cs +++ b/src/Voltiq.Functions/Program.cs @@ -19,4 +19,4 @@ .UseFunctionsWorkerDefaults() .UseAzureMonitorExporter(); -builder.Build().Run(); +await builder.Build().RunAsync(); diff --git a/src/Voltiq.Infrastructure/Auth/Argon2PasswordHasher.cs b/src/Voltiq.Infrastructure/Auth/Argon2PasswordHasher.cs index aba63ae..ccc82c9 100644 --- a/src/Voltiq.Infrastructure/Auth/Argon2PasswordHasher.cs +++ b/src/Voltiq.Infrastructure/Auth/Argon2PasswordHasher.cs @@ -20,9 +20,9 @@ public string Hash(string password) return $"{Convert.ToBase64String(salt)}.{Convert.ToBase64String(hash)}"; } - public bool Verify(string password, string storedHash) + public bool Verify(string password, string hash) { - var parts = storedHash.Split('.'); + var parts = hash.Split('.'); if (parts.Length != 2) return false; var salt = Convert.FromBase64String(parts[0]); diff --git a/src/Voltiq.Infrastructure/Persistence/Repositories/Budget/BudgetRepository.cs b/src/Voltiq.Infrastructure/Persistence/Repositories/Budget/BudgetRepository.cs index e63a2e8..b533338 100644 --- a/src/Voltiq.Infrastructure/Persistence/Repositories/Budget/BudgetRepository.cs +++ b/src/Voltiq.Infrastructure/Persistence/Repositories/Budget/BudgetRepository.cs @@ -64,14 +64,14 @@ public void Remove(Domain.Entities.Budget entity) } public async Task GetTrackedByIdAndUserIdAsync( - Guid id, Guid userId, CancellationToken cancellationToken) + Guid id, Guid userId, CancellationToken cancellationToken = default) { return await context.Budgets .FirstOrDefaultAsync(b => b.Id == id && b.UserId == userId, cancellationToken); } public async Task GetTrackedByIdWithItemsAndUserIdAsync( - Guid id, Guid userId, CancellationToken cancellationToken) + Guid id, Guid userId, CancellationToken cancellationToken = default) { return await context.Budgets .Include(b => b.Items) diff --git a/src/Voltiq.Infrastructure/Persistence/Repositories/Client/ClientRepository.cs b/src/Voltiq.Infrastructure/Persistence/Repositories/Client/ClientRepository.cs index a4db512..7a11ad3 100644 --- a/src/Voltiq.Infrastructure/Persistence/Repositories/Client/ClientRepository.cs +++ b/src/Voltiq.Infrastructure/Persistence/Repositories/Client/ClientRepository.cs @@ -17,7 +17,7 @@ public sealed class ClientRepository(ApplicationDbContext context) } public async Task GetByIdAndUserIdAsync( - Guid id, Guid userId, CancellationToken cancellationToken) + Guid id, Guid userId, CancellationToken cancellationToken = default) { return await context.Clients .AsNoTracking() @@ -37,7 +37,7 @@ public async Task ExistsWithEmailForUserAsync( } public async Task GetTrackedByIdAndUserIdAsync( - Guid id, Guid userId, CancellationToken cancellationToken) + Guid id, Guid userId, CancellationToken cancellationToken = default) { return await context.Clients .FirstOrDefaultAsync(c => c.Id == id && c.UserId == userId, cancellationToken); diff --git a/src/Voltiq.Infrastructure/Persistence/Repositories/Material/MaterialRepository.cs b/src/Voltiq.Infrastructure/Persistence/Repositories/Material/MaterialRepository.cs index 913ae8f..6f1cd62 100644 --- a/src/Voltiq.Infrastructure/Persistence/Repositories/Material/MaterialRepository.cs +++ b/src/Voltiq.Infrastructure/Persistence/Repositories/Material/MaterialRepository.cs @@ -24,7 +24,7 @@ public sealed class MaterialRepository(ApplicationDbContext context) } public async Task GetByIdAndUserIdAsync( - Guid id, Guid userId, CancellationToken cancellationToken) + Guid id, Guid userId, CancellationToken cancellationToken = default) { return await context.Materials .AsNoTracking() @@ -41,7 +41,7 @@ public sealed class MaterialRepository(ApplicationDbContext context) } public async Task GetTrackedByIdAndUserIdAsync( - Guid id, Guid userId, CancellationToken cancellationToken) + Guid id, Guid userId, CancellationToken cancellationToken = default) { return await context.Materials .FirstOrDefaultAsync(m => m.Id == id && m.UserId == userId, cancellationToken); diff --git a/tests/Voltiq.Infrastructure.Tests/Persistence/BudgetRepositoryTests.cs b/tests/Voltiq.Infrastructure.Tests/Persistence/BudgetRepositoryTests.cs index 7ee532c..d2a3803 100644 --- a/tests/Voltiq.Infrastructure.Tests/Persistence/BudgetRepositoryTests.cs +++ b/tests/Voltiq.Infrastructure.Tests/Persistence/BudgetRepositoryTests.cs @@ -271,8 +271,8 @@ public async Task GetByUserIdWithClientAsync_ShouldReturnBudgetsWithClientLoaded var budgets = await _budgetRepository.GetByUserIdWithClientAsync(user.Id, TestContext.Current.CancellationToken); budgets.Count.ShouldBe(1); - budgets.First().Client.ShouldNotBeNull(); - budgets.First().Client.Name.ShouldBe(client.Name); + budgets[0].Client.ShouldNotBeNull(); + budgets[0].Client.Name.ShouldBe(client.Name); } [Fact] diff --git a/tests/Voltiq.Infrastructure.Tests/Persistence/ClientRepositoryTests.cs b/tests/Voltiq.Infrastructure.Tests/Persistence/ClientRepositoryTests.cs index 71da220..0a192ea 100644 --- a/tests/Voltiq.Infrastructure.Tests/Persistence/ClientRepositoryTests.cs +++ b/tests/Voltiq.Infrastructure.Tests/Persistence/ClientRepositoryTests.cs @@ -18,7 +18,7 @@ public class ClientRepositoryTests(PostgreSqlContainerFixture fixture) private static readonly Guid UserId = Guid.NewGuid(); private ClientRepository _clientRepository = null!; - private IClientReadOnlyRepository _clientReadOnly = null!; + private ClientRepository? _clientReadOnly; private ApplicationDbContext _dbContext = null!; private UnitOfWork _unitOfWork = null!; @@ -49,7 +49,7 @@ public async Task AddAndGetById_ShouldPersistClient() var client = await TestDataBuilder.SeedClientAsync(_clientRepository, _unitOfWork, user.Id); var found = - await _clientReadOnly.GetByIdAndUserIdAsync(client.Id, user.Id, TestContext.Current.CancellationToken); + await _clientReadOnly!.GetByIdAndUserIdAsync(client.Id, user.Id, TestContext.Current.CancellationToken); found.ShouldNotBeNull(); found.Id.ShouldBe(client.Id); @@ -89,7 +89,7 @@ public async Task GetByIdAndUserIdAsync_ShouldReturnClient_WhenBelongsToUser() var user = await TestDataBuilder.SeedUserAsync(_userRepository, _unitOfWork); var client = await TestDataBuilder.SeedClientAsync(_clientRepository, _unitOfWork, user.Id); - var found = await _clientReadOnly.GetByIdAndUserIdAsync(client.Id, user.Id, + var found = await _clientReadOnly!.GetByIdAndUserIdAsync(client.Id, user.Id, TestContext.Current.CancellationToken); found.ShouldNotBeNull(); @@ -105,7 +105,7 @@ public async Task GetByIdAndUserIdAsync_ShouldReturnNull_WhenClientBelongsToAnot var client = await TestDataBuilder.SeedClientAsync(_clientRepository, _unitOfWork, user1.Id); - var found = await _clientReadOnly.GetByIdAndUserIdAsync(client.Id, user2.Id, + var found = await _clientReadOnly!.GetByIdAndUserIdAsync(client.Id, user2.Id, TestContext.Current.CancellationToken); found.ShouldBeNull(); diff --git a/tests/Voltiq.Infrastructure.Tests/Persistence/MaterialRepositoryTests.cs b/tests/Voltiq.Infrastructure.Tests/Persistence/MaterialRepositoryTests.cs index f28b155..0f6183f 100644 --- a/tests/Voltiq.Infrastructure.Tests/Persistence/MaterialRepositoryTests.cs +++ b/tests/Voltiq.Infrastructure.Tests/Persistence/MaterialRepositoryTests.cs @@ -18,7 +18,7 @@ public class MaterialRepositoryTests(PostgreSqlContainerFixture fixture) private static readonly Guid UserId = Guid.NewGuid(); private MaterialRepository _materialRepository = null!; - private IMaterialReadOnlyRepository _materialReadOnly = null!; + private MaterialRepository? _materialReadOnly; private ApplicationDbContext _dbContext = null!; private UnitOfWork _unitOfWork = null!; private UserRepository _userRepository = null!; @@ -80,7 +80,7 @@ public async Task GetByIdAndUserIdAsync_ShouldReturnMaterial_WhenBelongsToUser() var user = await TestDataBuilder.SeedUserAsync(_userRepository, _unitOfWork); var material = await TestDataBuilder.SeedMaterialAsync(_materialRepository, _unitOfWork, user.Id); - var found = await _materialReadOnly.GetByIdAndUserIdAsync(material.Id, user.Id, TestContext.Current.CancellationToken); + var found = await _materialReadOnly!.GetByIdAndUserIdAsync(material.Id, user.Id, TestContext.Current.CancellationToken); found.ShouldNotBeNull(); found.Id.ShouldBe(material.Id); @@ -95,7 +95,7 @@ public async Task GetByIdAndUserIdAsync_ShouldReturnNull_WhenMaterialBelongsToAn var material = await TestDataBuilder.SeedMaterialAsync(_materialRepository, _unitOfWork, user1.Id); - var found = await _materialReadOnly.GetByIdAndUserIdAsync(material.Id, user2.Id, TestContext.Current.CancellationToken); + var found = await _materialReadOnly!.GetByIdAndUserIdAsync(material.Id, user2.Id, TestContext.Current.CancellationToken); found.ShouldBeNull(); } diff --git a/tests/Voltiq.Infrastructure.Tests/Persistence/SoftDeleteTests.cs b/tests/Voltiq.Infrastructure.Tests/Persistence/SoftDeleteTests.cs index 3ce8cdd..890d1ce 100644 --- a/tests/Voltiq.Infrastructure.Tests/Persistence/SoftDeleteTests.cs +++ b/tests/Voltiq.Infrastructure.Tests/Persistence/SoftDeleteTests.cs @@ -17,7 +17,7 @@ public class SoftDeleteTests(PostgreSqlContainerFixture fixture) private static readonly Guid UserId = Guid.NewGuid(); private ClientRepository _clientRepository = null!; - private IClientReadOnlyRepository _clientReadOnly = null!; + private ClientRepository? _clientReadOnly; private ApplicationDbContext _dbContext = null!; private UnitOfWork _unitOfWork = null!; private UserRepository _userRepository = null!; @@ -89,7 +89,7 @@ public async Task GlobalQueryFilter_ShouldExcludeDeletedEntitiesFromNormalQuerie await _unitOfWork.SaveChangesAsync(TestContext.Current.CancellationToken); var found = - await _clientReadOnly.GetByIdAndUserIdAsync(client.Id, user.Id, TestContext.Current.CancellationToken); + await _clientReadOnly!.GetByIdAndUserIdAsync(client.Id, user.Id, TestContext.Current.CancellationToken); found.ShouldBeNull(); } diff --git a/tests/Voltiq.Infrastructure.Tests/Queue/AzureQueueServiceTests.cs b/tests/Voltiq.Infrastructure.Tests/Queue/AzureQueueServiceTests.cs index d30bf29..5940930 100644 --- a/tests/Voltiq.Infrastructure.Tests/Queue/AzureQueueServiceTests.cs +++ b/tests/Voltiq.Infrastructure.Tests/Queue/AzureQueueServiceTests.cs @@ -29,7 +29,11 @@ public ValueTask InitializeAsync() return ValueTask.CompletedTask; } - public ValueTask DisposeAsync() => ValueTask.CompletedTask; + public ValueTask DisposeAsync() + { + GC.SuppressFinalize(this); + return ValueTask.CompletedTask; + } [Fact] public async Task SendMessageAsync_ShouldCreateQueueAndSendMessage() diff --git a/tests/Voltiq.Infrastructure.Tests/Storage/AzureBlobStorageServiceTests.cs b/tests/Voltiq.Infrastructure.Tests/Storage/AzureBlobStorageServiceTests.cs index 0894071..6da7e86 100644 --- a/tests/Voltiq.Infrastructure.Tests/Storage/AzureBlobStorageServiceTests.cs +++ b/tests/Voltiq.Infrastructure.Tests/Storage/AzureBlobStorageServiceTests.cs @@ -28,7 +28,11 @@ public ValueTask InitializeAsync() return ValueTask.CompletedTask; } - public ValueTask DisposeAsync() => ValueTask.CompletedTask; + public ValueTask DisposeAsync() + { + GC.SuppressFinalize(this); + return ValueTask.CompletedTask; + } [Fact] public async Task UploadAsync_ShouldUploadFileAndReturnBlobUri()