Initial commit of LittleShop project (excluding large archives)

- BTCPay Server integration
- TeleBot Telegram bot
- Review system
- Admin area
- Docker deployment configuration

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-09-17 15:07:38 +01:00
parent bcca00ab39
commit e1b377a042
140 changed files with 32166 additions and 21089 deletions

View File

@@ -193,9 +193,10 @@ public class CategoryServiceTests : IDisposable
// Assert
result.Should().BeTrue();
// Verify in database
// Verify in database - soft delete means IsActive = false
var dbCategory = await _context.Categories.FindAsync(categoryId);
dbCategory.Should().BeNull();
dbCategory.Should().NotBeNull();
dbCategory!.IsActive.Should().BeFalse();
}
[Fact]
@@ -212,7 +213,7 @@ public class CategoryServiceTests : IDisposable
}
[Fact]
public async Task DeleteCategoryAsync_WithProductsAttached_ThrowsException()
public async Task DeleteCategoryAsync_WithProductsAttached_SoftDeletesCategory()
{
// Arrange
var categoryId = Guid.NewGuid();
@@ -240,11 +241,16 @@ public class CategoryServiceTests : IDisposable
_context.Products.Add(product);
await _context.SaveChangesAsync();
// Act & Assert
await Assert.ThrowsAsync<DbUpdateException>(async () =>
{
await _categoryService.DeleteCategoryAsync(categoryId);
});
// Act
var result = await _categoryService.DeleteCategoryAsync(categoryId);
// Assert - soft delete should succeed even with products
result.Should().BeTrue();
// Verify category is soft deleted
var dbCategory = await _context.Categories.FindAsync(categoryId);
dbCategory.Should().NotBeNull();
dbCategory!.IsActive.Should().BeFalse();
}
public void Dispose()

View File

@@ -51,11 +51,11 @@ public class ProductServiceTests : IDisposable
// Act
var result = await _productService.GetAllProductsAsync();
// Assert
result.Should().HaveCount(3);
// Assert - only active products should be returned
result.Should().HaveCount(2);
result.Should().Contain(p => p.Name == "Product 1");
result.Should().Contain(p => p.Name == "Product 2");
result.Should().Contain(p => p.Name == "Product 3");
result.Should().NotContain(p => p.Name == "Product 3"); // Inactive product should not be returned
}
[Fact]
@@ -209,9 +209,10 @@ public class ProductServiceTests : IDisposable
// Assert
result.Should().BeTrue();
// Verify in database
// Verify in database - soft delete means IsActive = false
var dbProduct = await _context.Products.FindAsync(productId);
dbProduct.Should().BeNull();
dbProduct.Should().NotBeNull();
dbProduct!.IsActive.Should().BeFalse();
}
[Fact]

View File

