Files
amrez-nova-eop-services-api/AMREZ.EOP.Infrastructures/Repositories/TenantRepository.cs
Thanakarn Klangkasame 92e614674c Init Git
2025-09-30 11:01:02 +07:00

172 lines
6.5 KiB
C#

using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
using AMREZ.EOP.Abstractions.Storage;
using AMREZ.EOP.Domain.Entities.Tenancy;
using AMREZ.EOP.Infrastructures.Data;
using AMREZ.EOP.Infrastructures.Options;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
namespace AMREZ.EOP.Infrastructures.Repositories;
public sealed class TenantRepository : ITenantRepository
{
private readonly IDbScope _scope;
public TenantRepository(IDbScope scope) => _scope = scope;
private AppDbContext Db() => _scope.Get<AppDbContext>();
private static string Norm(string s) => (s ?? string.Empty).Trim().ToLowerInvariant();
public Task<bool> TenantExistsAsync(string tenantKey, CancellationToken ct = default)
{
var key = Norm(tenantKey);
return Db().Set<TenantConfig>().AsNoTracking().AnyAsync(x => x.TenantKey == key, ct);
}
public Task<TenantConfig?> GetAsync(string tenantKey, CancellationToken ct = default)
{
var key = Norm(tenantKey);
return Db().Set<TenantConfig>().AsNoTracking().FirstOrDefaultAsync(x => x.TenantKey == key, ct);
}
public async Task<IReadOnlyList<TenantConfig>> ListTenantsAsync(CancellationToken ct = default)
=> await Db().Set<TenantConfig>().AsNoTracking().OrderBy(x => x.TenantKey).ToListAsync(ct);
public async Task<bool> CreateAsync(TenantConfig row, CancellationToken ct = default)
{
row.TenantKey = Norm(row.TenantKey);
row.Schema = string.IsNullOrWhiteSpace(row.Schema) ? null : row.Schema!.Trim();
row.ConnectionString = string.IsNullOrWhiteSpace(row.ConnectionString) ? null : row.ConnectionString!.Trim();
row.UpdatedAtUtc = DateTimeOffset.UtcNow;
await Db().Set<TenantConfig>().AddAsync(row, ct);
return await Db().SaveChangesAsync(ct) > 0;
}
public async Task<bool> UpdateAsync(TenantConfig row, DateTimeOffset? ifUnmodifiedSince, CancellationToken ct = default)
{
var key = Norm(row.TenantKey);
var db = Db();
var cur = await db.Set<TenantConfig>().FirstOrDefaultAsync(x => x.TenantKey == key, ct);
if (cur is null) return false;
if (ifUnmodifiedSince.HasValue && cur.UpdatedAtUtc > ifUnmodifiedSince.Value)
return false; // 412
cur.Schema = row.Schema is null ? cur.Schema : (string.IsNullOrWhiteSpace(row.Schema) ? null : row.Schema.Trim());
cur.ConnectionString = row.ConnectionString is null ? cur.ConnectionString : (string.IsNullOrWhiteSpace(row.ConnectionString) ? null : row.ConnectionString.Trim());
cur.Mode = row.Mode;
cur.IsActive = row.IsActive;
cur.UpdatedAtUtc = DateTimeOffset.UtcNow;
return await db.SaveChangesAsync(ct) > 0;
}
public async Task<bool> DeleteAsync(string tenantKey, CancellationToken ct = default)
{
var key = Norm(tenantKey);
var db = Db();
var t = await db.Set<TenantConfig>().FirstOrDefaultAsync(x => x.TenantKey == key, ct);
if (t is null) return false;
// ❌ ไม่ลบนะ — ✅ deactivate
if (t.IsActive)
{
t.IsActive = false;
t.UpdatedAtUtc = DateTimeOffset.UtcNow;
}
var domains = await db.Set<TenantDomain>()
.Where(d => d.TenantKey == key && d.IsActive)
.ToListAsync(ct);
foreach (var d in domains)
{
d.IsActive = false;
d.UpdatedAtUtc = DateTimeOffset.UtcNow;
}
return await db.SaveChangesAsync(ct) > 0;
}
public async Task<bool> MapDomainAsync(string domain, string tenantKey, CancellationToken ct = default)
{
var d = Norm(domain);
var key = Norm(tenantKey);
if (!await Db().Set<TenantConfig>().AnyAsync(x => x.TenantKey == key && x.IsActive, ct))
return false;
var db = Db();
var ex = await db.Set<TenantDomain>().FirstOrDefaultAsync(x => x.Domain == d, ct);
if (ex is null)
await db.Set<TenantDomain>().AddAsync(new TenantDomain { Domain = d, TenantKey = key, IsPlatformBaseDomain = false, IsActive = true, UpdatedAtUtc = DateTimeOffset.UtcNow }, ct);
else
{
ex.TenantKey = key;
ex.IsPlatformBaseDomain = false;
ex.IsActive = true;
ex.UpdatedAtUtc = DateTimeOffset.UtcNow;
}
return await db.SaveChangesAsync(ct) > 0;
}
public async Task<bool> UnmapDomainAsync(string domain, CancellationToken ct = default)
{
var d = Norm(domain);
var db = Db();
var ex = await db.Set<TenantDomain>().FirstOrDefaultAsync(x => x.Domain == d, ct);
if (ex is null) return false;
ex.IsActive = false;
ex.TenantKey = null;
ex.IsPlatformBaseDomain = false;
ex.UpdatedAtUtc = DateTimeOffset.UtcNow;
return await db.SaveChangesAsync(ct) > 0;
}
public async Task<IReadOnlyList<TenantDomain>> ListDomainsAsync(string? tenantKey, CancellationToken ct = default)
{
var db = Db();
var q = db.Set<TenantDomain>().AsNoTracking();
if (!string.IsNullOrWhiteSpace(tenantKey))
{
var key = Norm(tenantKey!);
q = q.Where(x => x.TenantKey == key || x.IsPlatformBaseDomain);
}
return await q.OrderBy(x => x.Domain).ToListAsync(ct);
}
public async Task<bool> AddBaseDomainAsync(string baseDomain, CancellationToken ct = default)
{
var d = Norm(baseDomain);
var db = Db();
var ex = await db.Set<TenantDomain>().FirstOrDefaultAsync(x => x.Domain == d, ct);
if (ex is null)
await db.Set<TenantDomain>().AddAsync(new TenantDomain { Domain = d, TenantKey = null, IsPlatformBaseDomain = true, IsActive = true, UpdatedAtUtc = DateTimeOffset.UtcNow }, ct);
else
{
ex.TenantKey = null;
ex.IsPlatformBaseDomain = true;
ex.IsActive = true;
ex.UpdatedAtUtc = DateTimeOffset.UtcNow;
}
return await db.SaveChangesAsync(ct) > 0;
}
public async Task<bool> RemoveBaseDomainAsync(string baseDomain, CancellationToken ct = default)
{
var d = Norm(baseDomain);
var db = Db();
var ex = await db.Set<TenantDomain>()
.FirstOrDefaultAsync(x => x.Domain == d && x.IsPlatformBaseDomain, ct);
if (ex is null) return false;
ex.IsActive = false;
ex.UpdatedAtUtc = DateTimeOffset.UtcNow;
return await db.SaveChangesAsync(ct) > 0;
}
}