Persist admin login defaults consistently
Adds shared admin login post-processing to save the admin employee id and site defaults, and updates login flows to use the helper.feature/centralized-offline-canteen
parent
8123d67121
commit
659c162c93
|
|
@ -32,9 +32,10 @@ public class AdminAuditService : IAdminAuditService
|
|||
db.AdminLoginRecords.Add(record);
|
||||
await db.SaveChangesAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Audit failures should never block login; ignore errors.
|
||||
// Audit failures should never block login.
|
||||
Logger.Log(ex, "AdminAuditService.RecordLoginAsync");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -50,8 +51,9 @@ public class AdminAuditService : IAdminAuditService
|
|||
.OrderByDescending(x => x.LoginTimeUtc)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log(ex, "AdminAuditService.GetLastLogin");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
namespace UtopiaCanteenSystem.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Shared admin login post-processing: persist employee id and site from session/backend.
|
||||
/// </summary>
|
||||
public static class AdminLoginHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Admin Access field: persisted <see cref="IConfigService.GetAdminCardId"/> first,
|
||||
/// then current session, then SQLite audit, then "ADMIN".
|
||||
/// </summary>
|
||||
public static string ResolveAdminCardIdForDisplay(
|
||||
IConfigService config,
|
||||
AppSession? session = null,
|
||||
IAdminAuditService? adminAudit = null)
|
||||
{
|
||||
var fromConfig = (config.GetAdminCardId() ?? string.Empty).Trim();
|
||||
if (!string.IsNullOrWhiteSpace(fromConfig))
|
||||
return fromConfig;
|
||||
|
||||
if (session != null && !string.IsNullOrWhiteSpace(session.AdminEmployeeId))
|
||||
return session.AdminEmployeeId.Trim();
|
||||
|
||||
var last = adminAudit?.GetLastLogin();
|
||||
if (last != null && !string.IsNullOrWhiteSpace(last.EmployeeId))
|
||||
return last.EmployeeId.Trim();
|
||||
|
||||
return "ADMIN";
|
||||
}
|
||||
|
||||
public static async Task ApplyAdminLoginDefaultsAsync(
|
||||
string employeeId,
|
||||
IConfigService config,
|
||||
IEmployeeLookupService employeeLookup,
|
||||
ICanteenBackendApiClient? backendApi = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(employeeId))
|
||||
return;
|
||||
|
||||
config.SetAdminCardId(employeeId.Trim());
|
||||
|
||||
string? siteId = null;
|
||||
try
|
||||
{
|
||||
siteId = await employeeLookup.GetLocationSiteIdByEmployeeSerialAsync(employeeId, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Local/HRMS lookup optional on client.
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(siteId) && backendApi != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
siteId = await backendApi.GetEmployeeLocationSiteAsync(employeeId, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Backend lookup optional.
|
||||
}
|
||||
}
|
||||
|
||||
config.ApplyLocationSiteIdFromAuth(siteId);
|
||||
}
|
||||
|
||||
/// <summary>Format site for UI fields (e.g. "SITE : 02").</summary>
|
||||
public static string FormatSiteIdForDisplay(string? siteId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(siteId))
|
||||
return string.Empty;
|
||||
|
||||
var raw = siteId.Trim();
|
||||
if (raw.StartsWith("SITE :", StringComparison.OrdinalIgnoreCase))
|
||||
return raw;
|
||||
|
||||
var digits = new string(raw.Where(char.IsDigit).ToArray());
|
||||
return string.IsNullOrEmpty(digits) ? raw : $"SITE : {digits}";
|
||||
}
|
||||
|
||||
/// <summary>Extract digits from site display for scanner header.</summary>
|
||||
public static string ExtractSiteDigits(string? siteId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(siteId))
|
||||
return "1";
|
||||
|
||||
var raw = siteId.Trim();
|
||||
if (raw.StartsWith("SITE :", StringComparison.OrdinalIgnoreCase))
|
||||
raw = raw.Substring(raw.IndexOf(':') + 1).Trim();
|
||||
|
||||
var digits = new string(raw.Where(char.IsDigit).ToArray());
|
||||
return string.IsNullOrEmpty(digits) ? "1" : digits;
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ public partial class AdminLoginViewModel : ObservableObject
|
|||
private readonly IConfigService _config;
|
||||
private readonly IAdminAuditService _adminAudit;
|
||||
private readonly IEmployeeLookupService _employeeLookup;
|
||||
private readonly ICanteenBackendApiClient? _backendApi;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _username = string.Empty;
|
||||
|
|
@ -35,7 +36,8 @@ public partial class AdminLoginViewModel : ObservableObject
|
|||
INavigationService navigation,
|
||||
IConfigService config,
|
||||
IAdminAuditService adminAudit,
|
||||
IEmployeeLookupService employeeLookup)
|
||||
IEmployeeLookupService employeeLookup,
|
||||
ICanteenBackendApiClient? backendApi = null)
|
||||
{
|
||||
_authService = authService;
|
||||
_session = session;
|
||||
|
|
@ -43,6 +45,7 @@ public partial class AdminLoginViewModel : ObservableObject
|
|||
_config = config;
|
||||
_adminAudit = adminAudit;
|
||||
_employeeLookup = employeeLookup;
|
||||
_backendApi = backendApi;
|
||||
|
||||
RememberCredentials = _config.GetRememberAdminCredentials();
|
||||
if (RememberCredentials)
|
||||
|
|
@ -86,15 +89,11 @@ public partial class AdminLoginViewModel : ObservableObject
|
|||
|
||||
_session.SetAdminAuthenticated(user, result.EmployeeId);
|
||||
|
||||
try
|
||||
{
|
||||
var siteId = await _employeeLookup.GetLocationSiteIdByEmployeeSerialAsync(result.EmployeeId).ConfigureAwait(true);
|
||||
_config.ApplyLocationSiteIdFromAuth(siteId);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// HRMS lookup optional; login still succeeds.
|
||||
}
|
||||
await AdminLoginHelper.ApplyAdminLoginDefaultsAsync(
|
||||
result.EmployeeId,
|
||||
_config,
|
||||
_employeeLookup,
|
||||
_backendApi).ConfigureAwait(true);
|
||||
|
||||
// Persist who logged in (for audit / reporting).
|
||||
await _adminAudit.RecordLoginAsync(user, result.EmployeeId).ConfigureAwait(false);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ public partial class AdminSettingsAuthViewModel : ObservableObject
|
|||
private readonly INavigationService _navigation;
|
||||
private readonly IConfigService _config;
|
||||
private readonly IEmployeeLookupService _employeeLookup;
|
||||
private readonly ICanteenBackendApiClient? _backendApi;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _username = string.Empty;
|
||||
|
|
@ -33,13 +34,15 @@ public partial class AdminSettingsAuthViewModel : ObservableObject
|
|||
AppSession session,
|
||||
INavigationService navigation,
|
||||
IConfigService config,
|
||||
IEmployeeLookupService employeeLookup)
|
||||
IEmployeeLookupService employeeLookup,
|
||||
ICanteenBackendApiClient? backendApi = null)
|
||||
{
|
||||
_authService = authService;
|
||||
_session = session;
|
||||
_navigation = navigation;
|
||||
_config = config;
|
||||
_employeeLookup = employeeLookup;
|
||||
_backendApi = backendApi;
|
||||
|
||||
RememberCredentials = _config.GetRememberAdminCredentials();
|
||||
if (RememberCredentials)
|
||||
|
|
@ -90,15 +93,11 @@ public partial class AdminSettingsAuthViewModel : ObservableObject
|
|||
// Refresh session details (who authenticated for Settings).
|
||||
_session.SetAdminAuthenticated(user, result.EmployeeId);
|
||||
|
||||
try
|
||||
{
|
||||
var siteId = await _employeeLookup.GetLocationSiteIdByEmployeeSerialAsync(result.EmployeeId).ConfigureAwait(true);
|
||||
_config.ApplyLocationSiteIdFromAuth(siteId);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// HRMS lookup optional; auth still succeeds.
|
||||
}
|
||||
await AdminLoginHelper.ApplyAdminLoginDefaultsAsync(
|
||||
result.EmployeeId,
|
||||
_config,
|
||||
_employeeLookup,
|
||||
_backendApi).ConfigureAwait(true);
|
||||
|
||||
// Persist credentials only if user opted in.
|
||||
_config.SetRememberAdminCredentials(RememberCredentials);
|
||||
|
|
|
|||
Loading…
Reference in New Issue