204 lines
6.9 KiB
C#
204 lines
6.9 KiB
C#
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Security.Claims;
|
||
|
|
using System.Security.Principal;
|
||
|
|
using System.Threading.Tasks;
|
||
|
|
using Microsoft.AspNetCore.Authentication;
|
||
|
|
using Microsoft.AspNetCore.Authorization;
|
||
|
|
using Microsoft.AspNetCore.Mvc;
|
||
|
|
using SkyArtShop.Models;
|
||
|
|
using SkyArtShop.Services;
|
||
|
|
|
||
|
|
namespace SkyArtShop.Controllers;
|
||
|
|
|
||
|
|
[Route("admin")]
|
||
|
|
[Authorize(Roles = "Admin,MasterAdmin,Cashier,Accountant")]
|
||
|
|
public class AdminController : Controller
|
||
|
|
{
|
||
|
|
private readonly PostgreSQLService _pgService;
|
||
|
|
|
||
|
|
private readonly PostgreAuthService _pgAuthService;
|
||
|
|
|
||
|
|
public AdminController(PostgreSQLService pgService, PostgreAuthService pgAuthService)
|
||
|
|
{
|
||
|
|
_pgService = pgService;
|
||
|
|
_pgAuthService = pgAuthService;
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpGet("login")]
|
||
|
|
[AllowAnonymous]
|
||
|
|
public IActionResult Login()
|
||
|
|
{
|
||
|
|
IIdentity? identity = base.User.Identity;
|
||
|
|
if (identity != null && identity.IsAuthenticated)
|
||
|
|
{
|
||
|
|
return RedirectToAction("Dashboard");
|
||
|
|
}
|
||
|
|
return View();
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpPost("login")]
|
||
|
|
[AllowAnonymous]
|
||
|
|
public async Task<IActionResult> Login(string email, string password)
|
||
|
|
{
|
||
|
|
AdminUser adminUser = await _pgAuthService.AuthenticateAsync(email, password);
|
||
|
|
if (adminUser == null)
|
||
|
|
{
|
||
|
|
base.ViewBag.Error = "Invalid email or password";
|
||
|
|
return View();
|
||
|
|
}
|
||
|
|
ClaimsPrincipal principal = _pgAuthService.CreateClaimsPrincipal(adminUser);
|
||
|
|
await base.HttpContext.SignInAsync("Cookies", principal, new AuthenticationProperties
|
||
|
|
{
|
||
|
|
IsPersistent = true,
|
||
|
|
ExpiresUtc = DateTimeOffset.UtcNow.AddDays(30.0)
|
||
|
|
});
|
||
|
|
return RedirectToAction("Dashboard");
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpGet("logout")]
|
||
|
|
public async Task<IActionResult> Logout()
|
||
|
|
{
|
||
|
|
await base.HttpContext.SignOutAsync("Cookies");
|
||
|
|
return RedirectToAction("Login");
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpGet("dashboard")]
|
||
|
|
public async Task<IActionResult> Dashboard()
|
||
|
|
{
|
||
|
|
List<Product> products = await _pgService.GetAllAsync<Product>("Products");
|
||
|
|
List<PortfolioProject> projects = await _pgService.GetAllAsync<PortfolioProject>("PortfolioProjects");
|
||
|
|
List<BlogPost> blogPosts = await _pgService.GetAllAsync<BlogPost>("BlogPosts");
|
||
|
|
List<Page> pages = await _pgService.GetAllAsync<Page>("Pages");
|
||
|
|
SiteSettings siteSettings = await _pgService.GetSiteSettingsAsync();
|
||
|
|
base.ViewBag.ProductCount = products.Count;
|
||
|
|
base.ViewBag.ProjectCount = projects.Count;
|
||
|
|
base.ViewBag.BlogCount = blogPosts.Count;
|
||
|
|
base.ViewBag.PageCount = pages.Count;
|
||
|
|
base.ViewBag.SiteName = siteSettings?.SiteName ?? "Sky Art Shop";
|
||
|
|
base.ViewBag.AdminEmail = base.User.Identity?.Name;
|
||
|
|
return View();
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpGet("")]
|
||
|
|
public IActionResult Index()
|
||
|
|
{
|
||
|
|
return RedirectToAction("Dashboard");
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpGet("system-status")]
|
||
|
|
[Authorize]
|
||
|
|
public async Task<IActionResult> SystemStatus()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var value = new
|
||
|
|
{
|
||
|
|
databaseConnected = true,
|
||
|
|
dbType = "PostgreSQL",
|
||
|
|
dbHost = "localhost",
|
||
|
|
dbName = "skyartshop",
|
||
|
|
dbVersion = "16",
|
||
|
|
userCount = (await _pgService.GetAllAsync<AdminUser>("AdminUsers")).Count,
|
||
|
|
timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss UTC")
|
||
|
|
};
|
||
|
|
return new JsonResult(value);
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
var value2 = new
|
||
|
|
{
|
||
|
|
databaseConnected = false,
|
||
|
|
error = ex.Message,
|
||
|
|
timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss UTC")
|
||
|
|
};
|
||
|
|
return new JsonResult(value2);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpGet("change-password")]
|
||
|
|
public IActionResult ChangePassword()
|
||
|
|
{
|
||
|
|
return View();
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpGet("diagnostic")]
|
||
|
|
public IActionResult DiagnosticTest()
|
||
|
|
{
|
||
|
|
return View();
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpGet("reset-password-emergency")]
|
||
|
|
[AllowAnonymous]
|
||
|
|
public async Task<IActionResult> EmergencyPasswordReset(string confirm, string secret)
|
||
|
|
{
|
||
|
|
string text = Environment.GetEnvironmentVariable("EMERGENCY_RESET_SECRET") ?? "skyart-emergency-2025";
|
||
|
|
if (secret != text)
|
||
|
|
{
|
||
|
|
return NotFound();
|
||
|
|
}
|
||
|
|
if (confirm != "yes-reset-now")
|
||
|
|
{
|
||
|
|
return Content("Add ?confirm=yes-reset-now&secret=YOUR_SECRET to URL to reset admin password");
|
||
|
|
}
|
||
|
|
string email = "admin@skyartshop.com";
|
||
|
|
string newPassword = "Admin123!";
|
||
|
|
AdminUser adminUser = await _pgService.GetUserByEmailAsync(email);
|
||
|
|
if (adminUser == null)
|
||
|
|
{
|
||
|
|
adminUser = new AdminUser
|
||
|
|
{
|
||
|
|
Email = email,
|
||
|
|
Name = "System Administrator",
|
||
|
|
Role = "MasterAdmin",
|
||
|
|
Permissions = new List<string>
|
||
|
|
{
|
||
|
|
"manage_users", "manage_products", "manage_orders", "manage_content", "manage_settings", "view_reports", "manage_finances", "manage_inventory", "manage_customers", "manage_blog",
|
||
|
|
"manage_portfolio", "manage_pages"
|
||
|
|
},
|
||
|
|
IsActive = true,
|
||
|
|
CreatedBy = "Emergency Reset",
|
||
|
|
CreatedAt = DateTime.UtcNow
|
||
|
|
};
|
||
|
|
}
|
||
|
|
adminUser.PasswordHash = _pgAuthService.HashPassword(newPassword);
|
||
|
|
adminUser.LastLogin = DateTime.UtcNow;
|
||
|
|
await _pgService.CreateAdminUserAsync(adminUser);
|
||
|
|
return Content($"\r\n<!DOCTYPE html>\r\n<html>\r\n<head>\r\n <title>Password Reset Complete</title>\r\n <style>\r\n body {{ font-family: Arial, sans-serif; max-width: 600px; margin: 50px auto; padding: 20px; }}\r\n .success {{ background: #d4edda; border: 1px solid #c3e6cb; padding: 20px; border-radius: 5px; }}\r\n .credentials {{ background: #f8f9fa; padding: 15px; margin: 20px 0; border-left: 4px solid #28a745; }}\r\n a {{ color: #007bff; text-decoration: none; }}\r\n </style>\r\n</head>\r\n<body>\r\n <div class='success'>\r\n <h2>✓ Password Reset Successful</h2>\r\n <p>The admin password has been reset.</p>\r\n <div class='credentials'>\r\n <strong>Login Credentials:</strong><br>\r\n Email: <code>{email}</code><br>\r\n Password: <code>{newPassword}</code>\r\n </div>\r\n <p><a href='/admin/login'>→ Go to Login Page</a></p>\r\n <p><small>For security, this URL will be disabled after first successful login.</small></p>\r\n </div>\r\n</body>\r\n</html>\r\n", "text/html");
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpPost("change-password")]
|
||
|
|
public async Task<IActionResult> ChangePassword(string currentPassword, string newPassword, string confirmPassword)
|
||
|
|
{
|
||
|
|
if (string.IsNullOrWhiteSpace(currentPassword) || string.IsNullOrWhiteSpace(newPassword))
|
||
|
|
{
|
||
|
|
base.ViewBag.Error = "All fields are required";
|
||
|
|
return View();
|
||
|
|
}
|
||
|
|
if (newPassword != confirmPassword)
|
||
|
|
{
|
||
|
|
base.ViewBag.Error = "New password and confirmation do not match";
|
||
|
|
return View();
|
||
|
|
}
|
||
|
|
if (newPassword.Length < 6)
|
||
|
|
{
|
||
|
|
base.ViewBag.Error = "Password must be at least 6 characters";
|
||
|
|
return View();
|
||
|
|
}
|
||
|
|
string text = base.User.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")?.Value;
|
||
|
|
if (string.IsNullOrEmpty(text))
|
||
|
|
{
|
||
|
|
base.ViewBag.Error = "User not found";
|
||
|
|
return View();
|
||
|
|
}
|
||
|
|
AdminUser adminUser = await _pgService.GetByIdAsync<AdminUser>("AdminUsers", text);
|
||
|
|
if (adminUser == null || !_pgAuthService.VerifyPassword(currentPassword, adminUser.PasswordHash))
|
||
|
|
{
|
||
|
|
base.ViewBag.Error = "Current password is incorrect";
|
||
|
|
return View();
|
||
|
|
}
|
||
|
|
base.ViewBag.Info = "Password change temporarily disabled during migration. Contact system admin.";
|
||
|
|
return View();
|
||
|
|
}
|
||
|
|
}
|