using Microsoft.AspNetCore.Authorization;
using PowderCoating.Shared.Constants;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using PowderCoating.Core.Entities;
using PowderCoating.Infrastructure.Data;
using System.Reflection;
namespace PowderCoating.Web.Controllers;
///
/// SuperAdmin-only system health and runtime information page.
/// Aggregates application version, database connectivity, migration state,
/// seed history, user counts, and host environment details into a single view
/// to give platform operators a quick operational snapshot without needing
/// server or database console access.
///
[Authorize(Policy = AppConstants.Policies.SuperAdminOnly)]
public class SystemInfoController : Controller
{
private readonly ApplicationDbContext _dbContext;
private readonly UserManager _userManager;
private readonly IWebHostEnvironment _env;
public SystemInfoController(
ApplicationDbContext dbContext,
UserManager userManager,
IWebHostEnvironment env)
{
_dbContext = dbContext;
_userManager = userManager;
_env = env;
}
///
/// Gathers and renders runtime system information into a
/// .
///
/// Key design decisions:
///
/// - The informational version string (from
/// ) is preferred over the
/// numeric version because it can include Git commit hashes or pre-release labels
/// set during CI builds.
/// - Database connectivity is tested via CanConnectAsync() rather than
/// a raw query to keep the check lightweight and independent of schema state.
/// - Applied migrations are listed (not pending) so the view can report the
/// last applied migration without needing write access to the migration history.
/// - SeedData.LastSeedRun is a static field updated by the seed service
/// each time seeding completes; it shows null if no seed has run since
/// the last application restart.
/// - Server time is reported in both local and UTC to help operators diagnose
/// timezone-related scheduling issues.
///
///
///
public async Task Index()
{
// App version from assembly
var assembly = Assembly.GetEntryAssembly();
var version = assembly?.GetName().Version?.ToString() ?? "Unknown";
var infoVersion = assembly?
.GetCustomAttribute()
?.InformationalVersion ?? version;
// Database connectivity
bool dbConnected;
string dbStatus;
string? lastMigration = null;
int migrationCount = 0;
try
{
dbConnected = await _dbContext.Database.CanConnectAsync();
dbStatus = dbConnected ? "Connected" : "Unreachable";
if (dbConnected)
{
var applied = await _dbContext.Database.GetAppliedMigrationsAsync();
var migrations = applied.ToList();
migrationCount = migrations.Count;
lastMigration = migrations.LastOrDefault();
}
}
catch (Exception ex)
{
dbConnected = false;
dbStatus = $"Error: {ex.Message}";
}
// User counts
var totalUsers = await _userManager.Users.CountAsync();
var activeUsers = await _userManager.Users.CountAsync(u => u.IsActive);
var vm = new SystemInfoViewModel
{
AppVersion = infoVersion,
DatabaseConnected = dbConnected,
DatabaseStatus = dbStatus,
LastAppliedMigration = lastMigration,
MigrationCount = migrationCount,
LastSeedRun = SeedData.LastSeedRun,
ServerTime = DateTime.Now,
ServerTimeUtc = DateTime.UtcNow,
ServerTimeZone = TimeZoneInfo.Local.DisplayName,
ActiveUserCount = activeUsers,
TotalUserCount = totalUsers,
EnvironmentName = _env.EnvironmentName,
MachineName = Environment.MachineName,
OsDescription = System.Runtime.InteropServices.RuntimeInformation.OSDescription,
RuntimeVersion = System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription
};
return View(vm);
}
}
public class SystemInfoViewModel
{
public string AppVersion { get; set; } = string.Empty;
public bool DatabaseConnected { get; set; }
public string DatabaseStatus { get; set; } = string.Empty;
public string? LastAppliedMigration { get; set; }
public int MigrationCount { get; set; }
public DateTime? LastSeedRun { get; set; }
public DateTime ServerTime { get; set; }
public DateTime ServerTimeUtc { get; set; }
public string ServerTimeZone { get; set; } = string.Empty;
public int ActiveUserCount { get; set; }
public int TotalUserCount { get; set; }
public string EnvironmentName { get; set; } = string.Empty;
public string MachineName { get; set; } = string.Empty;
public string OsDescription { get; set; } = string.Empty;
public string RuntimeVersion { get; set; } = string.Empty;
}