Fix config overwrite on login/navigation; use production DB for meal schedule CRUD, remove default SiteId normalization, add config load/save logging, and support legacy SiteId format.
parent
a42f43b2cc
commit
4d2433fa28
|
|
@ -92,44 +92,16 @@ public class ConfigService : IConfigService
|
|||
|
||||
public string GetSiteId()
|
||||
{
|
||||
// Normalize to a 2-digit string (e.g. "02", "07", "12").
|
||||
// Accepts legacy values like "SITE : 2" or "2" and converts them.
|
||||
var raw = _config.SiteId;
|
||||
if (string.IsNullOrWhiteSpace(raw))
|
||||
return "01";
|
||||
|
||||
var digits = new string(raw.Where(char.IsDigit).ToArray());
|
||||
if (string.IsNullOrWhiteSpace(digits))
|
||||
return "01";
|
||||
|
||||
if (!int.TryParse(digits, out var numeric))
|
||||
return "01";
|
||||
|
||||
return Math.Clamp(numeric, 0, 99).ToString("D2");
|
||||
// Return the configured SiteId as-is. No normalization.
|
||||
// Returns empty string if not configured.
|
||||
return _config.SiteId ?? string.Empty;
|
||||
}
|
||||
|
||||
public void SetSiteId(string siteId)
|
||||
public void SetSiteId(string siteId)
|
||||
{
|
||||
// Store the normalized 2-digit site code.
|
||||
var normalized = siteId;
|
||||
if (string.IsNullOrWhiteSpace(normalized))
|
||||
{
|
||||
normalized = "01";
|
||||
}
|
||||
else
|
||||
{
|
||||
var digits = new string(normalized.Where(char.IsDigit).ToArray());
|
||||
if (string.IsNullOrWhiteSpace(digits) || !int.TryParse(digits, out var numeric))
|
||||
{
|
||||
normalized = "01";
|
||||
}
|
||||
else
|
||||
{
|
||||
normalized = Math.Clamp(numeric, 0, 99).ToString("D2");
|
||||
}
|
||||
}
|
||||
|
||||
_config.SiteId = normalized;
|
||||
// Store the SiteId exactly as provided. No automatic normalization.
|
||||
// Caller is responsible for formatting.
|
||||
_config.SiteId = siteId ?? string.Empty;
|
||||
SaveConfig();
|
||||
}
|
||||
|
||||
|
|
@ -246,22 +218,30 @@ public class ConfigService : IConfigService
|
|||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(_configPath))
|
||||
if (!File.Exists(_configPath))
|
||||
{
|
||||
var defaults = new AppConfig();
|
||||
System.Diagnostics.Debug.WriteLine("[ConfigService] Config file not found. Creating with defaults.");
|
||||
var defaults = new AppConfig();
|
||||
SaveConfig(defaults);
|
||||
return defaults;
|
||||
return defaults;
|
||||
}
|
||||
|
||||
var json = File.ReadAllText(_configPath);
|
||||
var config = JsonSerializer.Deserialize<AppConfig>(json);
|
||||
config ??= new AppConfig();
|
||||
var json = File.ReadAllText(_configPath);
|
||||
var config = JsonSerializer.Deserialize<AppConfig>(json);
|
||||
config ??= new AppConfig();
|
||||
MigrateScanIntervalFromSecondsIfNeeded(config);
|
||||
return config;
|
||||
|
||||
System.Diagnostics.Debug.WriteLine($"[ConfigService] Config loaded from {_configPath}");
|
||||
System.Diagnostics.Debug.WriteLine($"[ConfigService] SiteId: '{config.SiteId}' (empty=not configured)");
|
||||
System.Diagnostics.Debug.WriteLine($"[ConfigService] MySqlConnectionString: {(string.IsNullOrWhiteSpace(config.MySqlConnectionString) ? "NOT CONFIGURED" : MaskConnectionString(config.MySqlConnectionString))}");
|
||||
System.Diagnostics.Debug.WriteLine($"[ConfigService] HrmsLookupConnectionString: {(string.IsNullOrWhiteSpace(config.HrmsLookupConnectionString) ? "NOT CONFIGURED" : MaskConnectionString(config.HrmsLookupConnectionString))}");
|
||||
|
||||
return config;
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new AppConfig();
|
||||
System.Diagnostics.Debug.WriteLine($"[ConfigService] ERROR loading config: {ex.Message}");
|
||||
return new AppConfig();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -308,18 +288,49 @@ public class ConfigService : IConfigService
|
|||
{
|
||||
try
|
||||
{
|
||||
var json = JsonSerializer.Serialize(config, new JsonSerializerOptions
|
||||
// Log what's being saved
|
||||
System.Diagnostics.Debug.WriteLine($"[ConfigService] Saving config...");
|
||||
System.Diagnostics.Debug.WriteLine($"[ConfigService] SiteId: '{_config.SiteId}'");
|
||||
System.Diagnostics.Debug.WriteLine($"[ConfigService] MySqlConnectionString: {(string.IsNullOrWhiteSpace(_config.MySqlConnectionString) ? "NOT CONFIGURED" : MaskConnectionString(_config.MySqlConnectionString))}");
|
||||
System.Diagnostics.Debug.WriteLine($"[ConfigService] HrmsLookupConnectionString: {(string.IsNullOrWhiteSpace(_config.HrmsLookupConnectionString) ? "NOT CONFIGURED" : MaskConnectionString(_config.HrmsLookupConnectionString))}");
|
||||
|
||||
var json = JsonSerializer.Serialize(config, new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true
|
||||
});
|
||||
File.WriteAllText(_configPath, json);
|
||||
System.Diagnostics.Debug.WriteLine($"[ConfigService] Config saved to {_configPath}");
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Ignore write failures (e.g., read-only location).
|
||||
System.Diagnostics.Debug.WriteLine($"[ConfigService] ERROR saving config: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Masks sensitive connection string values for logging.
|
||||
/// Shows server and database but hides password.
|
||||
/// </summary>
|
||||
private static string MaskConnectionString(string connectionString)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(connectionString))
|
||||
return string.Empty;
|
||||
|
||||
// Simple masking: show everything before 'Password=' and mask the rest
|
||||
var passwordIndex = connectionString.IndexOf("Password=", StringComparison.OrdinalIgnoreCase);
|
||||
if (passwordIndex >= 0)
|
||||
{
|
||||
var semicolonAfterPassword = connectionString.IndexOf(';', passwordIndex);
|
||||
if (semicolonAfterPassword >= 0)
|
||||
{
|
||||
return connectionString.Substring(0, passwordIndex) + "Password=***" + connectionString.Substring(semicolonAfterPassword);
|
||||
}
|
||||
return connectionString.Substring(0, passwordIndex) + "Password=***";
|
||||
}
|
||||
|
||||
return connectionString; // No password found, return as-is
|
||||
}
|
||||
|
||||
private sealed class AppConfig
|
||||
{
|
||||
public string SyncApiEndpoint { get; set; } = "https://api.example.com/uind/sync";
|
||||
|
|
@ -328,10 +339,10 @@ public class ConfigService : IConfigService
|
|||
public int ScanTimeoutSeconds { get; set; } = 0;
|
||||
public int ScanIntervalDays { get; set; } = 0;
|
||||
public int ScanIntervalHours { get; set; } = 0;
|
||||
public int ScanIntervalMinutes { get; set; } = 1;
|
||||
public int ScanIntervalSeconds { get; set; } = 0;
|
||||
public int ScanIntervalMinutes { get; set; } = 0;
|
||||
public int ScanIntervalSeconds { get; set; } = 2;
|
||||
public string AdminCardId { get; set; } = "ADMIN";
|
||||
public string SiteId { get; set; } = "SITE : 1";
|
||||
public string SiteId { get; set; } = string.Empty; // No default - must be explicitly configured
|
||||
public string DeviceId { get; set; } = string.Empty;
|
||||
|
||||
// Admin credential persistence (optional).
|
||||
|
|
@ -343,6 +354,6 @@ public class ConfigService : IConfigService
|
|||
public string MySqlConnectionString { get; set; } = string.Empty;
|
||||
|
||||
// Local HRMS MySQL for employee lookup by RFID. Separate from production sync.
|
||||
public string HrmsLookupConnectionString { get; set; } = "Server=192.168.90.147;Port=3306;Database=hrms;User Id=utopia;Password=Utopia01;SslMode=None;";
|
||||
public string HrmsLookupConnectionString { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace UtopiaCanteenSystem.Services;
|
|||
|
||||
/// <summary>
|
||||
/// Meal schedule CRUD against production HRMS MySQL table hrms.meal_schedule.
|
||||
/// Uses IConfigService.GetHrmsLookupConnectionString() (same DB as employee lookup).
|
||||
/// Uses IConfigService.GetMySqlConnectionString() (production database connection).
|
||||
/// Schema: id (bigint), meal_name (varchar), start_time (time), end_time (time), created_at, updated_at, location_site_id (int).
|
||||
/// No is_active column; all rows are treated as active.
|
||||
/// </summary>
|
||||
|
|
@ -22,7 +22,7 @@ public class ProductionMealScheduleService : IMealScheduleService
|
|||
/// <inheritdoc />
|
||||
public IReadOnlyList<MealSchedule> GetActiveSchedulesForSite(string siteId)
|
||||
{
|
||||
var connStr = _configService.GetHrmsLookupConnectionString();
|
||||
var connStr = _configService.GetMySqlConnectionString();
|
||||
if (string.IsNullOrWhiteSpace(connStr))
|
||||
return Array.Empty<MealSchedule>();
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ public class ProductionMealScheduleService : IMealScheduleService
|
|||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<MealSchedule>> GetAllSchedulesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var connStr = _configService.GetHrmsLookupConnectionString();
|
||||
var connStr = _configService.GetMySqlConnectionString();
|
||||
if (string.IsNullOrWhiteSpace(connStr))
|
||||
return Array.Empty<MealSchedule>();
|
||||
|
||||
|
|
@ -67,9 +67,9 @@ public class ProductionMealScheduleService : IMealScheduleService
|
|||
/// <inheritdoc />
|
||||
public async Task<long> CreateAsync(MealSchedule schedule, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var connStr = _configService.GetHrmsLookupConnectionString();
|
||||
var connStr = _configService.GetMySqlConnectionString();
|
||||
if (string.IsNullOrWhiteSpace(connStr))
|
||||
throw new InvalidOperationException("HRMS MySQL connection string not configured.");
|
||||
throw new InvalidOperationException("Production MySQL connection string not configured.");
|
||||
|
||||
var utc = DateTime.UtcNow;
|
||||
var mealName = (schedule.MealName ?? string.Empty).Trim();
|
||||
|
|
@ -93,9 +93,9 @@ public class ProductionMealScheduleService : IMealScheduleService
|
|||
/// <inheritdoc />
|
||||
public async Task UpdateAsync(MealSchedule schedule, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var connStr = _configService.GetHrmsLookupConnectionString();
|
||||
var connStr = _configService.GetMySqlConnectionString();
|
||||
if (string.IsNullOrWhiteSpace(connStr))
|
||||
throw new InvalidOperationException("HRMS MySQL connection string not configured.");
|
||||
throw new InvalidOperationException("Production MySQL connection string not configured.");
|
||||
|
||||
var utc = DateTime.UtcNow;
|
||||
var mealName = (schedule.MealName ?? string.Empty).Trim();
|
||||
|
|
@ -117,9 +117,9 @@ public class ProductionMealScheduleService : IMealScheduleService
|
|||
/// <inheritdoc />
|
||||
public async Task DeleteAsync(long id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var connStr = _configService.GetHrmsLookupConnectionString();
|
||||
var connStr = _configService.GetMySqlConnectionString();
|
||||
if (string.IsNullOrWhiteSpace(connStr))
|
||||
throw new InvalidOperationException("HRMS MySQL connection string not configured.");
|
||||
throw new InvalidOperationException("Production MySQL connection string not configured.");
|
||||
|
||||
await using var conn = new MySqlConnection(connStr);
|
||||
await conn.OpenAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
|
|
|||
|
|
@ -215,13 +215,21 @@ public partial class ScannerDashboardViewModel : ObservableObject
|
|||
_clockTimer.Tick += (_, _) => CurrentTime = DateTime.Now.ToString("MM/dd/yyyy, hh:mm:ss tt");
|
||||
_clockTimer.Start();
|
||||
|
||||
// Load initial site from config (e.g. "SITE : 1" -> "1").
|
||||
var siteId = _configService.GetSiteId();
|
||||
if (!string.IsNullOrWhiteSpace(siteId) && siteId.StartsWith("SITE : ", StringComparison.OrdinalIgnoreCase))
|
||||
// Load initial site from config.
|
||||
var siteId = _configService.GetSiteId();
|
||||
if (!string.IsNullOrWhiteSpace(siteId))
|
||||
{
|
||||
var num = siteId.Substring("SITE : ".Length).Trim();
|
||||
if (num.Length > 0 && num.All(char.IsDigit))
|
||||
SiteNumber = num;
|
||||
// Extract digits from legacy format "SITE : X"or use value directly if already numeric
|
||||
if (siteId.StartsWith("SITE : ", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var num = siteId.Substring("SITE : ".Length).Trim();
|
||||
if (num.Length > 0 && num.All(char.IsDigit))
|
||||
SiteNumber = num;
|
||||
}
|
||||
else if (siteId.All(char.IsDigit))
|
||||
{
|
||||
SiteNumber = siteId;
|
||||
}
|
||||
}
|
||||
|
||||
RefreshScannerStatus();
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@
|
|||
"ScannerConnected": false,
|
||||
"ScanIntervalDays": 0,
|
||||
"ScanIntervalHours": 0,
|
||||
"ScanIntervalMinutes": 1,
|
||||
"ScanIntervalMinutes": 0,
|
||||
"ScanIntervalSeconds": 2,
|
||||
"AdminCardId": "ADMIN",
|
||||
"SiteId": "02",
|
||||
"DeviceId": "",
|
||||
"RememberAdminCredentials": false,
|
||||
"SavedAdminUsername": "",
|
||||
"SavedAdminPasswordProtected": "",
|
||||
"MySqlConnectionString": "Server=localhost;Database=hrms;User=root;Password=CHANGE_ME;Port=3306;"
|
||||
"MySqlConnectionString": "SERVER=utopia-industries-rr.c5qech8o9lgg.us-east-1.rds.amazonaws.com;DATABASE=hrms;UID=uind_hrms_user;PASSWORD=UINDHRMS01;"
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue