using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Npgsql; using StackExchange.Redis; using Tiku.Application.Security; using Tiku.Domain.Identity; using Tiku.Infrastructure.Auth; using Tiku.Infrastructure.Observability; using Tiku.Infrastructure.Persistence; using Tiku.Infrastructure.Security; namespace Tiku.Infrastructure; public static class DependencyInjection { public static IServiceCollection AddInfrastructure( this IServiceCollection services, string connectionString, Action? configureDatabase = null) { ArgumentException.ThrowIfNullOrWhiteSpace(connectionString); services.AddSingleton(_ => NpgsqlDataSource.Create(connectionString)); services.AddScoped(); services.AddSingleton(); services.AddDbContext((serviceProvider, options) => { var dataSource = serviceProvider.GetRequiredService(); options.UseNpgsql(dataSource, npgsql => npgsql.MigrationsAssembly(typeof(TikuDbContext).Assembly.FullName)); configureDatabase?.Invoke(options); options.AddInterceptors( serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService()); }); services.AddScoped(provider => provider.GetRequiredService()); services.AddScoped(provider => provider.GetRequiredService()); services.AddScoped(provider => provider.GetRequiredService()); services.AddScoped(provider => provider.GetRequiredService()); services.AddScoped(provider => provider.GetRequiredService()); services.AddScoped(provider => provider.GetRequiredService()); services.AddScoped(provider => provider.GetRequiredService()); services.AddScoped(provider => provider.GetRequiredService()); services.AddScoped(provider => provider.GetRequiredService()); services.AddScoped(provider => provider.GetRequiredService()); services.AddScoped(provider => provider.GetRequiredService()); services.AddScoped(provider => provider.GetRequiredService()); services.AddScoped(provider => provider.GetRequiredService()); services.AddScoped(provider => provider.GetRequiredService()); services.AddScoped(provider => provider.GetRequiredService()); services.AddScoped(provider => provider.GetRequiredService()); services.AddScoped(provider => provider.GetRequiredService()); services.AddScoped(provider => provider.GetRequiredService()); services.AddIdentityCore(options => { options.Password.RequiredLength = 8; options.Password.RequireDigit = false; options.Password.RequireLowercase = false; options.Password.RequireUppercase = false; options.Password.RequireNonAlphanumeric = false; options.Lockout.MaxFailedAccessAttempts = 5; options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15); options.User.RequireUniqueEmail = false; }) .AddEntityFrameworkStores() .AddSignInManager() .AddDefaultTokenProviders() .AddPasswordValidator>(); services.Configure(options => options.IterationCount = 210_000); services.AddPlatformCoreModule(); services.AddAuthModule(); services.AddContentModule(); services.AddLearningModule(); services.AddTenantAdminModule(); services.AddCommerceModule(); services.AddJobsModule(); services.AddPlatformModule(); return services; } public static IServiceCollection AddRedisSecurity( this IServiceCollection services, string connectionString, string environmentName) { ArgumentException.ThrowIfNullOrWhiteSpace(connectionString); var options = ConfigurationOptions.Parse(connectionString); options.AbortOnConnectFail = false; options.ClientName = $"tiku-{environmentName.ToLowerInvariant()}"; services.AddSingleton(_ => ConnectionMultiplexer.Connect(options)); services.AddSingleton(provider => new RedisSecurityStore( provider.GetRequiredService(), environmentName, provider.GetRequiredService>())); services.AddSingleton(provider => provider.GetRequiredService()); services.AddSingleton(provider => new RedisAuthorizationCache( provider.GetRequiredService(), provider.GetRequiredService>(), environmentName)); services.AddSingleton(provider => provider.GetRequiredService()); services.AddSingleton(provider => provider.GetRequiredService()); services.AddStackExchangeRedisCache(cache => cache.ConfigurationOptions = options); return services; } }