558 lines
25 KiB
C#
558 lines
25 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Data;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Text.Json;
|
||
using System.Threading.Tasks;
|
||
using Microsoft.Extensions.Configuration;
|
||
using Microsoft.Extensions.Logging;
|
||
using Sozsoft.Languages.Entities;
|
||
using Sozsoft.Languages.Languages;
|
||
using Sozsoft.Platform.Entities;
|
||
using Sozsoft.Platform.Enums;
|
||
using Sozsoft.Platform.Extensions;
|
||
using Sozsoft.Platform.ListForms;
|
||
using Volo.Abp.Data;
|
||
using Volo.Abp.DependencyInjection;
|
||
using Volo.Abp.Domain.Repositories;
|
||
using Volo.Abp.MultiTenancy;
|
||
using Volo.Abp.PermissionManagement;
|
||
using static Sozsoft.Platform.PlatformConsts;
|
||
|
||
namespace Sozsoft.Platform.Data.Seeds;
|
||
|
||
/// <summary>
|
||
/// Wizard ile oluşturulan konfigürasyonları Seeds/{host|tenants/{tenantId}}/wizard/*.json
|
||
/// dosyalarından okuyarak veritabanına aktarır (kapsam, seed edilen veritabanını izler).
|
||
/// Wizard çalıştıktan sonra oluşturulan JSON dosyaları projeye commit edildikten sonra,
|
||
/// veritabanı silinip yeniden oluşturulduğunda bu seeder tüm wizard konfigürasyonlarını geri yükler.
|
||
/// </summary>
|
||
public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
||
{
|
||
private readonly IRepository<LanguageKey, Guid> _repoLangKey;
|
||
private readonly IRepository<LanguageText, Guid> _repoLangText;
|
||
private readonly IRepository<PermissionGroupDefinitionRecord, Guid> _repoPermGroup;
|
||
private readonly IRepository<PermissionDefinitionRecord, Guid> _repoPerm;
|
||
private readonly IRepository<Menu, Guid> _repoMenu;
|
||
private readonly IRepository<Module, string> _repoModule;
|
||
private readonly IRepository<DataSource, Guid> _repoDataSource;
|
||
private readonly IRepository<ListForm, Guid> _repoListForm;
|
||
private readonly IRepository<ListFormField, Guid> _repoListFormField;
|
||
private readonly IRepository<ListFormWorkflow, string> _repoListFormWorkflow;
|
||
private readonly IConfiguration _configuration;
|
||
private readonly ILogger<WizardDataSeeder> _logger;
|
||
|
||
private readonly string _cultureNameDefault = PlatformConsts.DefaultLanguage;
|
||
private readonly string _appName = PlatformConsts.AppName;
|
||
|
||
public WizardDataSeeder(
|
||
IRepository<LanguageKey, Guid> repoLangKey,
|
||
IRepository<LanguageText, Guid> repoLangText,
|
||
IRepository<PermissionGroupDefinitionRecord, Guid> repoPermGroup,
|
||
IRepository<PermissionDefinitionRecord, Guid> repoPerm,
|
||
IRepository<Menu, Guid> repoMenu,
|
||
IRepository<Module, string> repoModule,
|
||
IRepository<DataSource, Guid> repoDataSource,
|
||
IRepository<ListForm, Guid> repoListForm,
|
||
IRepository<ListFormField, Guid> repoListFormField,
|
||
IRepository<ListFormWorkflow, string> repoListFormWorkflow,
|
||
IConfiguration configuration,
|
||
ILogger<WizardDataSeeder> logger)
|
||
{
|
||
_repoLangKey = repoLangKey;
|
||
_repoLangText = repoLangText;
|
||
_repoPermGroup = repoPermGroup;
|
||
_repoPerm = repoPerm;
|
||
_repoMenu = repoMenu;
|
||
_repoModule = repoModule;
|
||
_repoDataSource = repoDataSource;
|
||
_repoListForm = repoListForm;
|
||
_repoListFormField = repoListFormField;
|
||
_repoListFormWorkflow = repoListFormWorkflow;
|
||
_configuration = configuration;
|
||
_logger = logger;
|
||
}
|
||
|
||
public async Task SeedAsync(DataSeedContext context)
|
||
{
|
||
var scopeFolderName = SeedPathResolver.GetScopeFolderName(context.TenantId);
|
||
var wizardDataPath = SeedPathResolver.GetScopePath(_configuration, context.TenantId, SeedPathResolver.WizardFolder);
|
||
if (!Directory.Exists(wizardDataPath))
|
||
{
|
||
_logger.LogInformation("Seeds/{Scope}/wizard directory not found, skipping.", scopeFolderName);
|
||
return;
|
||
}
|
||
|
||
var jsonFiles = Directory.GetFiles(wizardDataPath, "*.json");
|
||
if (jsonFiles.Length == 0)
|
||
{
|
||
_logger.LogInformation("No JSON files found in Seeds/{Scope}/wizard directory, skipping.", scopeFolderName);
|
||
return;
|
||
}
|
||
|
||
// Dosya adi tarih tasimadigi icin uygulama sirasi dosyanin kendi damgasindan gelir;
|
||
// birbirine bagli wizard'lar (once Customers, sonra Tasks) uretildikleri sirayla uygulanir.
|
||
var seedFiles = new List<(string FilePath, WizardSeedFileDto Seed)>();
|
||
foreach (var filePath in jsonFiles)
|
||
{
|
||
try
|
||
{
|
||
var seed = WizardSeedFileDto.FromSeedJson(await File.ReadAllTextAsync(filePath));
|
||
if (seed?.Wizard == null)
|
||
{
|
||
_logger.LogWarning("Invalid file skipped: {FilePath}", filePath);
|
||
continue;
|
||
}
|
||
|
||
seedFiles.Add((filePath, seed));
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, $"Error - {filePath}: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
_logger.LogInformation("WizardDataSeeder started. {Count} files to be processed.", seedFiles.Count);
|
||
|
||
foreach (var (filePath, seedFile) in seedFiles
|
||
.OrderBy(x => x.Seed.Wizard.SeededAt)
|
||
.ThenBy(x => Path.GetFileName(x.FilePath), StringComparer.OrdinalIgnoreCase))
|
||
{
|
||
var fileName = Path.GetFileName(filePath);
|
||
try
|
||
{
|
||
var wizardName = seedFile.Wizard.WizardName?.Trim();
|
||
if (string.IsNullOrWhiteSpace(wizardName))
|
||
{
|
||
_logger.LogWarning("WizardName is empty, skipped: {FilePath}", filePath);
|
||
continue;
|
||
}
|
||
|
||
var isCustomComponent = seedFile.Wizard.ComponentKind == WizardComponentKindEnum.Custom;
|
||
if (!isCustomComponent && seedFile.ListForm == null)
|
||
{
|
||
_logger.LogWarning("[{File}] ListForm section is missing, skipped.", fileName);
|
||
continue;
|
||
}
|
||
|
||
await BackfillMenuParentModuleIdAsync(seedFile.Wizard);
|
||
|
||
// Zaten seeded mi kontrol et. Custom yolunda ListForm üretilmediği için
|
||
// idempotency menü kaydı üzerinden değerlendirilir.
|
||
// Menusuz Custom wizard'da ne ListForm ne de menu kaydi olustugu icin
|
||
// idempotency okuma permission'i uzerinden degerlendirilir.
|
||
var alreadySeeded = isCustomComponent
|
||
? seedFile.Wizard.CreateMenu
|
||
? await _repoMenu.AnyAsync(a => a.Code == seedFile.Wizard.ResolveMenuCode())
|
||
: await _repoPerm.AnyAsync(a => a.Name == seedFile.Wizard.ResolveMenuCode())
|
||
: await _repoListForm.AnyAsync(a => a.ListFormCode == seedFile.Wizard.ListFormCode);
|
||
|
||
if (alreadySeeded)
|
||
{
|
||
// Ekran kurulu olsa da dil metinleri eksik kalmis olabilir: seed dosyasina yeni
|
||
// bir alan eklendiginde ya da ekran seeder disinda olustugunda sutun basliklari
|
||
// ham anahtar olarak gorunur. Mevcut metinlerin uzerine yazilmadigi icin bu
|
||
// tamamlama ekrani degistirmez.
|
||
await SeedLanguageTextsAsync(seedFile.Wizard, isCustomComponent);
|
||
_logger.LogInformation("[{File}] '{WizardName}' already exists, only missing language texts were created.", fileName, wizardName);
|
||
continue;
|
||
}
|
||
|
||
_logger.LogInformation("[{File}] '{WizardName}' is being applied...", fileName, wizardName);
|
||
await ApplyWizardSeedAsync(seedFile);
|
||
_logger.LogInformation("[{File}] '{WizardName}' has been successfully applied.", fileName, wizardName);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, $"Error - {filePath}: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
private async Task ApplyWizardSeedAsync(WizardSeedFileDto seedFile)
|
||
{
|
||
var input = seedFile.Wizard;
|
||
input.Groups ??= [];
|
||
|
||
var code = input.ResolveMenuCode();
|
||
var listFormCode = input.ResolveListFormCode();
|
||
var nameLangKey = code;
|
||
var permCreateName = $"{code}.Create";
|
||
var permUpdateName = $"{code}.Update";
|
||
var permDeleteName = $"{code}.Delete";
|
||
var permExportName = $"{code}.Export";
|
||
var permImportName = $"{code}.Import";
|
||
var permNoteName = $"{code}.Note";
|
||
|
||
// Yol ayrımı: Custom yolunda ListForm ekosistemi üretilmez (AppService.Create ile aynı davranış).
|
||
var isCustomComponent = input.ComponentKind == WizardComponentKindEnum.Custom;
|
||
var customRoutePath = NormalizeSeedCustomRoutePath(input);
|
||
|
||
// Dil - Language Keys
|
||
await SeedLanguageTextsAsync(input, isCustomComponent);
|
||
|
||
// Permission Group - gorunen adin dil anahtari SeedLanguageTextsAsync icinde uretilir.
|
||
var groupName = ResolvePermissionGroupName(input);
|
||
input.PermissionGroupName = groupName;
|
||
if (!await _repoPermGroup.AnyAsync(a => a.Name == groupName))
|
||
{
|
||
await _repoPermGroup.InsertAsync(
|
||
new PermissionGroupDefinitionRecord(Guid.NewGuid(), groupName, groupName), autoSave: true);
|
||
}
|
||
|
||
// Permissions - tek seferde mevcut permission'ları çek, sonra her birini kontrol et
|
||
var permQueryable = await _repoPerm.GetQueryableAsync();
|
||
var existingPerms = permQueryable.Where(a => a.GroupName == groupName).ToList();
|
||
|
||
// Yetkiler menuyle ayni modul filtresine tabidir; modul bos kalirsa rol ekraninda
|
||
// modul secimiyle filtrelenen listede gorunmez.
|
||
var permissionModules = input.MenuParentModuleId?.Trim();
|
||
|
||
var permRead = existingPerms.FirstOrDefault(a => a.Name == code);
|
||
permRead ??= await InsertPermissionAsync(groupName, code, null, nameLangKey, permissionModules);
|
||
|
||
// CRUD üçlüsü her iki yolda da üretilir: Custom component de Form
|
||
// üzerinden kayıt ekler, günceller ve siler (AppService.Create ile aynı davranış).
|
||
if (!existingPerms.Any(a => a.Name == permCreateName))
|
||
await InsertPermissionAsync(groupName, permCreateName, permRead.Name, WizardConsts.LangKeyCreate, permissionModules);
|
||
|
||
if (!existingPerms.Any(a => a.Name == permUpdateName))
|
||
await InsertPermissionAsync(groupName, permUpdateName, permRead.Name, WizardConsts.LangKeyUpdate, permissionModules);
|
||
|
||
if (!existingPerms.Any(a => a.Name == permDeleteName))
|
||
await InsertPermissionAsync(groupName, permDeleteName, permRead.Name, WizardConsts.LangKeyDelete, permissionModules);
|
||
|
||
// Export/Import/Note yalnızca ListForm ekosisteminde karşılığı olan işlemlerdir.
|
||
if (!isCustomComponent)
|
||
{
|
||
if (!existingPerms.Any(a => a.Name == permExportName))
|
||
await InsertPermissionAsync(groupName, permExportName, permRead.Name, WizardConsts.LangKeyExport, permissionModules);
|
||
|
||
if (!existingPerms.Any(a => a.Name == permImportName))
|
||
await InsertPermissionAsync(groupName, permImportName, permRead.Name, WizardConsts.LangKeyImport, permissionModules);
|
||
|
||
if (!existingPerms.Any(a => a.Name == permNoteName))
|
||
await InsertPermissionAsync(groupName, permNoteName, permRead.Name, WizardConsts.LangKeyNote, permissionModules);
|
||
}
|
||
|
||
// // Permission Grants - Admin role için, sadece eksik olanları ekle
|
||
// var existingGrants = await _permissionGrantRepository.GetListAsync("R", PlatformConsts.AbpIdentity.User.AdminRoleName);
|
||
// var existingGrantNames = new HashSet<string>(existingGrants.Select(g => g.Name));
|
||
|
||
// var grantsToInsert = new[]
|
||
// {
|
||
// permRead.Name, permCreate.Name, permUpdate.Name,
|
||
// permDelete.Name, permExport.Name, permImport.Name, permNote.Name
|
||
// }
|
||
// .Where(name => !existingGrantNames.Contains(name))
|
||
// .Select(name => new PermissionGrant(Guid.NewGuid(), name, "R", PlatformConsts.AbpIdentity.User.AdminRoleName))
|
||
// .ToList();
|
||
|
||
// if (grantsToInsert.Count > 0)
|
||
// {
|
||
// await _permissionGrantRepository.InsertManyAsync(grantsToInsert, autoSave: true);
|
||
// }
|
||
|
||
// Menunun acacagi adres; menu uretilmese de seed dosyasindaki degeri korunur.
|
||
input.MenuUrl = isCustomComponent
|
||
? customRoutePath
|
||
: !string.IsNullOrWhiteSpace(input.MenuUrl)
|
||
? input.MenuUrl.Trim()
|
||
: WizardConsts.MenuUrl(code);
|
||
|
||
// Menusuz wizard: menu (ve ust menu) kaydi hic uretilmez.
|
||
if (input.CreateMenu)
|
||
{
|
||
// Menu Parent
|
||
await EnsureModuleAsync(input.MenuParentModuleId);
|
||
|
||
var menuQueryable = await _repoMenu.GetQueryableAsync();
|
||
var menuParent = await _repoMenu.FirstOrDefaultAsync(a => a.Code == input.MenuParentCode);
|
||
if (menuParent == null)
|
||
{
|
||
var maxRootOrder = menuQueryable.Where(a => a.ParentCode == null || a.ParentCode == "").Select(a => (int?)a.Order).Max() ?? 0;
|
||
var menuParentIcon = !string.IsNullOrWhiteSpace(input.MenuParentIcon)
|
||
? input.MenuParentIcon
|
||
: !string.IsNullOrWhiteSpace(input.MenuIcon)
|
||
? input.MenuIcon
|
||
: WizardConsts.MenuIcon;
|
||
menuParent = await _repoMenu.InsertAsync(new Menu
|
||
{
|
||
Code = input.MenuParentCode,
|
||
DisplayName = input.MenuParentCode,
|
||
IsDisabled = false,
|
||
ModuleId = input.MenuParentModuleId,
|
||
Icon = menuParentIcon,
|
||
Order = maxRootOrder + 1,
|
||
}, autoSave: true);
|
||
}
|
||
|
||
// Menu
|
||
var maxChildOrder = menuQueryable.Where(a => a.ParentCode == menuParent.Code).Select(a => (int?)a.Order).Max() ?? 0;
|
||
var menuOrder = input.MenuOrder > 0 ? input.MenuOrder : maxChildOrder + 1;
|
||
input.MenuOrder = menuOrder;
|
||
var menuUrl = input.MenuUrl;
|
||
var existingMenu = await _repoMenu.FirstOrDefaultAsync(a => a.Code == code);
|
||
if (existingMenu == null)
|
||
{
|
||
await _repoMenu.InsertAsync(new Menu
|
||
{
|
||
Code = code,
|
||
DisplayName = nameLangKey,
|
||
IsDisabled = false,
|
||
ParentCode = menuParent.Code,
|
||
Icon = input.MenuIcon ?? WizardConsts.MenuIcon,
|
||
Target = null,
|
||
ElementId = null,
|
||
CssClass = null,
|
||
Url = menuUrl,
|
||
RequiredPermissionName = permRead.Name,
|
||
Order = menuOrder,
|
||
ModuleId = menuParent.ModuleId,
|
||
}, autoSave: true);
|
||
}
|
||
else if (existingMenu.Order != menuOrder || existingMenu.Url != menuUrl)
|
||
{
|
||
existingMenu.Order = menuOrder;
|
||
existingMenu.Url = menuUrl;
|
||
await _repoMenu.UpdateAsync(existingMenu, autoSave: true);
|
||
}
|
||
}
|
||
|
||
// Custom yolunda ListForm ekosistemi üretilmez.
|
||
if (isCustomComponent)
|
||
return;
|
||
|
||
// DataSource
|
||
var existingDataSource = await _repoDataSource.FirstOrDefaultAsync(a => a.Code == input.DataSourceCode);
|
||
if (existingDataSource == null)
|
||
{
|
||
await _repoDataSource.InsertAsync(new DataSource
|
||
{
|
||
Code = input.DataSourceCode,
|
||
DataSourceType = input.DataSourceConnectionString != null &&
|
||
input.DataSourceConnectionString.IndexOf("Server", StringComparison.OrdinalIgnoreCase) >= 0
|
||
? DataSourceTypeEnum.Mssql
|
||
: DataSourceTypeEnum.Postgresql,
|
||
ConnectionString = input.DataSourceConnectionString
|
||
}, autoSave: true);
|
||
}
|
||
|
||
// ListForm ve alanlari - varsa sil, seed dosyasindaki sozlesmeden yeniden kur
|
||
var existingListForm = await _repoListForm.FirstOrDefaultAsync(a => a.ListFormCode == input.ListFormCode);
|
||
if (existingListForm != null)
|
||
{
|
||
await _repoListForm.DeleteAsync(existingListForm, autoSave: true);
|
||
}
|
||
|
||
var existingListFormFields = await _repoListFormField.GetListAsync(a => a.ListFormCode == input.ListFormCode);
|
||
if (existingListFormFields.Count > 0)
|
||
{
|
||
await _repoListFormField.DeleteManyAsync(existingListFormFields, autoSave: true);
|
||
}
|
||
|
||
var existingWorkflowCriteria = await _repoListFormWorkflow.GetListAsync(a => a.ListFormCode == input.ListFormCode);
|
||
if (existingWorkflowCriteria.Count > 0)
|
||
{
|
||
await _repoListFormWorkflow.DeleteManyAsync(existingWorkflowCriteria, autoSave: true);
|
||
}
|
||
|
||
// Ekran, seed dosyasinin tasidigi ListForm sozlesmesinden kurulur; boylece wizard
|
||
// sonrasinda tasarimci uzerinde yapilan degisiklikler de geri gelir.
|
||
var listForm = new ListForm();
|
||
seedFile.ListForm.ApplyTo(listForm);
|
||
await _repoListForm.InsertAsync(listForm, autoSave: true);
|
||
|
||
foreach (var fieldDto in seedFile.Fields)
|
||
{
|
||
var field = new ListFormField();
|
||
fieldDto.ApplyTo(field);
|
||
await _repoListFormField.InsertAsync(field, autoSave: true);
|
||
}
|
||
|
||
foreach (var criteria in seedFile.ListForm.WorkflowDto.Criteria)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(criteria.Id))
|
||
{
|
||
_logger.LogWarning("Workflow criteria skipped because Id is empty. ListFormCode: {ListFormCode}, Title: {Title}", input.ListFormCode, criteria.Title);
|
||
continue;
|
||
}
|
||
|
||
await _repoListFormWorkflow.InsertAsync(new ListFormWorkflow(criteria.Id)
|
||
{
|
||
ListFormCode = string.IsNullOrWhiteSpace(criteria.ListFormCode) ? input.ListFormCode : criteria.ListFormCode,
|
||
Kind = criteria.Kind,
|
||
Title = criteria.Title,
|
||
CompareColumn = criteria.CompareColumn,
|
||
CompareOperator = criteria.CompareOperator,
|
||
CompareValue = criteria.CompareValue,
|
||
Approver = criteria.Approver,
|
||
NextOnStart = criteria.NextOnStart,
|
||
NextOnTrue = criteria.NextOnTrue,
|
||
NextOnFalse = criteria.NextOnFalse,
|
||
NextOnApprove = criteria.NextOnApprove,
|
||
NextOnReject = criteria.NextOnReject,
|
||
PositionX = criteria.PositionX,
|
||
PositionY = criteria.PositionY,
|
||
CompareOutcomesJson = JsonSerializer.Serialize(criteria.CompareOutcomes ?? []),
|
||
}, autoSave: true);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Custom yolunda menunun acacagi rotayi normalize eder. Rota MenuUrl uzerinden
|
||
/// tasinir; bos ise menu hicbir yere gitmeyecegi icin seed dosyasi hatali kabul edilir.
|
||
/// </summary>
|
||
private static string NormalizeSeedCustomRoutePath(ListFormWizardDto input)
|
||
{
|
||
if (input.ComponentKind != WizardComponentKindEnum.Custom)
|
||
return null;
|
||
|
||
var routePath = input.MenuUrl?.Trim();
|
||
if (string.IsNullOrWhiteSpace(routePath))
|
||
throw new InvalidOperationException(
|
||
$"'{input.WizardName}' custom component wizard'inda Route Path bos olamaz.");
|
||
|
||
return routePath.StartsWith('/') ? routePath : "/" + routePath;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Seed dosyasindaki modul kaydi yoksa olusturur; menunun ModuleId yabanci anahtari
|
||
/// tanimsiz bir module bagli kalmasin diye menu yazilmadan once cagrilir.
|
||
/// </summary>
|
||
private async Task EnsureModuleAsync(string moduleId)
|
||
{
|
||
var cleaned = moduleId?.Trim();
|
||
if (string.IsNullOrWhiteSpace(cleaned))
|
||
return;
|
||
|
||
if (await _repoModule.AnyAsync(a => a.Id == cleaned))
|
||
return;
|
||
|
||
await _repoModule.InsertAsync(new Module(cleaned) { Name = cleaned }, autoSave: true);
|
||
_logger.LogInformation("Module '{ModuleId}' seed sirasinda olusturuldu.", cleaned);
|
||
}
|
||
|
||
private async Task<PermissionDefinitionRecord> InsertPermissionAsync(
|
||
string groupName,
|
||
string name,
|
||
string parentName,
|
||
string displayName,
|
||
string modules)
|
||
{
|
||
var permission = new PermissionDefinitionRecord(
|
||
Guid.NewGuid(), groupName, name, parentName, displayName, true, MultiTenancySides.Both);
|
||
permission.SetModules(modules);
|
||
|
||
return await _repoPerm.InsertAsync(permission, autoSave: true);
|
||
}
|
||
|
||
private async Task BackfillMenuParentModuleIdAsync(ListFormWizardDto input)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(input.MenuParentCode) ||
|
||
string.IsNullOrWhiteSpace(input.MenuParentModuleId))
|
||
return;
|
||
|
||
await EnsureModuleAsync(input.MenuParentModuleId);
|
||
|
||
var menuParent = await _repoMenu.FirstOrDefaultAsync(a => a.Code == input.MenuParentCode);
|
||
if (menuParent == null || !string.IsNullOrWhiteSpace(menuParent.ModuleId))
|
||
return;
|
||
|
||
menuParent.ModuleId = input.MenuParentModuleId.Trim();
|
||
await _repoMenu.UpdateAsync(menuParent, autoSave: true);
|
||
_logger.LogInformation(
|
||
"Menu parent '{MenuParentCode}' ModuleId backfilled as '{ModuleId}'.",
|
||
input.MenuParentCode,
|
||
menuParent.ModuleId);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Wizard'in urettigi ekranin dil metinleri: menu adi, ust menu adi, izin grubu gorunen adi,
|
||
/// ekran basligi/aciklamasi ve alan basliklari. Ekran kurulumundan bagimsiz calisir; boylece
|
||
/// zaten kurulu bir ekranda eksik kalan anahtarlar da her seed calismasinda tamamlanir.
|
||
/// </summary>
|
||
private async Task SeedLanguageTextsAsync(ListFormWizardDto input, bool isCustomComponent)
|
||
{
|
||
await CreateLangKeyAsync(input.ResolveMenuCode(), input.MenuEn, input.MenuTr);
|
||
|
||
// Ust menu ve izin grubu paylasilan kayitlardir: ilk wizard onlari uretmis olsa bile dil
|
||
// metinleri eksik kalabilir, bu yuzden menu/grup kaydinin varligindan bagimsiz yazilir.
|
||
if (input.CreateMenu)
|
||
await CreateLangKeyAsync(input.MenuParentCode, input.MenuParentEn, input.MenuParentTr);
|
||
|
||
var groupName = ResolvePermissionGroupName(input);
|
||
|
||
// Grup adi ust menu koduyla ayniysa anahtar tektir; menu adi ile izin grubu adi ayni
|
||
// metni gosterir, ayrica gorunen ad girilmediyse menu metinlerine duser.
|
||
if (!string.Equals(groupName, input.MenuParentCode, StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
await CreateLangKeyAsync(groupName, input.PermissionGroupEn?.Trim(), input.PermissionGroupTr?.Trim());
|
||
}
|
||
else
|
||
{
|
||
await CreateLangKeyAsync(groupName,
|
||
input.PermissionGroupEn?.Trim() ?? input.MenuParentEn,
|
||
input.PermissionGroupTr?.Trim() ?? input.MenuParentTr);
|
||
}
|
||
|
||
// Custom yolunda ListForm ekosistemi (baslik, aciklama, alan basliklari) uretilmez.
|
||
if (isCustomComponent)
|
||
return;
|
||
|
||
var listFormCode = input.ResolveListFormCode();
|
||
await CreateLangKeyAsync($"{listFormCode}.Title", input.TitleEn, input.TitleTr);
|
||
await CreateLangKeyAsync($"{listFormCode}.Desc", input.DescEn, input.DescTr);
|
||
|
||
// Alan basliklarinin iki dilli metinleri yalnizca wizard bolumunde tasinir.
|
||
foreach (var item in (input.Groups ?? []).SelectMany(g => g.Items ?? []))
|
||
{
|
||
await CreateLangKeyAsync(item.CaptionName, item.EnglishCaption, item.TurkishCaption);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Yetkilerin toplanacagi izin grubu adi. Menuye eklenmeyen wizard'da grup sorulmaz; bos
|
||
/// geldiginde varsayilan uygulama grubuna duser.
|
||
/// </summary>
|
||
private static string ResolvePermissionGroupName(ListFormWizardDto input) =>
|
||
string.IsNullOrWhiteSpace(input.PermissionGroupName) ? AppName : input.PermissionGroupName.Trim();
|
||
|
||
private async Task CreateLangKeyAsync(string key, string textEn, string textTr)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(key)) return;
|
||
|
||
var langKey = await _repoLangKey.FirstOrDefaultAsync(a => a.ResourceName == _appName && a.Key == key)
|
||
?? await _repoLangKey.InsertAsync(new LanguageKey { ResourceName = _appName, Key = key }, autoSave: true);
|
||
|
||
var existingTexts = await _repoLangText.GetListAsync(a => a.ResourceName == _appName && a.Key == langKey.Key);
|
||
|
||
var existingEn = existingTexts.FirstOrDefault(a => a.CultureName == _cultureNameDefault);
|
||
if (existingEn == null)
|
||
{
|
||
await _repoLangText.InsertAsync(new LanguageText
|
||
{
|
||
ResourceName = _appName,
|
||
Key = langKey.Key,
|
||
CultureName = _cultureNameDefault,
|
||
Value = textEn ?? key
|
||
}, autoSave: true);
|
||
}
|
||
|
||
var existingTr = existingTexts.FirstOrDefault(a => a.CultureName == LanguageCodes.Tr);
|
||
if (existingTr == null)
|
||
{
|
||
await _repoLangText.InsertAsync(new LanguageText
|
||
{
|
||
ResourceName = _appName,
|
||
Key = langKey.Key,
|
||
CultureName = LanguageCodes.Tr,
|
||
Value = textTr ?? key
|
||
}, autoSave: true);
|
||
}
|
||
}
|
||
}
|
||
|
||
|