Add LittleShop.Client SDK library with complete API wrapper
Features: - Complete .NET client SDK for LittleShop API - JWT authentication with automatic token management - Catalog service for products and categories - Order service with payment creation - Retry policies using Polly for resilience - Error handling middleware - Dependency injection support - Comprehensive documentation and examples SDK Components: - Authentication service with token refresh - Strongly-typed models for all API responses - HTTP handlers for retry and error handling - Extension methods for easy DI registration - Example console application demonstrating usage Test Updates: - Fixed test compilation errors - Updated test data builders for new models - Corrected service constructor dependencies - Fixed enum value changes (PaymentStatus, OrderStatus) Documentation: - Complete project README with features and usage - Client SDK README with detailed examples - API endpoint documentation - Security considerations - Deployment guidelines Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -289,7 +289,7 @@ public class OrdersControllerTests : IClassFixture<TestWebApplicationFactory>
|
||||
var webhookDto = new PaymentWebhookDto
|
||||
{
|
||||
InvoiceId = "INV123456",
|
||||
Status = PaymentStatus.Confirmed,
|
||||
Status = PaymentStatus.Paid,
|
||||
Amount = 100.00m,
|
||||
TransactionHash = "tx123456789"
|
||||
};
|
||||
@@ -407,7 +407,7 @@ public class OrdersControllerTests : IClassFixture<TestWebApplicationFactory>
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
IdentityReference = identityReference,
|
||||
Status = OrderStatus.Pending,
|
||||
Status = OrderStatus.PendingPayment,
|
||||
ShippingName = "Test Customer",
|
||||
ShippingAddress = "Test Address",
|
||||
ShippingCity = "Test City",
|
||||
|
||||
@@ -78,12 +78,9 @@ public static class TestDataBuilder
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Username = user,
|
||||
Email = $"{user}@test.com",
|
||||
PasswordHash = "hashed-password",
|
||||
Role = role,
|
||||
IsActive = true,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
UpdatedAt = DateTime.UtcNow
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
}
|
||||
|
||||
@@ -94,12 +91,11 @@ public static class TestDataBuilder
|
||||
Id = Guid.NewGuid(),
|
||||
OrderId = orderId,
|
||||
Currency = currency,
|
||||
Amount = 0.0025m,
|
||||
CryptoAddress = $"bc1q{Guid.NewGuid().ToString().Replace("-", "").Substring(0, 39)}",
|
||||
RequiredAmount = 0.0025m,
|
||||
WalletAddress = $"bc1q{Guid.NewGuid().ToString().Replace("-", "").Substring(0, 39)}",
|
||||
Status = status,
|
||||
ExchangeRate = 40000.00m,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
UpdatedAt = DateTime.UtcNow
|
||||
ExpiresAt = DateTime.UtcNow.AddHours(1)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -161,15 +157,17 @@ public static class TestDataBuilder
|
||||
};
|
||||
}
|
||||
|
||||
public static ProductPhoto CreateProductPhoto(Guid productId, int displayOrder = 1)
|
||||
public static ProductPhoto CreateProductPhoto(Guid productId, int sortOrder = 1)
|
||||
{
|
||||
var fileName = $"{Guid.NewGuid()}.jpg";
|
||||
return new ProductPhoto
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
ProductId = productId,
|
||||
PhotoUrl = $"/uploads/products/{Guid.NewGuid()}.jpg",
|
||||
FileName = fileName,
|
||||
FilePath = $"/uploads/products/{fileName}",
|
||||
AltText = "Test product photo",
|
||||
DisplayOrder = displayOrder,
|
||||
SortOrder = sortOrder,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ public class CategoryServiceTests : IDisposable
|
||||
{
|
||||
private readonly LittleShopContext _context;
|
||||
private readonly ICategoryService _categoryService;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public CategoryServiceTests()
|
||||
{
|
||||
@@ -25,15 +24,8 @@ public class CategoryServiceTests : IDisposable
|
||||
.Options;
|
||||
_context = new LittleShopContext(options);
|
||||
|
||||
// Set up AutoMapper
|
||||
var mappingConfig = new MapperConfiguration(mc =>
|
||||
{
|
||||
mc.AddProfile(new MappingProfile());
|
||||
});
|
||||
_mapper = mappingConfig.CreateMapper();
|
||||
|
||||
// Create service
|
||||
_categoryService = new CategoryService(_context, _mapper);
|
||||
_categoryService = new CategoryService(_context);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -5,9 +5,9 @@ using LittleShop.Models;
|
||||
using LittleShop.Services;
|
||||
using LittleShop.Enums;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
using LittleShop.Mapping;
|
||||
|
||||
namespace LittleShop.Tests.Unit;
|
||||
|
||||
@@ -15,7 +15,7 @@ public class ProductServiceTests : IDisposable
|
||||
{
|
||||
private readonly LittleShopContext _context;
|
||||
private readonly IProductService _productService;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly Mock<IWebHostEnvironment> _mockEnvironment;
|
||||
|
||||
public ProductServiceTests()
|
||||
{
|
||||
@@ -25,15 +25,12 @@ public class ProductServiceTests : IDisposable
|
||||
.Options;
|
||||
_context = new LittleShopContext(options);
|
||||
|
||||
// Set up AutoMapper
|
||||
var mappingConfig = new MapperConfiguration(mc =>
|
||||
{
|
||||
mc.AddProfile(new MappingProfile());
|
||||
});
|
||||
_mapper = mappingConfig.CreateMapper();
|
||||
// Set up mock environment
|
||||
_mockEnvironment = new Mock<IWebHostEnvironment>();
|
||||
_mockEnvironment.Setup(e => e.WebRootPath).Returns("/test/wwwroot");
|
||||
|
||||
// Create service
|
||||
_productService = new ProductService(_context, _mapper);
|
||||
_productService = new ProductService(_context, _mockEnvironment.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -242,7 +239,7 @@ public class ProductServiceTests : IDisposable
|
||||
|
||||
// Assert
|
||||
result.Should().NotBeNull();
|
||||
result.PhotoUrl.Should().Be("/uploads/test-photo.jpg");
|
||||
result.FilePath.Should().Contain("test-photo.jpg");
|
||||
result.AltText.Should().Be("Test Photo");
|
||||
|
||||
// Verify in database
|
||||
|
||||
Reference in New Issue
Block a user