sozsoft-platform/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardDataSeeder.cs
2026-06-06 18:22:14 +03:00

462 lines
22 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.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("WizardData directory not found, skipping.");
return;
}
var jsonFiles = Directory.GetFiles(wizardDataPath, "*.json").OrderBy(f => Path.GetFileName(f)).ToArray();
if (jsonFiles.Length == 0)
{
_logger.LogInformation("No JSON files found in WizardData directory, skipping.");
return;
}
_logger.LogInformation("WizardDataSeeder started. {Count} files to be processed.", jsonFiles.Length);
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);
continue;
}
var wizardName = seedFile.Wizard.WizardName?.Trim();
if (string.IsNullOrWhiteSpace(wizardName))
{
_logger.LogWarning("WizardName is empty, skipped: {FilePath}", filePath);
continue;
}
var fileName = Path.GetFileName(filePath);
// 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);
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;
var isDeleted = seedFile.IsDeletedField;
var isCreated = seedFile.IsCreatedField;
input.SubForms ??= new List<SubFormDto>();
input.Widgets ??= new List<WidgetEditDto>();
input.Workflow ??= new WorkflowDto();
input.WorkflowCriteria ??= new List<ListFormWorkflowCriteriaDto>();
input.Workflow.Criteria = input.WorkflowCriteria;
var wizardName = input.WizardName.Trim();
var code = string.IsNullOrWhiteSpace(input.MenuCode)
? WizardConsts.WizardKey(wizardName)
: input.MenuCode.Trim();
var listFormCode = string.IsNullOrWhiteSpace(input.ListFormCode)
? code
: input.ListFormCode.Trim();
var titleLangKey = $"{listFormCode}.Title";
var nameLangKey = code;
var descLangKey = $"{listFormCode}.Desc";
var permCreateName = $"{code}.Create";
var permUpdateName = $"{code}.Update";
var permDeleteName = $"{code}.Delete";
var permExportName = $"{code}.Export";
var permImportName = $"{code}.Import";
var permNoteName = $"{code}.Note";
// 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);
if (string.Equals(groupName, input.MenuParentCode, StringComparison.OrdinalIgnoreCase))
await EnsureLangKeyAsync(groupName);
else
await CreateLangKeyAsync(groupName, groupName, groupName);
}
// 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();
var permRead = existingPerms.FirstOrDefault(a => a.Name == code);
if (permRead == null)
permRead = await _repoPerm.InsertAsync(new PermissionDefinitionRecord(
Guid.NewGuid(), groupName, code, null, nameLangKey, true, MultiTenancySides.Both), autoSave: true);
var permCreate = existingPerms.FirstOrDefault(a => a.Name == permCreateName);
if (permCreate == null)
permCreate = await _repoPerm.InsertAsync(new PermissionDefinitionRecord(
Guid.NewGuid(), groupName, permCreateName, permRead.Name, WizardConsts.LangKeyCreate, true, MultiTenancySides.Both), autoSave: true);
var permUpdate = existingPerms.FirstOrDefault(a => a.Name == permUpdateName);
if (permUpdate == null)
permUpdate = await _repoPerm.InsertAsync(new PermissionDefinitionRecord(
Guid.NewGuid(), groupName, permUpdateName, permRead.Name, WizardConsts.LangKeyUpdate, true, MultiTenancySides.Both), autoSave: true);
var permDelete = existingPerms.FirstOrDefault(a => a.Name == permDeleteName);
if (permDelete == null)
permDelete = await _repoPerm.InsertAsync(new PermissionDefinitionRecord(
Guid.NewGuid(), groupName, permDeleteName, permRead.Name, WizardConsts.LangKeyDelete, true, MultiTenancySides.Both), autoSave: true);
var permExport = existingPerms.FirstOrDefault(a => a.Name == permExportName);
if (permExport == null)
permExport = await _repoPerm.InsertAsync(new PermissionDefinitionRecord(
Guid.NewGuid(), groupName, permExportName, permRead.Name, WizardConsts.LangKeyExport, true, MultiTenancySides.Both), autoSave: true);
var permImport = existingPerms.FirstOrDefault(a => a.Name == permImportName);
if (permImport == null)
permImport = await _repoPerm.InsertAsync(new PermissionDefinitionRecord(
Guid.NewGuid(), groupName, permImportName, permRead.Name, WizardConsts.LangKeyImport, true, MultiTenancySides.Both), autoSave: true);
var permNote = existingPerms.FirstOrDefault(a => a.Name == permNoteName);
if (permNote == null)
permNote = await _repoPerm.InsertAsync(new PermissionDefinitionRecord(
Guid.NewGuid(), groupName, permNoteName, 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);
// }
// Menu Parent
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;
await CreateLangKeyAsync(input.MenuParentCode, input.LanguageTextMenuParentEn, input.LanguageTextMenuParentTr);
menuParent = await _repoMenu.InsertAsync(new Menu
{
Code = input.MenuParentCode,
DisplayName = input.MenuParentCode,
IsDisabled = false,
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 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 = WizardConsts.MenuUrl(code),
RequiredPermissionName = permRead.Name,
Order = maxChildOrder + 1,
}, autoSave: true);
}
// 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);
}
// 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);
}
// ListForm
await _repoListForm.InsertAsync(new ListForm
{
ListFormType = ListFormTypeEnum.List,
PageSize = 10,
ExportJson = WizardConsts.DefaultExportJson,
IsSubForm = false,
ShowNote = input.SubForms.Count > 0,
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,
SubFormsJson = input.SubForms.Count > 0 ? JsonSerializer.Serialize(input.SubForms) : null,
WidgetsJson = input.Widgets.Count > 0 ? JsonSerializer.Serialize(input.Widgets) : null,
WorkflowJson = HasWorkflow(input.Workflow, input.WorkflowCriteria) ? JsonSerializer.Serialize(input.Workflow) : 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.
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 static bool HasWorkflow(WorkflowDto workflow, List<ListFormWorkflowCriteriaDto> criteria)
{
return workflow != null && (
!string.IsNullOrWhiteSpace(workflow.ApprovalUserFieldName) ||
!string.IsNullOrWhiteSpace(workflow.ApprovalDateFieldName) ||
!string.IsNullOrWhiteSpace(workflow.ApprovalStatusFieldName) ||
!string.IsNullOrWhiteSpace(workflow.ApprovalDescriptionFieldName) ||
(criteria?.Count ?? 0) > 0
);
}
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);
}
}
private async Task EnsureLangKeyAsync(string key)
{
if (string.IsNullOrWhiteSpace(key)) return;
if (!await _repoLangKey.AnyAsync(a => a.ResourceName == _appName && a.Key == key))
{
await _repoLangKey.InsertAsync(new LanguageKey { ResourceName = _appName, Key = key }, autoSave: true);
}
}
}