@@ -2,11 +2,14 @@ using Xunit;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using System.Security.Claims;
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Text.Json;
using LittleShop.Controllers;
using LittleShop.Services;
using LittleShop.DTOs;
@@ -33,24 +36,47 @@ public class PushNotificationControllerTests
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, _testUserId.ToString()),
new Claim(ClaimTypes.Name, "testuser"),
new Claim(ClaimTypes.Role, "Admin")
};
var identity = new ClaimsIdentity(claims, "TestAuth");
var principal = new ClaimsPrincipal(identity);
// Setup service provider with logger
var services = new ServiceCollection();
services.AddLogging();
var serviceProvider = services.BuildServiceProvider();
var httpContext = new DefaultHttpContext
{
User = principal,
Connection = { RemoteIpAddress = System.Net.IPAddress.Parse("192.168.1.1") },
RequestServices = serviceProvider
};
_controller.ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext
{
User = principal,
Connection = { RemoteIpAddress = System.Net.IPAddress.Parse("192.168.1.1") }
}
HttpContext = httpContext
};
// Setup User-Agent header
_controller.HttpContext.Request.Headers.Add("User-Agent", "TestBrowser/1.0");
}
private string GetPropertyFromResult(object resultValue, string propertyName)
{
var jsonString = JsonSerializer.Serialize(resultValue);
var response = JsonSerializer.Deserialize<JsonElement>(jsonString);
// Handle case where the result is a simple string value
if (response.ValueKind == JsonValueKind.String)
{
return response.GetString()!;
}
return response.GetProperty(propertyName).GetString()!;
}
[Fact]
public void GetVapidPublicKey_ReturnsPublicKey()
{
@@ -63,8 +89,9 @@ public class PushNotificationControllerTests
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
dynamic value = okResult.Value;
Assert.Equal(expectedKey, value.publicKey);
var jsonString = JsonSerializer.Serialize(okResult.Value);
var response = JsonSerializer.Deserialize<JsonElement>(jsonString);
Assert.Equal(expectedKey, response.GetProperty("publicKey").GetString());
}
[Fact]
@@ -101,8 +128,8 @@ public class PushNotificationControllerTests
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
dynamic value = okResult.Value;
Assert.Equal("Successfully subscribed to push notifications", value.message);
var message = GetPropertyFromResult(okResult.Value!, "message");
Assert.Equal("Successfully subscribed to push notifications", message);
}
[Fact]
@@ -155,8 +182,8 @@ public class PushNotificationControllerTests
// Assert
var unauthorizedResult = Assert.IsType<UnauthorizedObjectResult>(result);
dynamic value = unauthorizedResult.Value;
Assert.Equal("Invalid user ID", value.error);
var error = GetPropertyFromResult(unauthorizedResult.Value!, "error");
Assert.Equal("Invalid user ID", error);
}
[Fact]
@@ -180,8 +207,8 @@ public class PushNotificationControllerTests
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
dynamic value = okResult.Value;
Assert.Equal("Successfully subscribed to push notifications", value.message);
var message = GetPropertyFromResult(okResult.Value!, "message");
Assert.Equal("Successfully subscribed to push notifications", message);
}
[Fact]
@@ -200,8 +227,8 @@ public class PushNotificationControllerTests
// Assert
var badRequestResult = Assert.IsType<BadRequestObjectResult>(result);
dynamic value = badRequestResult.Value;
Assert.Equal("Invalid customer ID", value.error);
var error = GetPropertyFromResult(badRequestResult.Value!, "error");
Assert.Equal("Invalid customer ID", error);
}
[Fact]
@@ -216,8 +243,8 @@ public class PushNotificationControllerTests
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
dynamic value = okResult.Value;
Assert.Equal("Successfully unsubscribed from push notifications", value.message);
var message = GetPropertyFromResult(okResult.Value!, "message");
Assert.Equal("Successfully unsubscribed from push notifications", message);
}
[Fact]
@@ -232,8 +259,8 @@ public class PushNotificationControllerTests
// Assert
var notFoundResult = Assert.IsType<NotFoundObjectResult>(result);
dynamic value = notFoundResult.Value;
Assert.Equal("Subscription not found", value.error);
var error = GetPropertyFromResult(notFoundResult.Value!, "error");
Assert.Equal("Subscription not found", error);
}
[Fact]
@@ -255,8 +282,8 @@ public class PushNotificationControllerTests
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
dynamic value = okResult.Value;
Assert.Equal("Test notification sent successfully", value.message);
var message = GetPropertyFromResult(okResult.Value!, "message");
Assert.Equal("Test notification sent successfully", message);
}
[Fact]
@@ -279,8 +306,8 @@ public class PushNotificationControllerTests
// Assert
var statusResult = Assert.IsType<ObjectResult>(result);
Assert.Equal(500, statusResult.StatusCode);
dynamic value = statusResult.Value;
Assert.Contains("Failed to send test notification", (string)value.error);
var error = GetPropertyFromResult(statusResult.Value!, "error");
Assert.Contains("Failed to send test notification", error);
}
[Fact]
@@ -302,8 +329,8 @@ public class PushNotificationControllerTests
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
dynamic value = okResult.Value;
Assert.Equal("Broadcast notification sent successfully", value.message);
var message = GetPropertyFromResult(okResult.Value!, "message");
Assert.Equal("Broadcast notification sent successfully", message);
}
[Fact]
@@ -331,9 +358,10 @@ public class PushNotificationControllerTests
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
var subscriptionList = okResult.Value as IEnumerable<dynamic>;
Assert.NotNull(subscriptionList);
Assert.Single(subscriptionList);
var jsonString = JsonSerializer.Serialize(okResult.Value);
var subscriptionArray = JsonSerializer.Deserialize<JsonElement[]>(jsonString);
Assert.NotNull(subscriptionArray);
Assert.Single(subscriptionArray);
}
[Fact]
@@ -347,7 +375,7 @@ public class PushNotificationControllerTests
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
dynamic value = okResult.Value;
Assert.Equal("Cleaned up 5 expired subscriptions", value.message);
var message = GetPropertyFromResult(okResult.Value!, "message");
Assert.Equal("Cleaned up 5 expired subscriptions", message);
}
}