Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Dentizone.Application/DI/Services.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,15 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection
services.AddScoped<IAnalyticsService, AnalyticsService>();
services.AddScoped<IFavoritesService, FavoriteService>();
services.AddScoped<IVerificationService, VerificationService>();

services.AddScoped<IWalletService, WalletService>();
services.AddScoped<IPaymentService, PaymentService>();

services.AddScoped<IReviewService, ReviewService>();

services.AddScoped<IWithdrawalService, WithdrawalService>();
services.AddScoped<IQaService, QaService>();

services.AddScoped<IShippingService, ShippingService>();


return services;
}
}
Expand Down
28 changes: 28 additions & 0 deletions Dentizone.Application/DI/ServicesValidator.cs
Original file line number Diff line number Diff line change
@@ -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}");
}
}
}
}
}
11 changes: 11 additions & 0 deletions Dentizone.Application/DTOs/Shipping/CreateShipmentStatusDto.cs
Original file line number Diff line number Diff line change
@@ -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; }
}
}
7 changes: 4 additions & 3 deletions Dentizone.Application/Interfaces/IShippingService.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
32 changes: 15 additions & 17 deletions Dentizone.Application/Services/ShippingService.cs
Original file line number Diff line number Diff line change
@@ -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)
{
Expand All @@ -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");
Comment on lines +42 to 49
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider improving email message localization and error handling.

The hardcoded email messages lack localization and there's no error handling for email sending failures.

-                await mailService.Send(item.Post.Seller.Email,
-                    $"the Status has been changed to {shipmentStatus.NewStatus}",
-                    "New status update");
+                try
+                {
+                    await mailService.Send(item.Post.Seller.Email,
+                        $"Order item {shipmentStatus.OrderItemId} status has been updated to {shipmentStatus.NewStatus}",
+                        "Shipment Status Update");
+                }
+                catch (Exception ex)
+                {
+                    // Log email sending failure but don't fail the entire operation
+                    // Consider using ILogger here
+                }

-                await mailService.Send(item.Order.Buyer.Email,
-                    $"the Status has been changed to {shipmentStatus.NewStatus}",
-                    "New status update");
+                try
+                {
+                    await mailService.Send(item.Order.Buyer.Email,
+                        $"Your order item {shipmentStatus.OrderItemId} status has been updated to {shipmentStatus.NewStatus}",
+                        "Shipment Status Update");
+                }
+                catch (Exception ex)
+                {
+                    // Log email sending failure but don't fail the entire operation
+                    // Consider using ILogger here
+                }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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");
try
{
await mailService.Send(item.Post.Seller.Email,
$"Order item {shipmentStatus.OrderItemId} status has been updated to {shipmentStatus.NewStatus}",
"Shipment Status Update");
}
catch (Exception ex)
{
// Log email sending failure but don't fail the entire operation
// Consider using ILogger here
}
try
{
await mailService.Send(item.Order.Buyer.Email,
$"Your order item {shipmentStatus.OrderItemId} status has been updated to {shipmentStatus.NewStatus}",
"Shipment Status Update");
}
catch (Exception ex)
{
// Log email sending failure but don't fail the entire operation
// Consider using ILogger here
}
🤖 Prompt for AI Agents
In Dentizone.Application/Services/ShippingService.cs around lines 42 to 49, the
email messages are hardcoded without localization and lack error handling.
Refactor the code to use localized strings for the email subject and body by
integrating with the existing localization framework. Additionally, wrap the
email sending calls in try-catch blocks to handle potential exceptions
gracefully, logging any errors encountered during the email sending process.

}
}
Expand Down
10 changes: 5 additions & 5 deletions Dentizone.Presentaion/Controllers/ShippingController.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -10,11 +11,10 @@ namespace Dentizone.Presentaion.Controllers
[Authorize(Policy = "IsAdmin")]
public class ShippingController(IShippingService shipmentActivity) : ControllerBase
{
[HttpPut]
public async Task<IActionResult> UpdateItemShipmentStatus(string orderItemId, ShipmentActivityStatus newStatus,
string? comment)
[HttpPost]
public async Task<IActionResult> UpdateItemShipmentStatus(CreateShipmentStatusDto shipmentStatus)
{
await shipmentActivity.UpdateItemShipmentStatusAsync(orderItemId, newStatus, comment);
await shipmentActivity.UpdateItemShipmentStatusAsync(shipmentStatus);
return Ok();
}
}
Expand Down
29 changes: 14 additions & 15 deletions Dentizone.Presentaion/Extensions/SwaggerServiceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
8 changes: 5 additions & 3 deletions Dentizone.Presentaion/Program.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -32,6 +33,7 @@ public static void Main(string[] args)
builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped<IRequestContextService, RequestContextService>();
builder.Services.AddSwaggerWithJwt();
builder.Services.ValidateAllDependencies([typeof(BaseService).Assembly]);


var app = builder.Build();
Expand Down Expand Up @@ -68,15 +70,15 @@ public static void Main(string[] args)
{
var db = scope.ServiceProvider.GetRequiredService<Infrastructure.AppDbContext>();
var userManager = scope.ServiceProvider
.GetRequiredService<Microsoft.AspNetCore.Identity.UserManager<
Infrastructure.Identity.ApplicationUser>>();
.GetRequiredService<Microsoft.AspNetCore.Identity.UserManager<
Infrastructure.Identity.ApplicationUser>>();
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)
Expand Down