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; /// /// 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. /// public class WizardDataSeeder : IDataSeedContributor, ITransientDependency { private readonly IRepository _repoLangKey; private readonly IRepository _repoLangText; private readonly IRepository _repoPermGroup; private readonly IRepository _repoPerm; private readonly IPermissionGrantRepository _permissionGrantRepository; private readonly IRepository _repoMenu; private readonly IRepository _repoDataSource; private readonly IRepository _repoListForm; private readonly IRepository _repoListFormField; private readonly ILogger _logger; private readonly string _cultureNameDefault = PlatformConsts.DefaultLanguage; private readonly string _appName = PlatformConsts.AppName; public WizardDataSeeder( IRepository repoLangKey, IRepository repoLangText, IRepository repoPermGroup, IRepository repoPerm, IPermissionGrantRepository permissionGrantRepository, IRepository repoMenu, IRepository repoDataSource, IRepository repoListForm, IRepository repoListFormField, ILogger 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(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(); input.Widgets ??= new List(); input.Workflow ??= new WorkflowDto(); input.WorkflowCriteria ??= new List(); 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(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(input.Widgets.Count > 0 ? GridOptions.SelectionModeSingle : GridOptions.SelectionModeNone), 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 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); } } }