diff --git a/Dentizone.Application/DI/Services.cs b/Dentizone.Application/DI/Services.cs index 83a23f7..6b1112b 100644 --- a/Dentizone.Application/DI/Services.cs +++ b/Dentizone.Application/DI/Services.cs @@ -28,14 +28,15 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection services.AddScoped(); services.AddScoped(); services.AddScoped(); - services.AddScoped(); services.AddScoped(); - services.AddScoped(); - services.AddScoped(); services.AddScoped(); + + services.AddScoped(); + + return services; } } diff --git a/Dentizone.Application/DI/ServicesValidator.cs b/Dentizone.Application/DI/ServicesValidator.cs new file mode 100644 index 0000000..8dbfbc8 --- /dev/null +++ b/Dentizone.Application/DI/ServicesValidator.cs @@ -0,0 +1,28 @@ +using System.Reflection; +using Microsoft.Extensions.DependencyInjection; + +namespace Dentizone.Application.DI +{ + public static class ServiceCollectionExtensions + { + public static void ValidateAllDependencies(this IServiceCollection services, Assembly[] assembliesToScan) + { + var serviceTypes = assembliesToScan + .SelectMany(a => a.GetTypes()) + .Where(t => t.IsInterface && t.Name.EndsWith("Service")) + .ToList(); + + foreach (var serviceType in serviceTypes) + { + var isRegistered = services.Any(sd => sd.ServiceType == serviceType); + if (!isRegistered) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"❌ Service not registered: {serviceType.FullName}"); + Console.ResetColor(); + throw new InvalidOperationException($"Service not registered: {serviceType.FullName}"); + } + } + } + } +} \ No newline at end of file diff --git a/Dentizone.Application/DTOs/Shipping/CreateShipmentStatusDto.cs b/Dentizone.Application/DTOs/Shipping/CreateShipmentStatusDto.cs new file mode 100644 index 0000000..6c62c86 --- /dev/null +++ b/Dentizone.Application/DTOs/Shipping/CreateShipmentStatusDto.cs @@ -0,0 +1,11 @@ +using Dentizone.Domain.Enums; + +namespace Dentizone.Application.DTOs.Shipping +{ + public class CreateShipmentStatusDto + { + public required string OrderItemId { get; set; } + public required ShipmentActivityStatus NewStatus { get; set; } + public string? Comment { get; set; } + } +} \ No newline at end of file diff --git a/Dentizone.Application/Interfaces/IShippingService.cs b/Dentizone.Application/Interfaces/IShippingService.cs index a71bb68..b2267c5 100644 --- a/Dentizone.Application/Interfaces/IShippingService.cs +++ b/Dentizone.Application/Interfaces/IShippingService.cs @@ -1,10 +1,11 @@ -using Dentizone.Domain.Enums; +using Dentizone.Application.DTOs.Shipping; +using Dentizone.Domain.Enums; +using Microsoft.AspNetCore.Mvc; namespace Dentizone.Application.Interfaces { public interface IShippingService { - Task UpdateItemShipmentStatusAsync(string orderItemId, ShipmentActivityStatus newStatus, - string? comments); + Task UpdateItemShipmentStatusAsync(CreateShipmentStatusDto shipmentStatus); } } \ No newline at end of file diff --git a/Dentizone.Application/Services/ShippingService.cs b/Dentizone.Application/Services/ShippingService.cs index da16165..0d6d5b9 100644 --- a/Dentizone.Application/Services/ShippingService.cs +++ b/Dentizone.Application/Services/ShippingService.cs @@ -1,28 +1,28 @@ -using Dentizone.Application.Interfaces; -using Dentizone.Application.Services.Authentication; +using Dentizone.Application.DTOs.Shipping; +using Dentizone.Application.Interfaces; using Dentizone.Domain.Entity; using Dentizone.Domain.Enums; using Dentizone.Domain.Exceptions; using Dentizone.Domain.Interfaces.Mail; using Dentizone.Domain.Interfaces.Repositories; +using Microsoft.AspNetCore.Mvc; namespace Dentizone.Application.Services { internal class ShippingService( IOrderItemRepository orderItemRepository, IShipmentActivityRepository shipmentActivityRepository, - IMailService mailService, - AuthService authService) + IMailService mailService + ) : IShippingService { - public async Task UpdateItemShipmentStatusAsync(string orderItemId, ShipmentActivityStatus newStatus, - string? comments) + public async Task UpdateItemShipmentStatusAsync(CreateShipmentStatusDto shipmentStatus) { //search in DataBase if orderItemId found or not? var item = await orderItemRepository.FindBy( - oi => oi.Id == orderItemId, - [oi => oi.ShipmentActivities]); + oi => oi.Id == shipmentStatus.OrderItemId, + [oi => oi.ShipmentActivities, oi => oi.Post.Seller, oi => oi.Order.Buyer]); if (item == null) { @@ -32,22 +32,20 @@ public async Task UpdateItemShipmentStatusAsync(string orderItemId, ShipmentActi { var shipmentActivity = new ShipmentActivity { - ItemId = orderItemId, - Status = newStatus, - ActivityDescription = comments + ItemId = shipmentStatus.OrderItemId, + Status = shipmentStatus.NewStatus, + ActivityDescription = shipmentStatus.Comment ?? "No comment provided", }; await shipmentActivityRepository.CreateAsync(shipmentActivity); - var seller = await authService.GetById(item.Post.SellerId); - - - await mailService.Send(seller.Email, $"the Status has been changed to {newStatus}", + await mailService.Send(item.Post.Seller.Email, + $"the Status has been changed to {shipmentStatus.NewStatus}", "New status update"); - var buyer = await authService.GetById(item.Order.BuyerId); - await mailService.Send(buyer.Email, $"the Status has been changed to {newStatus}", + await mailService.Send(item.Order.Buyer.Email, + $"the Status has been changed to {shipmentStatus.NewStatus}", "New status update"); } } diff --git a/Dentizone.Presentaion/Controllers/ShippingController.cs b/Dentizone.Presentaion/Controllers/ShippingController.cs index 8088b8d..5dbb95e 100644 --- a/Dentizone.Presentaion/Controllers/ShippingController.cs +++ b/Dentizone.Presentaion/Controllers/ShippingController.cs @@ -1,4 +1,5 @@ -using Dentizone.Application.Interfaces; +using Dentizone.Application.DTOs.Shipping; +using Dentizone.Application.Interfaces; using Dentizone.Domain.Enums; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -10,11 +11,10 @@ namespace Dentizone.Presentaion.Controllers [Authorize(Policy = "IsAdmin")] public class ShippingController(IShippingService shipmentActivity) : ControllerBase { - [HttpPut] - public async Task UpdateItemShipmentStatus(string orderItemId, ShipmentActivityStatus newStatus, - string? comment) + [HttpPost] + public async Task UpdateItemShipmentStatus(CreateShipmentStatusDto shipmentStatus) { - await shipmentActivity.UpdateItemShipmentStatusAsync(orderItemId, newStatus, comment); + await shipmentActivity.UpdateItemShipmentStatusAsync(shipmentStatus); return Ok(); } } diff --git a/Dentizone.Presentaion/Extensions/SwaggerServiceExtensions.cs b/Dentizone.Presentaion/Extensions/SwaggerServiceExtensions.cs index 9b206b7..7d214e4 100644 --- a/Dentizone.Presentaion/Extensions/SwaggerServiceExtensions.cs +++ b/Dentizone.Presentaion/Extensions/SwaggerServiceExtensions.cs @@ -11,27 +11,26 @@ public static IServiceCollection AddSwaggerWithJwt(this IServiceCollection servi opt.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { BearerFormat = "JWT", - Description = - "JWT Authorization header using the Bearer scheme.", + Description = "JWT Authorization header using the Bearer scheme.", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.Http, Scheme = "Bearer" }); opt.AddSecurityRequirement(new OpenApiSecurityRequirement - { - { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference - { - Id = "Bearer", - Type = ReferenceType.SecurityScheme - } - }, - [] - } - }); + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Id = "Bearer", + Type = ReferenceType.SecurityScheme + } + }, + [] + } + }); }); return services; } diff --git a/Dentizone.Presentaion/Program.cs b/Dentizone.Presentaion/Program.cs index f965fb1..25777ed 100644 --- a/Dentizone.Presentaion/Program.cs +++ b/Dentizone.Presentaion/Program.cs @@ -1,5 +1,6 @@ using Dentizone.Application.DI; using Dentizone.Application.Interfaces; +using Dentizone.Application.Services; using Dentizone.Infrastructure.DependencyInjection; using Dentizone.Infrastructure.Filters; using Dentizone.Presentaion.Context; @@ -32,6 +33,7 @@ public static void Main(string[] args) builder.Services.AddHttpContextAccessor(); builder.Services.AddScoped(); builder.Services.AddSwaggerWithJwt(); + builder.Services.ValidateAllDependencies([typeof(BaseService).Assembly]); var app = builder.Build(); @@ -68,15 +70,15 @@ public static void Main(string[] args) { var db = scope.ServiceProvider.GetRequiredService(); var userManager = scope.ServiceProvider - .GetRequiredService>(); + .GetRequiredService>(); try { Console.WriteLine("[Seeding] Starting full data seeding..."); Infrastructure.Persistence.Seeder.FullDataSeeder.SeedingConfig config = new(); // Use default or customize Infrastructure.Persistence.Seeder.FullDataSeeder.SeedAsync(db, userManager, config) - .GetAwaiter().GetResult(); + .GetAwaiter().GetResult(); Console.WriteLine("[Seeding] Full data seeding completed."); } catch (Exception ex)