using System.Text.RegularExpressions; using Cloud; using DatabaseTest.Models; using Microsoft.EntityFrameworkCore; using Npgsql; namespace DatabaseTest.Services; public interface IDatabaseConfigService { DatabaseProviderType ProviderType { get; } string ConnectionString { get; } string InMemoryDbName { get; } event Action? OnConfigurationChanged; void SetProvider(DatabaseProviderType providerType); void SetConnectionString(string connectionString); void SetInMemoryDbName(string name); AppDbContext CreateDbContext(); string GetActiveProviderDescription(); } public class DatabaseConfigService : IDatabaseConfigService { private readonly IConfiguration _configuration; public DatabaseConfigService(IConfiguration configuration) { _configuration = configuration; var envPassword = Environment.GetEnvironmentVariable("PostgreSQL_Password") ?? (OperatingSystem.IsWindows() ? Environment.GetEnvironmentVariable("PostgreSQL_Password", EnvironmentVariableTarget.User) : null) ?? (OperatingSystem.IsWindows() ? Environment.GetEnvironmentVariable("PostgreSQL_Password", EnvironmentVariableTarget.Machine) : null) ?? Environment.GetEnvironmentVariable("POSTGRESQL_PASSWORD") ?? Environment.GetEnvironmentVariable("POSTGRES_PASSWORD"); var configuredConn = _configuration.GetConnectionString("DefaultConnection") ?? _configuration.GetConnectionString("Postgres") ?? Environment.GetEnvironmentVariable("POSTGRES_CONNECTION_STRING"); if (string.IsNullOrWhiteSpace(configuredConn)) { var csb = new NpgsqlConnectionStringBuilder { Host = "localhost", Database = "chrono", Username = "postgres", Password = envPassword }; configuredConn = csb.ConnectionString; } else if (!string.IsNullOrEmpty(envPassword)) { try { var csb = new NpgsqlConnectionStringBuilder(configuredConn) { Password = envPassword }; configuredConn = csb.ConnectionString; } catch { } } ConnectionString = configuredConn; ProviderType = DatabaseProviderType.PostgreSQL; } public event Action? OnConfigurationChanged; public DatabaseProviderType ProviderType { get; private set; } public string ConnectionString { get; private set; } public string InMemoryDbName { get; private set; } = "chrono_database_test"; public void SetProvider(DatabaseProviderType providerType) { if (ProviderType != providerType) { ProviderType = providerType; OnConfigurationChanged?.Invoke(); } } public void SetConnectionString(string connectionString) { if (ConnectionString != connectionString) { ConnectionString = connectionString; OnConfigurationChanged?.Invoke(); } } public void SetInMemoryDbName(string name) { if (InMemoryDbName != name) { InMemoryDbName = name; OnConfigurationChanged?.Invoke(); } } public string GetActiveProviderDescription() { return ProviderType switch { DatabaseProviderType.PostgreSQL => $"PostgreSQL ({GetMaskedConnectionString(ConnectionString)})", DatabaseProviderType.InMemory => $"In-Memory Test Database ({InMemoryDbName})", _ => ProviderType.ToString() }; } public AppDbContext CreateDbContext() { var builder = new DbContextOptionsBuilder(); if (ProviderType == DatabaseProviderType.PostgreSQL) builder.UseNpgsql(ConnectionString, npgsqlOptions => { npgsqlOptions.CommandTimeout(15); }); else builder.UseInMemoryDatabase(InMemoryDbName); return new AppDbContext(builder.Options); } private static string GetMaskedConnectionString(string conn) { if (string.IsNullOrWhiteSpace(conn)) return "Not configured"; // Hide password in display return Regex.Replace(conn, @"(?i)Password=[^;]+", "Password=******"); } }