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);
}
}
}