sozsoft-platform/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardDataSeeder.cs

414 lines
19 KiB
C#
Raw Normal View History

2026-05-02 17:08:06 +00:00
using System;
using System.Collections.Generic;
2026-05-02 17:08:06 +00:00
using System.Data;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Sozsoft.Languages.Entities;
using Sozsoft.Languages.Languages;
using Sozsoft.Platform.Entities;
using Sozsoft.Platform.Enums;
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/WizardData/*.json dosyalarından okuyarak veritabanına aktarır.
/// 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 IPermissionGrantRepository _permissionGrantRepository;
private readonly IRepository<Menu, Guid> _repoMenu;
private readonly IRepository<DataSource, Guid> _repoDataSource;
private readonly IRepository<ListForm, Guid> _repoListForm;
private readonly IRepository<ListFormField, Guid> _repoListFormField;
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,
IPermissionGrantRepository permissionGrantRepository,
IRepository<Menu, Guid> repoMenu,
IRepository<DataSource, Guid> repoDataSource,
IRepository<ListForm, Guid> repoListForm,
IRepository<ListFormField, Guid> repoListFormField,
ILogger<WizardDataSeeder> logger)
{
_repoLangKey = repoLangKey;
_repoLangText = repoLangText;
_repoPermGroup = repoPermGroup;
_repoPerm = repoPerm;
_permissionGrantRepository = permissionGrantRepository;
_repoMenu = repoMenu;
_repoDataSource = repoDataSource;
_repoListForm = repoListForm;
_repoListFormField = repoListFormField;
_logger = logger;
}
public async Task SeedAsync(DataSeedContext context)
{
var wizardDataPath = Path.Combine(Directory.GetCurrentDirectory(), "Seeds", "WizardData");
if (!Directory.Exists(wizardDataPath))
{
_logger.LogInformation("Seeds/WizardData directory not found, skipping.");
2026-05-02 17:08:06 +00:00
return;
}
var jsonFiles = Directory.GetFiles(wizardDataPath, "*.json").OrderBy(f => Path.GetFileName(f)).ToArray();
if (jsonFiles.Length == 0)
{
_logger.LogInformation("No JSON files found in Seeds/WizardData directory, skipping.");
2026-05-02 17:08:06 +00:00
return;
}
_logger.LogInformation("WizardDataSeeder started. {Count} files to be processed.", jsonFiles.Length);
2026-05-02 17:08:06 +00:00
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
foreach (var filePath in jsonFiles)
{
try
{
var json = await File.ReadAllTextAsync(filePath);
var seedFile = JsonSerializer.Deserialize<WizardSeedFileDto>(json, options);
if (seedFile?.Wizard == null)
{
_logger.LogWarning("Invalid file skipped: {FilePath}", filePath);
2026-05-02 17:08:06 +00:00
continue;
}
var wizardName = seedFile.Wizard.WizardName?.Trim();
if (string.IsNullOrWhiteSpace(wizardName))
{
_logger.LogWarning("WizardName is empty, skipped: {FilePath}", filePath);
2026-05-02 17:08:06 +00:00
continue;
}
var fileName = Path.GetFileName(filePath);
2026-05-02 17:08:06 +00:00
// Zaten seeded mi kontrol et (ListForm var mı?)
if (await _repoListForm.AnyAsync(a => a.ListFormCode == seedFile.Wizard.ListFormCode))
{
_logger.LogInformation("[{File}] '{WizardName}' already exists, skipped.", fileName, wizardName);
2026-05-02 17:08:06 +00:00
continue;
}
_logger.LogInformation("[{File}] '{WizardName}' is being applied...", fileName, wizardName);
2026-05-02 17:08:06 +00:00
await ApplyWizardSeedAsync(seedFile);
_logger.LogInformation("[{File}] '{WizardName}' has been successfully applied.", fileName, wizardName);
2026-05-02 17:08:06 +00:00
}
catch (Exception ex)
{
_logger.LogError(ex, $"Hata - {filePath}: {ex.Message}");
}
}
}
private async Task ApplyWizardSeedAsync(WizardSeedFileDto seedFile)
{
var input = seedFile.Wizard;
var isDeleted = seedFile.IsDeletedField;
var isCreated = seedFile.IsCreatedField;
var wizardName = input.WizardName.Trim();
var titleLangKey = WizardConsts.WizardKeyTitle(wizardName);
var nameLangKey = WizardConsts.WizardKey(wizardName);
var descLangKey = WizardConsts.WizardKeyDesc(wizardName);
var code = WizardConsts.WizardKey(wizardName);
// Dil - Language Keys
await CreateLangKeyAsync(nameLangKey, input.LanguageTextMenuEn, input.LanguageTextMenuTr);
await CreateLangKeyAsync(titleLangKey, input.LanguageTextTitleEn, input.LanguageTextTitleTr);
await CreateLangKeyAsync(descLangKey, input.LanguageTextDescEn, input.LanguageTextDescTr);
// Permission Group
var groupName = input.PermissionGroupName ?? AppName;
if (!await _repoPermGroup.AnyAsync(a => a.Name == groupName))
{
await _repoPermGroup.InsertAsync(
new PermissionGroupDefinitionRecord(Guid.NewGuid(), groupName, groupName), autoSave: true);
await CreateLangKeyAsync(groupName, groupName, groupName);
}
// Permissions - tek seferde mevcut permission'ları çek, sonra her birini kontrol et
2026-05-02 17:08:06 +00:00
var permQueryable = await _repoPerm.GetQueryableAsync();
var existingPerms = permQueryable.Where(a => a.GroupName == groupName).ToList();
var permRead = existingPerms.FirstOrDefault(a => a.Name == code);
if (permRead == null)
permRead = await _repoPerm.InsertAsync(new PermissionDefinitionRecord(
2026-05-02 17:08:06 +00:00
Guid.NewGuid(), groupName, code, null, nameLangKey, true, MultiTenancySides.Both), autoSave: true);
var permCreate = existingPerms.FirstOrDefault(a => a.Name == WizardConsts.PermCreate(wizardName));
if (permCreate == null)
permCreate = await _repoPerm.InsertAsync(new PermissionDefinitionRecord(
2026-05-02 17:08:06 +00:00
Guid.NewGuid(), groupName, WizardConsts.PermCreate(wizardName), permRead.Name, WizardConsts.LangKeyCreate, true, MultiTenancySides.Both), autoSave: true);
var permUpdate = existingPerms.FirstOrDefault(a => a.Name == WizardConsts.PermUpdate(wizardName));
if (permUpdate == null)
permUpdate = await _repoPerm.InsertAsync(new PermissionDefinitionRecord(
2026-05-02 17:08:06 +00:00
Guid.NewGuid(), groupName, WizardConsts.PermUpdate(wizardName), permRead.Name, WizardConsts.LangKeyUpdate, true, MultiTenancySides.Both), autoSave: true);
var permDelete = existingPerms.FirstOrDefault(a => a.Name == WizardConsts.PermDelete(wizardName));
if (permDelete == null)
permDelete = await _repoPerm.InsertAsync(new PermissionDefinitionRecord(
2026-05-02 17:08:06 +00:00
Guid.NewGuid(), groupName, WizardConsts.PermDelete(wizardName), permRead.Name, WizardConsts.LangKeyDelete, true, MultiTenancySides.Both), autoSave: true);
var permExport = existingPerms.FirstOrDefault(a => a.Name == WizardConsts.PermExport(wizardName));
if (permExport == null)
permExport = await _repoPerm.InsertAsync(new PermissionDefinitionRecord(
2026-05-02 17:08:06 +00:00
Guid.NewGuid(), groupName, WizardConsts.PermExport(wizardName), permRead.Name, WizardConsts.LangKeyExport, true, MultiTenancySides.Both), autoSave: true);
var permImport = existingPerms.FirstOrDefault(a => a.Name == WizardConsts.PermImport(wizardName));
if (permImport == null)
permImport = await _repoPerm.InsertAsync(new PermissionDefinitionRecord(
2026-05-02 17:08:06 +00:00
Guid.NewGuid(), groupName, WizardConsts.PermImport(wizardName), permRead.Name, WizardConsts.LangKeyImport, true, MultiTenancySides.Both), autoSave: true);
var permNote = existingPerms.FirstOrDefault(a => a.Name == WizardConsts.PermNote(wizardName));
if (permNote == null)
permNote = await _repoPerm.InsertAsync(new PermissionDefinitionRecord(
2026-05-02 17:08:06 +00:00
Guid.NewGuid(), groupName, WizardConsts.PermNote(wizardName), permRead.Name, WizardConsts.LangKeyNote, true, MultiTenancySides.Both), autoSave: true);
// // 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);
// }
2026-05-02 17:08:06 +00:00
// Menu Parent
var menuQueryable = await _repoMenu.GetQueryableAsync();
2026-05-02 17:08:06 +00:00
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;
2026-05-02 17:08:06 +00:00
await CreateLangKeyAsync(WizardConsts.WizardKeyParent(wizardName), input.LanguageTextMenuParentEn, input.LanguageTextMenuParentTr);
menuParent = await _repoMenu.InsertAsync(new Menu
{
Code = input.MenuParentCode,
DisplayName = WizardConsts.WizardKeyParent(wizardName),
IsDisabled = false,
Order = maxRootOrder + 1,
2026-05-02 17:08:06 +00:00
}, autoSave: true);
}
// Menu
var maxChildOrder = menuQueryable.Where(a => a.ParentCode == menuParent.Code).Select(a => (int?)a.Order).Max() ?? 0;
var existingMenu = await _repoMenu.FirstOrDefaultAsync(a => a.Code == code);
if (existingMenu == null)
2026-05-02 17:08:06 +00:00
{
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 = WizardConsts.MenuUrl(code),
RequiredPermissionName = permRead.Name,
Order = maxChildOrder + 1,
2026-05-02 17:08:06 +00:00
}, autoSave: true);
}
// DataSource
var existingDataSource = await _repoDataSource.FirstOrDefaultAsync(a => a.Code == input.DataSourceCode);
if (existingDataSource == null)
2026-05-02 17:08:06 +00:00
{
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);
}
2026-05-02 17:08:06 +00:00
// EditingFormJson
var editingFormDtos = input.Groups
.Select((g, gi) => new EditingFormDto
{
Order = gi + 1,
Caption = g.Caption,
ColCount = g.ColCount,
ColSpan = g.ColCount,
ItemType = "group",
Items = g.Items
.Where(i => i.DataField != input.KeyFieldName)
.Select((it, ii) => new EditingFormItemDto
{
Order = ii + 1,
DataField = it.DataField,
EditorType2 = it.EditorType,
ColSpan = it.ColSpan,
EditorOptions = string.IsNullOrWhiteSpace(it.EditorOptions) ? null : it.EditorOptions,
EditorScript = string.IsNullOrWhiteSpace(it.EditorScript) ? null : it.EditorScript,
IsRequired = it.IsRequired,
})
.ToArray()
})
.ToList();
// ListForm - varsa sil, yeniden ekle
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);
}
2026-05-02 17:08:06 +00:00
// ListForm
await _repoListForm.InsertAsync(new ListForm
{
ListFormType = ListFormTypeEnum.List,
PageSize = 10,
ExportJson = WizardConsts.DefaultExportJson,
IsSubForm = false,
ShowNote = true,
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler),
CultureName = LanguageCodes.En,
ListFormCode = input.ListFormCode,
Name = nameLangKey,
Title = titleLangKey,
Description = descLangKey,
DataSourceCode = input.DataSourceCode,
IsTenant = input.IsTenant,
IsBranch = input.IsBranch,
IsOrganizationUnit = input.IsOrganizationUnit,
SelectCommandType = input.SelectCommandType,
SelectCommand = input.SelectCommand,
KeyFieldName = input.KeyFieldName,
KeyFieldDbSourceType = input.KeyFieldDbSourceType,
DefaultFilter = isDeleted ? WizardConsts.DefaultFilterJson : null,
SortMode = GridOptions.SortModeSingle,
FilterRowJson = WizardConsts.DefaultFilterRowJson,
HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson,
SearchPanelJson = WizardConsts.DefaultSearchPanelJson,
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
SelectionJson = WizardConsts.DefaultSelectionSingleJson,
ColumnOptionJson = WizardConsts.DefaultColumnOptionJson(),
PermissionJson = WizardConsts.DefaultPermissionJson(code),
DeleteCommand = isDeleted ? WizardConsts.DefaultDeleteCommand(input.SelectCommand) : null,
DeleteFieldsDefaultValueJson = isDeleted
? WizardConsts.DefaultDeleteFieldsDefaultValueJson(input.KeyFieldDbSourceType)
: WizardConsts.DefaultFieldsJsonOnlyId(input.KeyFieldDbSourceType),
InsertFieldsDefaultValueJson = isCreated
? WizardConsts.DefaultInsertFieldsDefaultValueJson(input.KeyFieldDbSourceType)
: WizardConsts.DefaultFieldsJsonOnlyId(input.KeyFieldDbSourceType),
PagerOptionJson = WizardConsts.DefaultPagerOptionJson,
EditingOptionJson = WizardConsts.DefaultEditingOptionJson(titleLangKey, 600, 500, input.AllowDeleting, input.AllowAdding, input.AllowUpdating, input.ConfirmDelete, false, input.AllowDetail),
EditingFormJson = editingFormDtos.Count > 0 ? JsonSerializer.Serialize(editingFormDtos) : null,
}, autoSave: true);
// ListFormFields
var fieldOrder = 0;
foreach (var group in input.Groups)
{
foreach (var item in group.Items)
{
fieldOrder++;
await _repoListFormField.InsertAsync(new ListFormField
{
ListFormCode = input.ListFormCode,
FieldName = item.DataField,
CaptionName = item.CaptionName,
Visible = item.DataField != input.KeyFieldName,
IsActive = true,
Width = 0, //Fit columns için hepsine sıfır veriyorum.
2026-05-02 17:08:06 +00:00
AllowSearch = true,
ListOrderNo = fieldOrder,
SourceDbType = item.DbSourceType,
CultureName = PlatformConsts.DefaultLanguage,
PermissionJson = WizardConsts.DefaultFieldPermissionJson(code),
ColumnCustomizationJson = WizardConsts.DefaultColumnCustomizationJson,
ColumnFilterJson = WizardConsts.DefaultColumnFilteringJson,
PivotSettingsJson = WizardConsts.DefaultPivotSettingsJson,
LookupJson = !string.IsNullOrWhiteSpace(item.LookupQuery)
? WizardConsts.DefaultLookupJson(item.LookupDataSourceType, item.DisplayExpr, item.ValueExpr, item.LookupQuery)
: null,
}, autoSave: true);
await CreateLangKeyAsync(item.CaptionName, item.EnglishCaption, item.TurkishCaption);
}
}
}
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);
}
}
}