using System; using System.Globalization; using System.IO; using System.Linq; using System.Text.Json; using System.Threading.Tasks; using Kurs.Languages.Entities; using Kurs.Platform.Entities; using Kurs.Platform.Enums; using Kurs.Settings.Entities; using Microsoft.Extensions.Configuration; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Repositories; using Volo.Abp.MultiTenancy; using Volo.Abp.PermissionManagement; using Microsoft.EntityFrameworkCore; using EFCore.BulkExtensions; using System.Collections.Generic; using Kurs.Platform.Public; using static Kurs.Settings.SettingsConsts; using Kurs.Platform.Extensions; namespace Kurs.Platform.Data.Seeds; #region SeedDtos public class AiBotSeedDto { public string BotName { get; set; } } public class LanguageTextsSeedDto { public string ResourceName { get; set; } public string Key { get; set; } public string En { get; set; } public string Tr { get; set; } } public class BackgroundWorkerSeedDto { public string Name { get; set; } public string Cron { get; set; } public string WorkerType { get; set; } public bool IsActive { get; set; } public string DataSourceCode { get; set; } } public class NotificationRuleSeedDto { public string NotificationType { get; set; } public string RecipientType { get; set; } public string RecipientId { get; set; } public string Channel { get; set; } public bool IsActive { get; set; } public bool IsFixed { get; set; } public bool IsCustomized { get; set; } } public class MenuSeedDto { public string ParentCode { get; set; } public string Code { get; set; } public string DisplayName { get; set; } public int Order { get; set; } public string Url { get; set; } public string Icon { get; set; } public string RequiredPermissionName { get; set; } public bool IsDisabled { get; set; } } public class PermissionGroupDefinitionRecordSeedDto { public string Name { get; set; } public string DisplayName { get; set; } } public class PermissionDefinitionRecordSeedDto { public string GroupName { get; set; } public string Name { get; set; } public string ParentName { get; set; } public string DisplayName { get; set; } public bool IsEnabled { get; set; } public int MultiTenancySide { get; set; } public string MenuGroup { get; set; } } public class CurrencySeedDto { public string Code { get; set; } public string Symbol { get; set; } public string Name { get; set; } public bool IsActive { get; set; } } public class ContactTagSeedDto { public string Name { get; set; } public string Category { get; set; } } public class ContactTitleSeedDto { public string Title { get; set; } public string Abbreviation { get; set; } } public class RouteSeedDto { public string Key { get; set; } public string Path { get; set; } public string ComponentPath { get; set; } public string RouteType { get; set; } public string[] Authority { get; set; } } public class HostSeederDto { public List AiBots { get; set; } public List Languages { get; set; } public List LanguageTexts { get; set; } public List DataSources { get; set; } public List Settings { get; set; } public List BackgroundWorkers { get; set; } public List NotificationRules { get; set; } public List Menus { get; set; } public List PermissionGroupDefinitionRecords { get; set; } public List PermissionDefinitionRecords { get; set; } public List Currencies { get; set; } public List ContactTags { get; set; } public List ContactTitles { get; set; } public List Routes { get; set; } } #endregion public class HostDataSeeder : IDataSeedContributor, ITransientDependency { private readonly IRepository _aiBotRepository; private readonly IRepository _languages; private readonly IRepository _languageKey; private readonly IRepository _languagesText; private readonly IRepository _dataSources; private readonly IRepository _settings; private readonly IRepository _backgroundWorkerRepository; private readonly IRepository _menuRepository; private readonly IRepository _permissionGroupRepository; private readonly IRepository _permissionRepository; private readonly IRepository _currencyRepository; private readonly IRepository _countryGroupRepository; private readonly IRepository _countryRepository; private readonly IRepository _cityRepository; private readonly IRepository _districtRepository; private readonly IRepository _contactTagRepository; private readonly IRepository _contactTitleRepository; private readonly IRepository _routeRepository; public HostDataSeeder( IRepository aiBotRepository, IRepository languages, IRepository languageKey, IRepository languagesText, IRepository dataSource, IRepository settings, IRepository backgroundWorkerRepository, IRepository menuRepository, IRepository permissionGroupRepository, IRepository permissionRepository, IRepository currencyRepository, IRepository countryGroupRepository, IRepository countryRepository, IRepository cityRepository, IRepository districtRepository, IRepository contactTagRepository, IRepository contactTitleRepository, IRepository routeRepository ) { _languages = languages; _languageKey = languageKey; _languagesText = languagesText; _dataSources = dataSource; _settings = settings; _backgroundWorkerRepository = backgroundWorkerRepository; _menuRepository = menuRepository; _permissionGroupRepository = permissionGroupRepository; _permissionRepository = permissionRepository; _currencyRepository = currencyRepository; _countryGroupRepository = countryGroupRepository; _countryRepository = countryRepository; _cityRepository = cityRepository; _districtRepository = districtRepository; _contactTagRepository = contactTagRepository; _contactTitleRepository = contactTitleRepository; _aiBotRepository = aiBotRepository; _routeRepository = routeRepository; } private static IConfigurationRoot BuildConfiguration() { var builder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? ""}.json", true); return builder.Build(); } public async Task SeedCountyGroupsAsync() { var dbCtx = await _countryRepository.GetDbContextAsync(); // DB’de mevcut kodları set olarak al var existingCodes = (await dbCtx.Set() .Select(c => c.Name) .ToListAsync()) .ToHashSet(); var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; using var fs = File.OpenRead(Path.Combine("Seeds", "CountryGroups.json")); var buffer = new List(capacity: 1000); var seenCodes = new HashSet(); // JSON içindeki duplicate’leri yakalamak için await foreach (var item in JsonSerializer.DeserializeAsyncEnumerable(fs, options)) { if (item == null) continue; if (string.IsNullOrWhiteSpace(item.Name)) continue; // boş kodları atla // hem DB’de hem JSON içinde duplicate engelle if (!seenCodes.Add(item.Name) || existingCodes.Contains(item.Name)) continue; buffer.Add(new CountryGroup( Guid.NewGuid(), item.Name )); if (buffer.Count >= 1000) { await BulkCountryGroupInsertAsync(buffer); buffer.Clear(); } } if (buffer.Count > 0) { await BulkCountryGroupInsertAsync(buffer); } } private async Task BulkCountryGroupInsertAsync(List entities) { var dbCtx = await _countryGroupRepository.GetDbContextAsync(); await dbCtx.BulkInsertAsync(entities, new BulkConfig { BatchSize = 1000 }); } public async Task SeedCountriesAsync() { var dbCtx = await _countryRepository.GetDbContextAsync(); // DB’de mevcut kodları set olarak al var existingCodes = (await dbCtx.Set() .Select(c => c.Code) .ToListAsync()) .ToHashSet(); var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; using var fs = File.OpenRead(Path.Combine("Seeds", "Countries.json")); var buffer = new List(capacity: 1000); var seenCodes = new HashSet(); // JSON içindeki duplicate’leri yakalamak için await foreach (var item in JsonSerializer.DeserializeAsyncEnumerable(fs, options)) { if (item == null) continue; if (string.IsNullOrWhiteSpace(item.Code)) continue; // boş kodları atla // hem DB’de hem JSON içinde duplicate engelle if (!seenCodes.Add(item.Code) || existingCodes.Contains(item.Code)) continue; var currency = await _currencyRepository.FirstOrDefaultAsync(c => c.Code == item.CurrencyCode); buffer.Add(new Country( Guid.NewGuid(), item.Code, item.Name, item.GroupName, currency != null ? currency.Id : null, item.PhoneCode, item.TaxLabel )); if (buffer.Count >= 1000) { await BulkCountryInsertAsync(buffer); buffer.Clear(); } } if (buffer.Count > 0) { await BulkCountryInsertAsync(buffer); } } private async Task BulkCountryInsertAsync(List entities) { var dbCtx = await _countryRepository.GetDbContextAsync(); await dbCtx.BulkInsertAsync(entities, new BulkConfig { BatchSize = 1000 }); } public async Task SeedCitiesAsync() { var dbCtx = await _cityRepository.GetDbContextAsync(); // 1. Mevcut kayıtları çek (tek sorguda) var existingCities = await dbCtx.Set() .Select(d => new { d.Code }) .ToListAsync(); var existingSet = existingCities .Select(d => d.Code) .ToHashSet(); var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; // 2. JSON’u stream et using FileStream fs = File.OpenRead(Path.Combine("Seeds", "Cities.json")); var buffer = new List(capacity: 5000); await foreach (var item in JsonSerializer.DeserializeAsyncEnumerable(fs, options)) { if (item == null) continue; var key = $"{item.Country}.{item.Code}"; if (existingSet.Contains(key)) continue; // duplicate kontrolü buffer.Add(new City( Guid.NewGuid(), item.Country, item.Name, key, item.PlateCode )); if (buffer.Count >= 1000) // 3. Batch { await BulkCityInsertAsync(buffer); buffer.Clear(); } } if (buffer.Count > 0) { await BulkCityInsertAsync(buffer); } } private async Task BulkCityInsertAsync(List entities) { var dbCtx = await _cityRepository.GetDbContextAsync(); await dbCtx.BulkInsertAsync(entities, new BulkConfig { PreserveInsertOrder = true, SetOutputIdentity = true, BatchSize = 1000 }); } public async Task SeedDistrictsAsync() { var dbCtx = await _districtRepository.GetDbContextAsync(); // 1. Mevcut kayıtları çek (tek sorguda) var existingDistricts = await dbCtx.Set() .Select(d => new { d.Country, d.City, d.Name, d.Township, d.Street, d.ZipCode }) .ToListAsync(); var existingSet = existingDistricts .Select(d => $"{d.Country}:{d.City}:{d.Name}:{d.Township}:{d.Street}:{d.ZipCode}") .ToHashSet(); var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; // 2. JSON’u stream et using FileStream fs = File.OpenRead(Path.Combine("Seeds", "Districts.json")); var buffer = new List(capacity: 5000); await foreach (var item in JsonSerializer.DeserializeAsyncEnumerable(fs, options)) { if (item == null) continue; var key = $"{item.Country}:{item.Country}.{item.City}:{item.Name}:{item.Township}:{item.Street}:{item.ZipCode}"; var city = $"{item.Country}.{item.City}"; if (existingSet.Contains(key)) continue; buffer.Add(new District( Guid.NewGuid(), item.Country, city, item.Name, item.Township, item.Street, item.ZipCode )); if (buffer.Count >= 5000) // 3. Batch { await BulkDistrictInsertAsync(buffer); buffer.Clear(); } } if (buffer.Count > 0) { await BulkDistrictInsertAsync(buffer); } } private async Task BulkDistrictInsertAsync(List entities) { var dbCtx = await _districtRepository.GetDbContextAsync(); await dbCtx.BulkInsertAsync(entities, new BulkConfig { PreserveInsertOrder = true, SetOutputIdentity = true, BatchSize = 5000 }); } public async Task SeedAsync(DataSeedContext context) { var settings = await _settings.GetListAsync(); var dataSources = await _dataSources.GetListAsync(); var languages = await _languages.GetListAsync(); var keys = await _languageKey.GetListAsync(); var texts = await _languagesText.GetListAsync(); var configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile(Path.Combine("Seeds", "HostData.json")) .AddJsonFile(Path.Combine("Seeds", $"HostData.{Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? ""}.json"), true) .AddJsonFile(Path.Combine("Seeds", "LanguagesData.json")) .AddJsonFile(Path.Combine("Seeds", "MenusData.json")) .AddJsonFile(Path.Combine("Seeds", "PermissionsData.json")) .Build(); var items = configuration.Get(); var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; foreach (var item in items.Settings) { if (!settings.Any(a => a.Code == item.Code)) { await _settings.InsertAsync(new() { Code = item.Code, NameKey = item.NameKey, DescriptionKey = item.DescriptionKey, DefaultValue = item.DefaultValue.Replace("\r\n", Environment.NewLine), IsVisibleToClients = item.IsVisibleToClients, IsInherited = item.IsInherited, IsEncrypted = item.IsEncrypted, MainGroupKey = item.MainGroupKey, SubGroupKey = item.SubGroupKey, RequiredPermissionName = item.RequiredPermissionName, DataType = item.DataType, Providers = item.Providers, SelectOptions = item.SelectOptions, Order = item.Order }); } } if (!dataSources.Any(a => a.Code == SeedConsts.DataSources.DefaultCode)) { var config = BuildConfiguration(); await _dataSources.InsertAsync(new() { Code = SeedConsts.DataSources.DefaultCode, DataSourceType = DefaultDatabaseProvider == DatabaseProvider.SqlServer ? DataSourceTypeEnum.Mssql : DataSourceTypeEnum.Postgresql, ConnectionString = config.GetConnectionString(DefaultDatabaseProvider) }); } foreach (var item in items.Languages) { if (!languages.Any(a => a.CultureName == item.CultureName)) { await _languages.InsertAsync(new() { CultureName = item.CultureName, UiCultureName = item.UiCultureName, DisplayName = item.DisplayName, IsEnabled = item.IsEnabled, TwoLetterISOLanguageName = new CultureInfo(item.CultureName).TwoLetterISOLanguageName, }); } } foreach (var item in items.LanguageTexts) { try { if (!keys.Any(a => a.Key == item.Key)) { await _languageKey.InsertAsync(new() { Key = item.Key, ResourceName = item.ResourceName, }); } if (!texts.Any(a => a.CultureName == "en" && a.Key == item.Key)) { await _languagesText.InsertAsync(new() { CultureName = "en", Key = item.Key, Value = item.En, ResourceName = item.ResourceName, }); } if (!texts.Any(a => a.CultureName == "tr" && a.Key == item.Key)) { await _languagesText.InsertAsync(new() { CultureName = "tr", Key = item.Key, Value = item.Tr, ResourceName = item.ResourceName, }); } } catch (Exception ex) { throw new Exception($"Hata veren Kod:' ResourceName='{item.ResourceName}', Key='{item.Key}' Message='{ex.Message}'"); } } foreach (var item in items.BackgroundWorkers) { if (!await _backgroundWorkerRepository.AnyAsync(x => x.Name == item.Name)) { await _backgroundWorkerRepository.InsertAsync(new BackgroundWorker { Name = item.Name, Cron = item.Cron, WorkerType = Enum.Parse(item.WorkerType), IsActive = item.IsActive, DataSourceCode = item.DataSourceCode }); } } foreach (var item in items.Menus) { var exists = await _menuRepository.AnyAsync(x => x.Code == item.Code); if (!exists) { await _menuRepository.InsertAsync(new Menu { ParentCode = string.IsNullOrWhiteSpace(item.ParentCode) ? null : item.ParentCode, Code = item.Code, DisplayName = item.DisplayName, Order = item.Order, Url = item.Url, Icon = item.Icon, RequiredPermissionName = item.RequiredPermissionName, IsDisabled = item.IsDisabled, }); } } foreach (var item in items.PermissionGroupDefinitionRecords) { var exists = await _permissionGroupRepository.AnyAsync(x => x.Name == item.Name); if (!exists) { await _permissionGroupRepository.InsertAsync(new PermissionGroupDefinitionRecord { Name = item.Name, DisplayName = item.DisplayName }); } } foreach (var item in items.PermissionDefinitionRecords) { var exists = await _permissionRepository.AnyAsync(x => x.Name == item.Name); if (!exists) { var perm = new PermissionDefinitionRecord { GroupName = item.GroupName, Name = item.Name, ParentName = string.IsNullOrWhiteSpace(item.ParentName) ? null : item.ParentName, DisplayName = item.DisplayName, IsEnabled = item.IsEnabled, MultiTenancySide = (MultiTenancySides)item.MultiTenancySide, }; perm.SetMenuGroup(item.MenuGroup); await _permissionRepository.InsertAsync(perm); } } foreach (var item in items.Currencies) { var exists = await _currencyRepository.AnyAsync(x => x.Code == item.Code); if (!exists) { await _currencyRepository.InsertAsync(new Currency { Code = item.Code, Symbol = item.Symbol, Name = item.Name, IsActive = item.IsActive }, autoSave: true); } } foreach (var item in items.ContactTags) { var exists = await _contactTagRepository.AnyAsync(x => x.Name == item.Name); if (!exists) { await _contactTagRepository.InsertAsync(new ContactTag { Name = item.Name, Category = item.Category, }); } } foreach (var item in items.ContactTitles) { var exists = await _contactTitleRepository.AnyAsync(x => x.Title == item.Title); if (!exists) { await _contactTitleRepository.InsertAsync(new ContactTitle { Title = item.Title, Abbreviation = item.Abbreviation, }); } } foreach (var item in items.AiBots) { var exists = await _aiBotRepository.AnyAsync(x => x.BotName == item.BotName); if (!exists) { await _aiBotRepository.InsertAsync(new AiBot { BotName = item.BotName, }); } } foreach (var item in items.Routes) { var exists = await _routeRepository.AnyAsync(x => x.Key == item.Key); if (!exists) { await _routeRepository.InsertAsync(new Route( item.Key, item.Path, item.ComponentPath, item.RouteType, item.Authority ?? [] )); } } await SeedCountyGroupsAsync(); await SeedCountriesAsync(); await SeedCitiesAsync(); await SeedDistrictsAsync(); } }