using AMREZ.EOP.Abstractions.Applications.Tenancy; using AMREZ.EOP.API.Middleware; using AMREZ.EOP.Domain.Shared.Contracts; using AMREZ.EOP.Domain.Shared.Tenancy; using AMREZ.EOP.Infrastructures.Data; using AMREZ.EOP.Infrastructures.DependencyInjections; using AMREZ.EOP.Infrastructures.Options; using AMREZ.EOP.Infrastructures.Tenancy; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; using Microsoft.OpenApi.Models; using Npgsql; var builder = WebApplication.CreateBuilder(args); builder.Services.Configure(builder.Configuration.GetSection("Connections")); builder.Services.AddInfrastructure(); builder.Services.AddOpenApi(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "AMREZ.EOP API", Version = "v1" }); // Cookie auth (ชื่อคุกกี้ eop.auth) c.AddSecurityDefinition("cookieAuth", new OpenApiSecurityScheme { Type = SecuritySchemeType.ApiKey, In = ParameterLocation.Cookie, Name = "eop.auth", Description = "Sign in via /api/authentication/login to receive cookie." }); c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme{ Reference = new OpenApiReference{ Type = ReferenceType.SecurityScheme, Id = "cookieAuth" } }, Array.Empty() } }); }); builder.Services .AddAuthentication(AuthPolicies.Scheme) .AddCookie(AuthPolicies.Scheme, o => { o.LoginPath="/api/authentication/login"; o.Cookie.Name="eop.auth"; o.SlidingExpiration=true; }); builder.Services.AddAuthorization(); builder.Services.AddSingleton(new StrictTenantGuardOptions { PlatformSlug = "public", HeaderName = "X-Tenant", ClaimName = "tenant" }); builder.Services.AddTransient(); builder.Services.AddControllers(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { await ApplyMigrationsAsync(app.Services); app.MapOpenApi(); app.UseSwagger(); app.UseSwaggerUI(o => { o.SwaggerEndpoint("/swagger/v1/swagger.json", "AMREZ.EOP API v1"); o.RoutePrefix = "swagger"; o.DisplayRequestDuration(); }); } app.UseHttpsRedirection(); app.UseAuthentication(); app.UseMiddleware(); app.UseAuthorization(); app.MapControllers(); app.Run(); static async Task ApplyMigrationsAsync(IServiceProvider services) { using var scope = services.CreateScope(); var sp = scope.ServiceProvider; var opts = sp.GetRequiredService>().Value; var factory = sp.GetRequiredService(); if (!opts.UseSchemaPerTenant) { await using var db = factory.Create(new TenantContext { Id = "_shared_" }); await db.Database.MigrateAsync(); } var schemas = await GetAppSchemasAsync(opts.DefaultConnection); foreach (var schema in schemas) { var t = new TenantContext { Id = schema, Schema = schema, Mode = TenantMode.Schema }; await using var db = factory.Create(t); await db.Database.MigrateAsync(); } } static async Task> GetAppSchemasAsync(string connectionString) { var list = new List(); await using var conn = new NpgsqlConnection(connectionString); await conn.OpenAsync(); const string sql = @" SELECT nspname FROM pg_namespace WHERE nspname NOT LIKE 'pg_%' AND nspname <> 'information_schema' ORDER BY nspname;"; await using var cmd = new NpgsqlCommand(sql, conn); await using var rd = await cmd.ExecuteReaderAsync(); while (await rd.ReadAsync()) list.Add(rd.GetString(0)); if (list.Count == 0) list.Add("public"); return list; }