140 lines
6.3 KiB
C#
140 lines
6.3 KiB
C#
using AMREZ.EOP.Abstractions.Applications.Tenancy;
|
|
using AMREZ.EOP.Abstractions.Applications.UseCases.Authentications;
|
|
using AMREZ.EOP.Abstractions.Applications.UseCases.HumanResources;
|
|
using AMREZ.EOP.Abstractions.Applications.UseCases.Tenancy;
|
|
using AMREZ.EOP.Abstractions.Infrastructures.Common;
|
|
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
|
using AMREZ.EOP.Abstractions.Security;
|
|
using AMREZ.EOP.Abstractions.Storage;
|
|
using AMREZ.EOP.Application.UseCases.Authentications;
|
|
using AMREZ.EOP.Application.UseCases.HumanResources;
|
|
using AMREZ.EOP.Application.UseCases.Tenancy;
|
|
using AMREZ.EOP.Domain.Shared.Tenancy;
|
|
using AMREZ.EOP.Infrastructures.Data;
|
|
using AMREZ.EOP.Infrastructures.Options;
|
|
using AMREZ.EOP.Infrastructures.Repositories;
|
|
using AMREZ.EOP.Infrastructures.Security;
|
|
using AMREZ.EOP.Infrastructures.Storage;
|
|
using AMREZ.EOP.Infrastructures.Tenancy;
|
|
using AMREZ.EOP.Infrastructures.UnitOfWork;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Options;
|
|
using StackExchange.Redis;
|
|
|
|
namespace AMREZ.EOP.Infrastructures.DependencyInjections;
|
|
|
|
public static class ServiceCollectionExtensions
|
|
{
|
|
public static IServiceCollection AddInfrastructure(this IServiceCollection services)
|
|
{
|
|
services.AddHttpContextAccessor();
|
|
services.AddScoped<IJwtFactory, JwtFactory>();
|
|
|
|
// Options
|
|
services.AddOptions<AuthOptions>()
|
|
.BindConfiguration("Connections")
|
|
.ValidateOnStart();
|
|
|
|
// Tenancy core (order matters for AddDbContext factory resolution)
|
|
services.AddSingleton(sp =>
|
|
{
|
|
var map = new TenantMap();
|
|
var opts = sp.GetRequiredService<IOptions<AuthOptions>>().Value;
|
|
map.UpsertTenant("public", new TenantContext
|
|
{
|
|
Id = "public",
|
|
Schema = "public",
|
|
ConnectionString = string.IsNullOrWhiteSpace(opts.DefaultConnection) ? null : opts.DefaultConnection,
|
|
Mode = TenantMode.Rls
|
|
});
|
|
return map;
|
|
});
|
|
services.AddHostedService<TenantMapLoader>();
|
|
services.AddScoped<SearchPathInterceptor>();
|
|
services.AddScoped<TenantRlsInterceptor>();
|
|
services.AddScoped<ITenantResolver, DefaultTenantResolver>();
|
|
services.AddScoped<ITenantDbContextFactory, TenantDbContextFactory>();
|
|
services.AddScoped<ITenantProvisioner, TenantProvisioner>();
|
|
|
|
// DbContext (attach RLS/search_path interceptors)
|
|
services.AddDbContext<AppDbContext>((sp, o) =>
|
|
{
|
|
var cfg = sp.GetRequiredService<IOptions<AuthOptions>>().Value;
|
|
o.UseNpgsql(cfg.DefaultConnection);
|
|
o.AddInterceptors(
|
|
sp.GetRequiredService<SearchPathInterceptor>(),
|
|
sp.GetRequiredService<TenantRlsInterceptor>()
|
|
);
|
|
});
|
|
|
|
// Db scope / UoW
|
|
services.AddScoped<IDbScope, DbScope>();
|
|
services.AddScoped<EFUnitOfWork>();
|
|
services.AddScoped<IUnitOfWork, EFUnitOfWork>();
|
|
|
|
// Security
|
|
services.AddScoped<IPasswordHasher, BcryptPasswordHasher>();
|
|
|
|
// Repositories — Auth & HR แยกกัน
|
|
services.AddScoped<IUserRepository, UserRepository>();
|
|
services.AddScoped<IUserProfileRepository, UserProfileRepository>();
|
|
services.AddScoped<ITenantRepository, TenantRepository>();
|
|
|
|
// UseCases — Authentication
|
|
services.AddScoped<ILoginUseCase, LoginUseCase>();
|
|
services.AddScoped<IRegisterUseCase, RegisterUseCase>();
|
|
services.AddScoped<IChangePasswordUseCase, ChangePasswordUseCase>();
|
|
services.AddScoped<IAddEmailIdentityUseCase, AddEmailIdentityUseCase>();
|
|
services.AddScoped<IVerifyEmailUseCase, VerifyEmailUseCase>();
|
|
services.AddScoped<IEnableTotpUseCase, EnableTotpUseCase>();
|
|
services.AddScoped<IDisableMfaUseCase, DisableMfaUseCase>();
|
|
services.AddScoped<ILogoutUseCase, LogoutUseCase>();
|
|
services.AddScoped<ILogoutAllUseCase, LogoutAllUseCase>();
|
|
services.AddScoped<IIssueTokenPairUseCase, IssueTokenPairUseCase>();
|
|
services.AddScoped<IRefreshUseCase, RefreshUseCase>();
|
|
|
|
// UseCases — HR
|
|
services.AddScoped<IUpsertUserProfileUseCase, UpsertUserProfileUseCase>();
|
|
services.AddScoped<IAddEmploymentUseCase, AddEmploymentUseCase>();
|
|
services.AddScoped<IEndEmploymentUseCase, EndEmploymentUseCase>();
|
|
services.AddScoped<IAddEmployeeAddressUseCase, AddEmployeeAddressUseCase>();
|
|
services.AddScoped<ISetPrimaryAddressUseCase, SetPrimaryAddressUseCase>();
|
|
services.AddScoped<IAddEmergencyContactUseCase, AddEmergencyContactUseCase>();
|
|
services.AddScoped<ISetPrimaryEmergencyContactUseCase, SetPrimaryEmergencyContactUseCase>();
|
|
services.AddScoped<IAddEmployeeBankAccountUseCase, AddEmployeeBankAccountUseCase>();
|
|
services.AddScoped<ISetPrimaryBankAccountUseCase, SetPrimaryBankAccountUseCase>();
|
|
|
|
// UseCases — Tenancy
|
|
services.AddScoped<ICreateTenantUseCase, CreateTenantUseCase>();
|
|
services.AddScoped<IUpdateTenantUseCase, UpdateTenantUseCase>();
|
|
services.AddScoped<IDeleteTenantUseCase, DeleteTenantUseCase>();
|
|
services.AddScoped<IMapDomainUseCase, MapDomainUseCase>();
|
|
services.AddScoped<IUnmapDomainUseCase, UnmapDomainUseCase>();
|
|
services.AddScoped<IAddBaseDomainUseCase, AddBaseDomainUseCase>();
|
|
services.AddScoped<IRemoveBaseDomainUseCase, RemoveBaseDomainUseCase>();
|
|
services.AddScoped<IListTenantsUseCase, ListTenantsUseCase>();
|
|
services.AddScoped<IListDomainsUseCase, ListDomainsUseCase>();
|
|
|
|
// Redis (optional)
|
|
services.AddSingleton<IConnectionMultiplexer?>(sp =>
|
|
{
|
|
var opts = sp.GetRequiredService<IOptions<AuthOptions>>().Value;
|
|
var conn = opts.RedisConnection;
|
|
if (string.IsNullOrWhiteSpace(conn)) return null;
|
|
|
|
try
|
|
{
|
|
var cfg = ConfigurationOptions.Parse(conn, true);
|
|
cfg.AbortOnConnectFail = false;
|
|
cfg.ConnectTimeout = 1000;
|
|
cfg.SyncTimeout = 1000;
|
|
var mux = ConnectionMultiplexer.Connect(cfg);
|
|
return mux.IsConnected ? mux : null;
|
|
}
|
|
catch { return null; }
|
|
});
|
|
|
|
return services;
|
|
}
|
|
} |