PlotDirector/PlotLine/Controllers/ManageAccountController.cs
2026-06-07 10:13:16 +01:00

155 lines
5.0 KiB
C#

using System.Text.Json;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using PlotLine.Data;
using PlotLine.Services;
using PlotLine.ViewModels;
namespace PlotLine.Controllers;
[Authorize]
public sealed class ManageAccountController(
ICurrentUserService currentUser,
IUserRepository users,
IAuthService authService,
ITwoFactorService twoFactorService,
ISubscriptionService subscriptions) : Controller
{
[HttpGet]
public async Task<IActionResult> Index()
{
var user = await GetCurrentUserAsync();
if (user is null)
{
return RedirectToAction("Login", "Account");
}
return View(new ManageAccountViewModel
{
User = user,
Subscription = await subscriptions.GetCurrentSubscriptionAsync(user.UserID)
});
}
[HttpGet]
public IActionResult ChangePassword()
{
return View(new ChangePasswordViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ChangePassword(ChangePasswordViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var result = await authService.ChangePasswordAsync(model);
if (!result.Success)
{
ModelState.AddModelError(string.Empty, result.ErrorMessage ?? "Your password could not be changed.");
return View(model);
}
TempData["AuthMessage"] = "Your password has been changed. Please sign in again.";
return RedirectToAction("Login", "Account");
}
[HttpGet]
public async Task<IActionResult> EnableTwoFactor()
{
var user = await GetCurrentUserAsync();
if (user is null)
{
return RedirectToAction("Login", "Account");
}
var secret = twoFactorService.GenerateSecretKey();
var uri = twoFactorService.GenerateQrCodeUri(user.Email, secret);
return View(new EnableTwoFactorViewModel
{
SecretKey = secret,
QrCodeUri = uri,
QrCodeImageDataUri = twoFactorService.GenerateQrCodeDataUri(uri)
});
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EnableTwoFactor(EnableTwoFactorViewModel model)
{
if (!ModelState.IsValid)
{
model.QrCodeUri = twoFactorService.GenerateQrCodeUri(currentUser.Email ?? string.Empty, model.SecretKey);
model.QrCodeImageDataUri = twoFactorService.GenerateQrCodeDataUri(model.QrCodeUri);
return View(model);
}
var result = await authService.EnableTwoFactorAsync(currentUser.UserId!.Value, model.SecretKey, model.Code);
if (!result.Success)
{
ModelState.AddModelError(string.Empty, result.ErrorMessage ?? "Two-factor authentication could not be enabled.");
model.QrCodeUri = twoFactorService.GenerateQrCodeUri(currentUser.Email ?? string.Empty, model.SecretKey);
model.QrCodeImageDataUri = twoFactorService.GenerateQrCodeDataUri(model.QrCodeUri);
return View(model);
}
TempData["RecoveryCodes"] = JsonSerializer.Serialize(result.RecoveryCodes);
TempData["AuthMessage"] = "Two-factor authentication has been enabled.";
return RedirectToAction(nameof(RecoveryCodes));
}
[HttpGet]
public IActionResult DisableTwoFactor()
{
return View(new DisableTwoFactorViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DisableTwoFactor(DisableTwoFactorViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var result = await authService.DisableTwoFactorAsync(currentUser.UserId!.Value, model.CurrentPassword);
if (!result.Success)
{
ModelState.AddModelError(string.Empty, result.ErrorMessage ?? "Two-factor authentication could not be disabled.");
return View(model);
}
TempData["AuthMessage"] = "Two-factor authentication has been disabled.";
return RedirectToAction(nameof(Index));
}
[HttpGet]
public IActionResult RecoveryCodes()
{
var codes = TempData["RecoveryCodes"] is string json
? JsonSerializer.Deserialize<IReadOnlyList<string>>(json) ?? Array.Empty<string>()
: Array.Empty<string>();
return View(new RecoveryCodesViewModel { RecoveryCodes = codes });
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> RegenerateRecoveryCodes()
{
var codes = await authService.GenerateRecoveryCodesAsync(currentUser.UserId!.Value);
TempData["RecoveryCodes"] = JsonSerializer.Serialize(codes);
TempData["AuthMessage"] = "New recovery codes have been generated.";
return RedirectToAction(nameof(RecoveryCodes));
}
private async Task<PlotLine.Models.AppUser?> GetCurrentUserAsync()
{
return currentUser.UserId is int userId ? await users.GetByIdAsync(userId) : null;
}
}