using FrameworkDAL.DTO.SchedulerTaskGenerator; using GB5Shared.DTO.Framework.Login; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using System.Text.Json; namespace FrameworkDAL.CustomCode.SchedulerTaskGenerator { // ═══════════════════════════════════════════════════════════════════ // ILoginContextProvider // ═══════════════════════════════════════════════════════════════════ public interface ILoginContextProvider { /// /// Returns the LoginDTO for the current request context. /// /// ⚠ FOR HTTP ENDPOINTS ONLY. /// Do NOT use this in background services (SchedulerBackgroundService, /// SchedulerQuartzJob) — HttpContext is null in non-HTTP contexts and /// this will return an empty LoginDTO with no ClientId, breaking all /// tenant-scoped DAL queries. /// /// Background services must build LoginDTO from IConfiguration directly /// via BuildLoginFromConfig() in the respective job/service class. /// LoginDTO GetLogin(); } // ═══════════════════════════════════════════════════════════════════ // HeaderLoginContextProvider // ═══════════════════════════════════════════════════════════════════ /// /// Resolves LoginDTO from HTTP request headers. /// Used by FastEndpoints BaseEndpoint — the framework calls this for /// every HTTP request. /// /// Header priority: /// 1. X-LoginDTO — full LoginDTO JSON (internal service-to-service calls) /// 2. X-DatabaseName — database name only (minimal header calls) /// 3. Empty LoginDTO — fallback for background / non-HTTP execution /// public class HeaderLoginContextProvider : ILoginContextProvider { private readonly IHttpContextAccessor _http; public HeaderLoginContextProvider(IHttpContextAccessor http) { _http = http; } public LoginDTO GetLogin() { var ctx = _http.HttpContext; // ✅ Null-safe: background execution has no HttpContext // Return empty DTO — caller must validate ClientId / DatabaseName before use if (ctx == null) return new LoginDTO(); // Priority 1: full LoginDTO JSON in X-LoginDTO header // Used for internal service-to-service calls where the full context is known if (ctx.Request.Headers.TryGetValue("X-LoginDTO", out var val)) { try { var login = JsonSerializer.Deserialize( val.ToString(), new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); if (login != null) return login; } catch { // Ignore malformed header and fall through to next option } } // Priority 2: database name only in X-DatabaseName header if (ctx.Request.Headers.TryGetValue("X-DatabaseName", out var db)) { return new LoginDTO { DatabaseName = db.ToString() }; } // Priority 3: empty fallback — endpoints must handle missing login gracefully return new LoginDTO(); } } // ═══════════════════════════════════════════════════════════════════ // Gb4DbContext // ═══════════════════════════════════════════════════════════════════ /// /// EF Core context for read-only GB4 views (MJOBDEFINE, TSCHEDULER). /// /// NOTE: The scheduler task pipeline (ISchedulerTaskDAL / SchedulerTaskServiceDAL) /// uses Dapper via IQueryExecutor — NOT this context. /// This context is reserved for: /// - Reporting / analytics queries that need LINQ expressiveness /// - Future read-model projections over GB4 views /// - Do NOT use for scheduler INSERT/UPDATE operations /// public class Gb4DbContext : DbContext { public Gb4DbContext(DbContextOptions options) : base(options) { } // GB4 views (read-only — HasNoKey + ToView prevents EF from generating migrations) public DbSet JobDefinitions { get; set; } public DbSet SchedulerConfigs { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity() .HasNoKey() .ToView("MJobDefine"); modelBuilder.Entity() .HasNoKey() .ToView("TScheduler"); base.OnModelCreating(modelBuilder); } } // ═══════════════════════════════════════════════════════════════════ // CentralDbContext // ═══════════════════════════════════════════════════════════════════ /// /// EF Core context for the GB5 central database. /// /// NOTE: The scheduler task pipeline uses Dapper via IQueryExecutor — NOT this context. /// This context is reserved for: /// - Persisting SchedulerTaskGeneratorEntity metadata (audit, config store) /// - Central-DB operations that are separate from tenant-scoped scheduler execution /// - Do NOT use for TJOBEXECUTION read/write — use ISchedulerTaskDAL instead /// public class CentralDbContext : DbContext { public CentralDbContext(DbContextOptions options) : base(options) { } public DbSet SchedulerTaskGenerators { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity() .HasKey(x => x.SchedulerTaskId); base.OnModelCreating(modelBuilder); } } }