using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Identity; using Volo.Abp.MultiTenancy; using Volo.Abp.TenantManagement; namespace WinIn.FasterZ.AgGridReport.Data; public class AgGridReportDbMigrationService : ITransientDependency { public ILogger Logger { get; set; } private readonly IDataSeeder _dataSeeder; private readonly IEnumerable _dbSchemaMigrators; private readonly ITenantRepository _tenantRepository; private readonly ICurrentTenant _currentTenant; public AgGridReportDbMigrationService( IDataSeeder dataSeeder, IEnumerable dbSchemaMigrators, ITenantRepository tenantRepository, ICurrentTenant currentTenant) { _dataSeeder = dataSeeder; _dbSchemaMigrators = dbSchemaMigrators; _tenantRepository = tenantRepository; _currentTenant = currentTenant; Logger = NullLogger.Instance; } public async Task MigrateAsync() { var initialMigrationAdded = AddInitialMigrationIfNotExist(); if (initialMigrationAdded) { return; } Logger.LogInformation("Started database migrations..."); await MigrateDatabaseSchemaAsync(); await SeedDataAsync(); Logger.LogInformation($"Successfully completed host database migrations."); var tenants = await _tenantRepository.GetListAsync(includeDetails: true); var migratedDatabaseSchemas = new HashSet(); foreach (var tenant in tenants) { using (_currentTenant.Change(tenant.Id)) { if (tenant.ConnectionStrings.Any()) { var tenantConnectionStrings = tenant.ConnectionStrings .Select(x => x.Value) .ToList(); if (!migratedDatabaseSchemas.IsSupersetOf(tenantConnectionStrings)) { await MigrateDatabaseSchemaAsync(tenant); migratedDatabaseSchemas.AddIfNotContains(tenantConnectionStrings); } } await SeedDataAsync(tenant); } Logger.LogInformation($"Successfully completed {tenant.Name} tenant database migrations."); } Logger.LogInformation("Successfully completed all database migrations."); Logger.LogInformation("You can safely end this process..."); } private async Task MigrateDatabaseSchemaAsync(Tenant? tenant = null) { Logger.LogInformation( $"Migrating schema for {(tenant == null ? "host" : tenant.Name + " tenant")} database..."); foreach (var migrator in _dbSchemaMigrators) { await migrator.MigrateAsync(); } } private async Task SeedDataAsync(Tenant? tenant = null) { Logger.LogInformation($"Executing {(tenant == null ? "host" : tenant.Name + " tenant")} database seed..."); await _dataSeeder.SeedAsync(new DataSeedContext(tenant?.Id) .WithProperty(IdentityDataSeedContributor.AdminEmailPropertyName, IdentityDataSeedContributor.AdminEmailDefaultValue) .WithProperty(IdentityDataSeedContributor.AdminPasswordPropertyName, IdentityDataSeedContributor.AdminPasswordDefaultValue) ); } private bool AddInitialMigrationIfNotExist() { try { if (!DbMigrationsProjectExists()) { return false; } } catch (Exception) { return false; } try { if (!MigrationsFolderExists()) { AddInitialMigration(); return true; } else { return false; } } catch (Exception e) { Logger.LogWarning("Couldn't determinate if any migrations exist : " + e.Message); return false; } } private bool DbMigrationsProjectExists() { var dbMigrationsProjectFolder = GetEntityFrameworkCoreProjectFolderPath(); return dbMigrationsProjectFolder != null; } private bool MigrationsFolderExists() { var dbMigrationsProjectFolder = GetEntityFrameworkCoreProjectFolderPath(); return dbMigrationsProjectFolder != null && Directory.Exists(Path.Combine(dbMigrationsProjectFolder, "Migrations")); } private void AddInitialMigration() { Logger.LogInformation("Creating initial migration..."); string argumentPrefix; string fileName; if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { argumentPrefix = "-c"; fileName = "/bin/bash"; } else { argumentPrefix = "/C"; fileName = "cmd.exe"; } var procStartInfo = new ProcessStartInfo(fileName, $"{argumentPrefix} \"abp create-migration-and-run-migrator \"{GetEntityFrameworkCoreProjectFolderPath()}\"\"" ); try { Process.Start(procStartInfo); } catch (Exception) { throw new Exception("Couldn't run ABP CLI..."); } } private string? GetEntityFrameworkCoreProjectFolderPath() { var slnDirectoryPath = GetSolutionDirectoryPath(); if (slnDirectoryPath == null) { throw new Exception("Solution folder not found!"); } var srcDirectoryPath = Path.Combine(slnDirectoryPath, "src"); return Directory.GetDirectories(srcDirectoryPath) .FirstOrDefault(d => d.EndsWith(".EntityFrameworkCore")); } private string? GetSolutionDirectoryPath() { var currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory()); while (currentDirectory != null && Directory.GetParent(currentDirectory.FullName) != null) { currentDirectory = Directory.GetParent(currentDirectory.FullName); if (currentDirectory != null && Directory.GetFiles(currentDirectory.FullName).FirstOrDefault(f => f.EndsWith(".sln")) != null) { return currentDirectory.FullName; } } return null; } }