607 lines
23 KiB
C#
607 lines
23 KiB
C#
using System.Text;
|
|
using System.Text.Json;
|
|
using FluentAssertions;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using TakeoutSaaS.Application.Dictionary.Contracts;
|
|
using TakeoutSaaS.Application.Dictionary.Services;
|
|
using TakeoutSaaS.Domain.Dictionary.Entities;
|
|
using TakeoutSaaS.Domain.Dictionary.Enums;
|
|
using TakeoutSaaS.Domain.Dictionary.ValueObjects;
|
|
using TakeoutSaaS.Infrastructure.Dictionary.ImportExport;
|
|
using TakeoutSaaS.Infrastructure.Dictionary.Repositories;
|
|
using TakeoutSaaS.Integration.Tests.Fixtures;
|
|
using TakeoutSaaS.Shared.Abstractions.Constants;
|
|
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
|
|
|
namespace TakeoutSaaS.Integration.Tests.App.Dictionary;
|
|
|
|
public sealed class DictionaryApiTests
|
|
{
|
|
[Fact]
|
|
public async Task Test_CreateDictionaryGroup_ReturnsCreated()
|
|
{
|
|
using var database = new DictionarySqliteTestDatabase();
|
|
using var context = database.CreateContext(tenantId: 0, userId: 11);
|
|
var tenantProvider = new TestTenantProvider(0);
|
|
var cache = new TestDictionaryHybridCache();
|
|
|
|
var service = BuildCommandService(context, tenantProvider, cache);
|
|
var result = await service.CreateGroupAsync(new CreateDictionaryGroupRequest
|
|
{
|
|
Code = "ORDER_STATUS",
|
|
Name = "Order Status",
|
|
Scope = DictionaryScope.System,
|
|
AllowOverride = true,
|
|
Description = "Order lifecycle"
|
|
});
|
|
|
|
result.Id.Should().NotBe(0);
|
|
result.Code.Should().Be("order_status");
|
|
result.Scope.Should().Be(DictionaryScope.System);
|
|
|
|
using var verifyContext = database.CreateContext(tenantId: 0);
|
|
var stored = await verifyContext.DictionaryGroups
|
|
.IgnoreQueryFilters()
|
|
.FirstOrDefaultAsync(group => group.Id == result.Id);
|
|
|
|
stored.Should().NotBeNull();
|
|
stored!.TenantId.Should().Be(0);
|
|
stored.Code.Value.Should().Be("order_status");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Test_GetDictionaryGroups_ReturnsPaged()
|
|
{
|
|
using var database = new DictionarySqliteTestDatabase();
|
|
using var context = database.CreateContext(tenantId: 0, userId: 11);
|
|
|
|
context.DictionaryGroups.AddRange(
|
|
CreateSystemGroup(101, "order_status"),
|
|
CreateSystemGroup(102, "payment_method"));
|
|
await context.SaveChangesAsync();
|
|
context.ChangeTracker.Clear();
|
|
|
|
var tenantProvider = new TestTenantProvider(0);
|
|
var cache = new TestDictionaryHybridCache();
|
|
var service = BuildQueryService(context, tenantProvider, cache);
|
|
|
|
var page = await service.GetGroupsAsync(new DictionaryGroupQuery
|
|
{
|
|
Scope = DictionaryScope.System,
|
|
Page = 1,
|
|
PageSize = 1
|
|
});
|
|
|
|
page.TotalCount.Should().Be(2);
|
|
page.Items.Should().HaveCount(1);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Test_UpdateDictionaryGroup_WithValidRowVersion_ReturnsOk()
|
|
{
|
|
using var database = new DictionarySqliteTestDatabase();
|
|
using var context = database.CreateContext(tenantId: 0, userId: 11);
|
|
var tenantProvider = new TestTenantProvider(0);
|
|
var cache = new TestDictionaryHybridCache();
|
|
var service = BuildCommandService(context, tenantProvider, cache);
|
|
|
|
var created = await service.CreateGroupAsync(new CreateDictionaryGroupRequest
|
|
{
|
|
Code = "PAYMENT_METHOD",
|
|
Name = "Payment Method",
|
|
Scope = DictionaryScope.System,
|
|
AllowOverride = true
|
|
});
|
|
|
|
var updated = await service.UpdateGroupAsync(created.Id, new UpdateDictionaryGroupRequest
|
|
{
|
|
Name = "Payment Method Updated",
|
|
Description = "Updated",
|
|
AllowOverride = false,
|
|
IsEnabled = false,
|
|
RowVersion = created.RowVersion
|
|
});
|
|
|
|
updated.Name.Should().Be("Payment Method Updated");
|
|
updated.AllowOverride.Should().BeFalse();
|
|
updated.IsEnabled.Should().BeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Test_UpdateDictionaryGroup_WithStaleRowVersion_ReturnsConflict()
|
|
{
|
|
using var database = new DictionarySqliteTestDatabase();
|
|
using var context = database.CreateContext(tenantId: 0, userId: 11);
|
|
var tenantProvider = new TestTenantProvider(0);
|
|
var cache = new TestDictionaryHybridCache();
|
|
var service = BuildCommandService(context, tenantProvider, cache);
|
|
|
|
var created = await service.CreateGroupAsync(new CreateDictionaryGroupRequest
|
|
{
|
|
Code = "SHIPPING_METHOD",
|
|
Name = "Shipping Method",
|
|
Scope = DictionaryScope.System,
|
|
AllowOverride = true
|
|
});
|
|
|
|
var request = new UpdateDictionaryGroupRequest
|
|
{
|
|
Name = "Shipping Method Updated",
|
|
AllowOverride = true,
|
|
IsEnabled = true,
|
|
RowVersion = new byte[] { 9 }
|
|
};
|
|
|
|
Func<Task> act = async () => await service.UpdateGroupAsync(created.Id, request);
|
|
|
|
var exception = await act.Should().ThrowAsync<BusinessException>();
|
|
exception.Which.ErrorCode.Should().Be(ErrorCodes.Conflict);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Test_DeleteDictionaryGroup_SoftDeletesGroup()
|
|
{
|
|
using var database = new DictionarySqliteTestDatabase();
|
|
using var context = database.CreateContext(tenantId: 0, userId: 11);
|
|
|
|
var group = CreateSystemGroup(201, "user_role");
|
|
var item = CreateSystemItem(210, group.Id, "ADMIN", 10);
|
|
context.DictionaryGroups.Add(group);
|
|
context.DictionaryItems.Add(item);
|
|
await context.SaveChangesAsync();
|
|
context.ChangeTracker.Clear();
|
|
|
|
var tenantProvider = new TestTenantProvider(0);
|
|
var cache = new TestDictionaryHybridCache();
|
|
var service = BuildCommandService(context, tenantProvider, cache);
|
|
|
|
var result = await service.DeleteGroupAsync(group.Id);
|
|
result.Should().BeTrue();
|
|
|
|
using var verifyContext = database.CreateContext(tenantId: 0);
|
|
var deletedGroup = await verifyContext.DictionaryGroups
|
|
.IgnoreQueryFilters()
|
|
.FirstAsync(x => x.Id == group.Id);
|
|
deletedGroup.DeletedAt.Should().NotBeNull();
|
|
|
|
var deletedItem = await verifyContext.DictionaryItems
|
|
.IgnoreQueryFilters()
|
|
.FirstAsync(x => x.Id == item.Id);
|
|
deletedItem.DeletedAt.Should().NotBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Test_EnableOverride_CreatesOverrideConfig()
|
|
{
|
|
using var database = new DictionarySqliteTestDatabase();
|
|
|
|
using (var systemContext = database.CreateContext(tenantId: 0, userId: 11))
|
|
{
|
|
systemContext.DictionaryGroups.Add(CreateSystemGroup(301, "order_status", allowOverride: true));
|
|
await systemContext.SaveChangesAsync();
|
|
}
|
|
|
|
using var tenantContext = database.CreateContext(tenantId: 100, userId: 21);
|
|
var cache = new TestDictionaryHybridCache();
|
|
var service = BuildOverrideService(tenantContext, cache);
|
|
|
|
var result = await service.EnableOverrideAsync(100, "ORDER_STATUS");
|
|
|
|
result.OverrideEnabled.Should().BeTrue();
|
|
result.SystemDictionaryGroupCode.Should().Be("order_status");
|
|
|
|
var stored = await tenantContext.TenantDictionaryOverrides
|
|
.IgnoreQueryFilters()
|
|
.FirstOrDefaultAsync(x => x.TenantId == 100 && x.SystemDictionaryGroupId == 301);
|
|
stored.Should().NotBeNull();
|
|
stored!.OverrideEnabled.Should().BeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Test_DisableOverride_ClearsCustomization()
|
|
{
|
|
using var database = new DictionarySqliteTestDatabase();
|
|
|
|
using (var systemContext = database.CreateContext(tenantId: 0, userId: 11))
|
|
{
|
|
systemContext.DictionaryGroups.Add(CreateSystemGroup(401, "payment_method", allowOverride: true));
|
|
await systemContext.SaveChangesAsync();
|
|
}
|
|
|
|
using var tenantContext = database.CreateContext(tenantId: 100, userId: 21);
|
|
var cache = new TestDictionaryHybridCache();
|
|
var service = BuildOverrideService(tenantContext, cache);
|
|
|
|
await service.EnableOverrideAsync(100, "payment_method");
|
|
var disabled = await service.DisableOverrideAsync(100, "payment_method");
|
|
|
|
disabled.Should().BeTrue();
|
|
|
|
var stored = await tenantContext.TenantDictionaryOverrides
|
|
.IgnoreQueryFilters()
|
|
.FirstAsync(x => x.TenantId == 100 && x.SystemDictionaryGroupId == 401);
|
|
stored.OverrideEnabled.Should().BeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Test_UpdateHiddenItems_FiltersSystemItems()
|
|
{
|
|
using var database = new DictionarySqliteTestDatabase();
|
|
|
|
using (var systemContext = database.CreateContext(tenantId: 0, userId: 11))
|
|
{
|
|
var group = CreateSystemGroup(501, "shipping_method", allowOverride: true);
|
|
systemContext.DictionaryGroups.Add(group);
|
|
systemContext.DictionaryItems.AddRange(
|
|
CreateSystemItem(510, group.Id, "PLATFORM", 10),
|
|
CreateSystemItem(511, group.Id, "MERCHANT", 20));
|
|
await systemContext.SaveChangesAsync();
|
|
}
|
|
|
|
using var tenantContext = database.CreateContext(tenantId: 200, userId: 22);
|
|
var cache = new TestDictionaryHybridCache();
|
|
var overrideService = BuildOverrideService(tenantContext, cache);
|
|
var mergeService = BuildMergeService(tenantContext);
|
|
|
|
await overrideService.UpdateHiddenItemsAsync(200, "shipping_method", new[] { 511L });
|
|
var merged = await mergeService.MergeItemsAsync(200, 501);
|
|
|
|
merged.Should().Contain(item => item.Id == 510);
|
|
merged.Should().NotContain(item => item.Id == 511);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Test_GetMergedDictionary_ReturnsMergedResult()
|
|
{
|
|
using var database = new DictionarySqliteTestDatabase();
|
|
|
|
using (var systemContext = database.CreateContext(tenantId: 0, userId: 11))
|
|
{
|
|
var group = CreateSystemGroup(601, "order_status", allowOverride: true);
|
|
systemContext.DictionaryGroups.Add(group);
|
|
systemContext.DictionaryItems.AddRange(
|
|
CreateSystemItem(610, group.Id, "PENDING", 10),
|
|
CreateSystemItem(611, group.Id, "ACCEPTED", 20));
|
|
await systemContext.SaveChangesAsync();
|
|
}
|
|
|
|
using (var tenantContext = database.CreateContext(tenantId: 300, userId: 33))
|
|
{
|
|
var tenantGroup = CreateTenantGroup(701, 300, "order_status");
|
|
tenantContext.DictionaryGroups.Add(tenantGroup);
|
|
tenantContext.DictionaryItems.Add(CreateTenantItem(720, tenantGroup.Id, "CUSTOM", 15));
|
|
await tenantContext.SaveChangesAsync();
|
|
}
|
|
|
|
using var queryContext = database.CreateContext(tenantId: 300, userId: 33);
|
|
var cache = new TestDictionaryHybridCache();
|
|
var overrideService = BuildOverrideService(queryContext, cache);
|
|
await overrideService.EnableOverrideAsync(300, "order_status");
|
|
await overrideService.UpdateHiddenItemsAsync(300, "order_status", new[] { 611L });
|
|
await overrideService.UpdateCustomSortOrderAsync(300, "order_status", new Dictionary<long, int>
|
|
{
|
|
[720L] = 1,
|
|
[610L] = 2
|
|
});
|
|
|
|
var queryService = BuildQueryService(queryContext, new TestTenantProvider(300), cache);
|
|
var merged = await queryService.GetMergedDictionaryAsync("order_status");
|
|
|
|
merged.Should().Contain(item => item.Id == 610);
|
|
merged.Should().Contain(item => item.Id == 720 && item.Source == "tenant");
|
|
merged.Should().NotContain(item => item.Id == 611);
|
|
merged.First().Id.Should().Be(720);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Test_ExportCsv_GeneratesValidFile()
|
|
{
|
|
using var database = new DictionarySqliteTestDatabase();
|
|
|
|
using (var systemContext = database.CreateContext(tenantId: 0, userId: 11))
|
|
{
|
|
var group = CreateSystemGroup(801, "payment_method", allowOverride: true);
|
|
systemContext.DictionaryGroups.Add(group);
|
|
systemContext.DictionaryItems.Add(CreateSystemItem(810, group.Id, "ALIPAY", 10));
|
|
await systemContext.SaveChangesAsync();
|
|
}
|
|
|
|
using var exportContext = database.CreateContext(tenantId: 0, userId: 11);
|
|
var cache = new TestDictionaryHybridCache();
|
|
var service = BuildImportExportService(exportContext, new TestTenantProvider(0), new TestCurrentUserAccessor(11), cache);
|
|
|
|
await using var stream = new MemoryStream();
|
|
await service.ExportToCsvAsync(801, stream);
|
|
var csv = Encoding.UTF8.GetString(stream.ToArray());
|
|
|
|
csv.Should().Contain("code,key,value,sortOrder,isEnabled,description,source");
|
|
csv.Should().Contain("payment_method");
|
|
csv.Should().Contain("ALIPAY");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Test_ImportCsv_WithSkipMode_SkipsDuplicates()
|
|
{
|
|
using var database = new DictionarySqliteTestDatabase();
|
|
|
|
using (var systemContext = database.CreateContext(tenantId: 0, userId: 11))
|
|
{
|
|
var group = CreateSystemGroup(901, "order_status", allowOverride: true);
|
|
systemContext.DictionaryGroups.Add(group);
|
|
systemContext.DictionaryItems.Add(CreateSystemItem(910, group.Id, "PENDING", 10));
|
|
await systemContext.SaveChangesAsync();
|
|
}
|
|
|
|
using var importContext = database.CreateContext(tenantId: 0, userId: 11);
|
|
var cache = new TestDictionaryHybridCache();
|
|
var service = BuildImportExportService(importContext, new TestTenantProvider(0), new TestCurrentUserAccessor(11), cache);
|
|
|
|
var csv = BuildCsv(
|
|
new[] { "code", "key", "value", "sortOrder", "isEnabled", "description", "source" },
|
|
new[]
|
|
{
|
|
new[] { "order_status", "PENDING", BuildValueJson("待接单", "Pending"), "10", "true", "重复项", "system" },
|
|
new[] { "order_status", "COMPLETED", BuildValueJson("已完成", "Completed"), "20", "true", "新增项", "system" }
|
|
});
|
|
|
|
var result = await service.ImportFromCsvAsync(new DictionaryImportRequest
|
|
{
|
|
GroupId = 901,
|
|
FileName = "import.csv",
|
|
FileSize = Encoding.UTF8.GetByteCount(csv),
|
|
ConflictMode = ConflictResolutionMode.Skip,
|
|
FileStream = new MemoryStream(Encoding.UTF8.GetBytes(csv))
|
|
});
|
|
|
|
result.SkipCount.Should().Be(1);
|
|
result.SuccessCount.Should().Be(1);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Test_ImportCsv_WithOverwriteMode_UpdatesExisting()
|
|
{
|
|
using var database = new DictionarySqliteTestDatabase();
|
|
|
|
using (var systemContext = database.CreateContext(tenantId: 0, userId: 11))
|
|
{
|
|
var group = CreateSystemGroup(1001, "payment_method", allowOverride: true);
|
|
systemContext.DictionaryGroups.Add(group);
|
|
systemContext.DictionaryItems.Add(CreateSystemItem(1010, group.Id, "ALIPAY", 10));
|
|
await systemContext.SaveChangesAsync();
|
|
}
|
|
|
|
using var importContext = database.CreateContext(tenantId: 0, userId: 11);
|
|
var cache = new TestDictionaryHybridCache();
|
|
var service = BuildImportExportService(importContext, new TestTenantProvider(0), new TestCurrentUserAccessor(11), cache);
|
|
|
|
var csv = BuildCsv(
|
|
new[] { "code", "key", "value", "sortOrder", "isEnabled", "description", "source" },
|
|
new[]
|
|
{
|
|
new[] { "payment_method", "ALIPAY", BuildValueJson("支付宝新版", "Alipay New"), "15", "true", "覆盖", "system" }
|
|
});
|
|
|
|
await service.ImportFromCsvAsync(new DictionaryImportRequest
|
|
{
|
|
GroupId = 1001,
|
|
FileName = "import.csv",
|
|
FileSize = Encoding.UTF8.GetByteCount(csv),
|
|
ConflictMode = ConflictResolutionMode.Overwrite,
|
|
FileStream = new MemoryStream(Encoding.UTF8.GetBytes(csv))
|
|
});
|
|
|
|
var updated = await importContext.DictionaryItems
|
|
.IgnoreQueryFilters()
|
|
.FirstAsync(item => item.GroupId == 1001 && item.Key == "ALIPAY");
|
|
|
|
updated.Value.Should().Contain("支付宝新版");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Test_ImportCsv_WithInvalidData_ReturnsErrors()
|
|
{
|
|
using var database = new DictionarySqliteTestDatabase();
|
|
|
|
using (var systemContext = database.CreateContext(tenantId: 0, userId: 11))
|
|
{
|
|
systemContext.DictionaryGroups.Add(CreateSystemGroup(1101, "user_role", allowOverride: false));
|
|
await systemContext.SaveChangesAsync();
|
|
}
|
|
|
|
using var importContext = database.CreateContext(tenantId: 0, userId: 11);
|
|
var cache = new TestDictionaryHybridCache();
|
|
var service = BuildImportExportService(importContext, new TestTenantProvider(0), new TestCurrentUserAccessor(11), cache);
|
|
|
|
var csv = BuildCsv(
|
|
new[] { "code", "key", "value", "sortOrder", "isEnabled", "description", "source" },
|
|
new[]
|
|
{
|
|
new[] { "user_role", "ADMIN", "invalid-json", "10", "true", "bad", "system" }
|
|
});
|
|
|
|
var result = await service.ImportFromCsvAsync(new DictionaryImportRequest
|
|
{
|
|
GroupId = 1101,
|
|
FileName = "import.csv",
|
|
FileSize = Encoding.UTF8.GetByteCount(csv),
|
|
ConflictMode = ConflictResolutionMode.Skip,
|
|
FileStream = new MemoryStream(Encoding.UTF8.GetBytes(csv))
|
|
});
|
|
|
|
result.ErrorCount.Should().Be(1);
|
|
result.SuccessCount.Should().Be(0);
|
|
}
|
|
|
|
private static DictionaryCommandService BuildCommandService(
|
|
TakeoutSaaS.Infrastructure.Dictionary.Persistence.DictionaryDbContext context,
|
|
TestTenantProvider tenantProvider,
|
|
TestDictionaryHybridCache cache)
|
|
{
|
|
return new DictionaryCommandService(
|
|
new DictionaryGroupRepository(context),
|
|
new DictionaryItemRepository(context),
|
|
cache,
|
|
tenantProvider,
|
|
NullLogger<DictionaryCommandService>.Instance);
|
|
}
|
|
|
|
private static DictionaryQueryService BuildQueryService(
|
|
TakeoutSaaS.Infrastructure.Dictionary.Persistence.DictionaryDbContext context,
|
|
TestTenantProvider tenantProvider,
|
|
TestDictionaryHybridCache cache)
|
|
{
|
|
var groupRepository = new DictionaryGroupRepository(context);
|
|
var itemRepository = new DictionaryItemRepository(context);
|
|
var overrideRepository = new TenantDictionaryOverrideRepository(context);
|
|
var mergeService = new DictionaryMergeService(groupRepository, itemRepository, overrideRepository);
|
|
|
|
return new DictionaryQueryService(groupRepository, itemRepository, mergeService, cache, tenantProvider);
|
|
}
|
|
|
|
private static DictionaryOverrideService BuildOverrideService(
|
|
TakeoutSaaS.Infrastructure.Dictionary.Persistence.DictionaryDbContext context,
|
|
TestDictionaryHybridCache cache)
|
|
{
|
|
return new DictionaryOverrideService(
|
|
new DictionaryGroupRepository(context),
|
|
new DictionaryItemRepository(context),
|
|
new TenantDictionaryOverrideRepository(context),
|
|
cache);
|
|
}
|
|
|
|
private static DictionaryMergeService BuildMergeService(
|
|
TakeoutSaaS.Infrastructure.Dictionary.Persistence.DictionaryDbContext context)
|
|
{
|
|
var groupRepository = new DictionaryGroupRepository(context);
|
|
var itemRepository = new DictionaryItemRepository(context);
|
|
var overrideRepository = new TenantDictionaryOverrideRepository(context);
|
|
return new DictionaryMergeService(groupRepository, itemRepository, overrideRepository);
|
|
}
|
|
|
|
private static DictionaryImportExportService BuildImportExportService(
|
|
TakeoutSaaS.Infrastructure.Dictionary.Persistence.DictionaryDbContext context,
|
|
TestTenantProvider tenantProvider,
|
|
TestCurrentUserAccessor currentUser,
|
|
TestDictionaryHybridCache cache)
|
|
{
|
|
return new DictionaryImportExportService(
|
|
new CsvDictionaryParser(),
|
|
new JsonDictionaryParser(),
|
|
new DictionaryGroupRepository(context),
|
|
new DictionaryItemRepository(context),
|
|
new DictionaryImportLogRepository(context),
|
|
cache,
|
|
tenantProvider,
|
|
currentUser,
|
|
NullLogger<DictionaryImportExportService>.Instance);
|
|
}
|
|
|
|
private static DictionaryGroup CreateSystemGroup(long id, string code, bool allowOverride = true)
|
|
{
|
|
return new DictionaryGroup
|
|
{
|
|
Id = id,
|
|
TenantId = 0,
|
|
Code = new DictionaryCode(code),
|
|
Name = code,
|
|
Scope = DictionaryScope.System,
|
|
AllowOverride = allowOverride,
|
|
Description = "Test group",
|
|
IsEnabled = true,
|
|
RowVersion = new byte[] { 1 }
|
|
};
|
|
}
|
|
|
|
private static DictionaryGroup CreateTenantGroup(long id, long tenantId, string code)
|
|
{
|
|
return new DictionaryGroup
|
|
{
|
|
Id = id,
|
|
TenantId = tenantId,
|
|
Code = new DictionaryCode(code),
|
|
Name = code,
|
|
Scope = DictionaryScope.Business,
|
|
AllowOverride = false,
|
|
Description = "Tenant group",
|
|
IsEnabled = true,
|
|
RowVersion = new byte[] { 1 }
|
|
};
|
|
}
|
|
|
|
private static DictionaryItem CreateSystemItem(long id, long groupId, string key, int sortOrder)
|
|
{
|
|
return new DictionaryItem
|
|
{
|
|
Id = id,
|
|
TenantId = 0,
|
|
GroupId = groupId,
|
|
Key = key,
|
|
Value = BuildValueJson("测试", "Test"),
|
|
IsDefault = false,
|
|
IsEnabled = true,
|
|
SortOrder = sortOrder,
|
|
Description = "System item",
|
|
RowVersion = new byte[] { 1 }
|
|
};
|
|
}
|
|
|
|
private static DictionaryItem CreateTenantItem(long id, long groupId, string key, int sortOrder)
|
|
{
|
|
return new DictionaryItem
|
|
{
|
|
Id = id,
|
|
TenantId = 300,
|
|
GroupId = groupId,
|
|
Key = key,
|
|
Value = BuildValueJson("租户值", "Tenant Value"),
|
|
IsDefault = false,
|
|
IsEnabled = true,
|
|
SortOrder = sortOrder,
|
|
Description = "Tenant item",
|
|
RowVersion = new byte[] { 1 }
|
|
};
|
|
}
|
|
|
|
private static string BuildValueJson(string zh, string en)
|
|
{
|
|
var value = new I18nValue(new Dictionary<string, string>
|
|
{
|
|
["zh-CN"] = zh,
|
|
["en"] = en
|
|
});
|
|
return value.ToJson();
|
|
}
|
|
|
|
private static string BuildCsv(string[] headers, IEnumerable<string[]> rows)
|
|
{
|
|
var builder = new StringBuilder();
|
|
builder.AppendLine(string.Join(",", headers));
|
|
foreach (var row in rows)
|
|
{
|
|
builder.AppendLine(string.Join(",", row.Select(EscapeCsvField)));
|
|
}
|
|
|
|
return builder.ToString();
|
|
}
|
|
|
|
private static string EscapeCsvField(string value)
|
|
{
|
|
if (value.Contains('"', StringComparison.Ordinal))
|
|
{
|
|
value = value.Replace("\"", "\"\"");
|
|
}
|
|
|
|
if (value.Contains(',', StringComparison.Ordinal) ||
|
|
value.Contains('\n', StringComparison.Ordinal) ||
|
|
value.Contains('\r', StringComparison.Ordinal) ||
|
|
value.Contains('"', StringComparison.Ordinal))
|
|
{
|
|
return $"\"{value}\"";
|
|
}
|
|
|
|
return value;
|
|
}
|
|
}
|