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; }