using GB5Shared.DTO.Framework.Login; using GB5Shared.GenerateAutoNumber; using GB5Shared.Resource.Response; using SwDAL.CustomCode.ClientDatabaseKey; using SwDAL.DTO.ClientDatabaseKey; using static GB5Shared.GB5Constant.Constant; namespace SwBLL.ClientDatabaseKey; public class ClientDatabaseKeyBLL : IClientDatabaseKeyBLL { private readonly IClientDatabaseKeyDAL _DAL; private readonly AutoNumber _AutoNumber; public ClientDatabaseKeyBLL(IClientDatabaseKeyDAL dal, AutoNumber autoNumber) { _DAL = dal; _AutoNumber = autoNumber; } public async Task GetActiveByClientDb(int clientDbId, LoginDTO loginDTO, CancellationToken ct) => await _DAL.GetActiveByClientDb(clientDbId, loginDTO, ct).ConfigureAwait(false); public async Task RegisterKeyAsync(int clientDbId, string publicKeyPem, LoginDTO loginDTO, CancellationToken ct) { // Real GB5 ClientDbIds are large negative AutoNumber-allocated values (e.g. -1370001001), // never small positive ones — a "clientDbId <= 0" guard would reject every genuine // client database, the same live-caught bug class already fixed in // EntitlementBLL.ClientEntitlementSnapshotBLL.GetSnapshotAsync. Only reject the // genuinely-missing/default case. if (clientDbId == 0) throw new ArgumentException("ClientDbId is required.", nameof(clientDbId)); if (string.IsNullOrWhiteSpace(publicKeyPem)) throw new ArgumentException("PublicKeyPem is required.", nameof(publicKeyPem)); // Rotation, not overwrite: whatever key currently sits Active for this client database is // superseded (kept, never deleted) before the new one is inserted as Active — enforces // "exactly one Active row per ClientDbId" without a DB constraint, same posture as // UpgradePackageBLL's own "immutable once Released" guard. await _DAL.SupersedeActive(clientDbId, loginDTO, ct).ConfigureAwait(false); var auto = await _AutoNumber.GetNumberAsync(1, AUTONUMBERCONSTANT.SWCLIENTDATABASEKEY, loginDTO); var dto = new ClientDatabaseKeyDTO { ClientDatabaseKeyId = auto.StartNumber, ClientDbId = clientDbId, PublicKeyPem = publicKeyPem, KeyStatus = 0, RegisteredOn = DateTime.UtcNow, CreatedById = loginDTO.UserId, CreatedOn = DateTime.UtcNow, ModifiedById = loginDTO.UserId, ModifiedOn = DateTime.UtcNow, TenantId = loginDTO.ClientId, }; await _DAL.Insert(dto, loginDTO, ct).ConfigureAwait(false); return $"{SuccessResponse.SaveSuccessMessage} {dto.ClientDatabaseKeyId}"; } public async Task RevokeAsync(int clientDatabaseKeyId, LoginDTO loginDTO, CancellationToken ct) { if (clientDatabaseKeyId <= 0) throw new ArgumentException("ClientDatabaseKeyId is required.", nameof(clientDatabaseKeyId)); await _DAL.Revoke(clientDatabaseKeyId, loginDTO, ct).ConfigureAwait(false); return SuccessResponse.UpdateSuccess; } }