114 lines
4.7 KiB
C#
114 lines
4.7 KiB
C#
using PlotLine.Data;
|
|
using PlotLine.Models;
|
|
|
|
namespace PlotLine.Services;
|
|
|
|
public sealed class AccountDeletionService(
|
|
IUserRepository users,
|
|
IProjectRepository projects,
|
|
ISubscriptionService subscriptions,
|
|
IHardDeleteFileCleanupService fileCleanup,
|
|
ILogger<AccountDeletionService> logger) : IAccountDeletionService
|
|
{
|
|
public async Task<AccountDeletionResult> HardDeleteAccountAsync(int userId)
|
|
{
|
|
var user = await users.GetByIdAsync(userId);
|
|
if (user is null)
|
|
{
|
|
logger.LogWarning("Account hard delete requested for missing user {UserID}.", userId);
|
|
return AccountDeletionResult.MissingUser();
|
|
}
|
|
|
|
if (await subscriptions.HasPaidBillingRiskAsync(userId))
|
|
{
|
|
logger.LogWarning("Account hard delete blocked for user {UserID}: paid billing risk exists.", userId);
|
|
return AccountDeletionResult.PaidSubscriptionBlocked();
|
|
}
|
|
|
|
var deletedProjects = 0;
|
|
var deletedFiles = 0;
|
|
var missingFiles = 0;
|
|
var failedFiles = 0;
|
|
|
|
var ownedProjects = await projects.ListOwnedForAccountDeletionAsync(userId);
|
|
logger.LogInformation("Account hard delete started for user {UserID} with {OwnedProjectCount} owned projects.", userId, ownedProjects.Count);
|
|
|
|
foreach (var project in ownedProjects)
|
|
{
|
|
IReadOnlyList<string> projectFilePaths;
|
|
try
|
|
{
|
|
projectFilePaths = await projects.ListHardDeleteFilePathsForAccountDeletionAsync(project.ProjectID, userId);
|
|
await projects.HardDeleteForAccountDeletionAsync(project.ProjectID, userId);
|
|
deletedProjects++;
|
|
logger.LogInformation("Account hard delete removed project {ProjectID} for user {UserID}. {FilePathCount} file paths queued for cleanup.",
|
|
project.ProjectID,
|
|
userId,
|
|
projectFilePaths.Count);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.LogError(ex, "Account hard delete failed while deleting project {ProjectID} for user {UserID}. Account deletion stopped.",
|
|
project.ProjectID,
|
|
userId);
|
|
return AccountDeletionResult.Failure("The account could not be deleted. No further account data was removed.");
|
|
}
|
|
|
|
var projectCleanup = fileCleanup.DeleteFiles("account project hard delete", project.ProjectID, projectFilePaths);
|
|
deletedFiles += projectCleanup.Deleted;
|
|
missingFiles += projectCleanup.Missing;
|
|
failedFiles += projectCleanup.Failed;
|
|
}
|
|
|
|
IReadOnlyList<string> userFilePaths;
|
|
try
|
|
{
|
|
userFilePaths = await users.ListHardDeleteFilePathsAsync(userId);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.LogError(ex, "Account hard delete could not list remaining user-level files for user {UserID}. Account deletion stopped.", userId);
|
|
return AccountDeletionResult.Failure("The account could not be deleted. No further account data was removed.");
|
|
}
|
|
|
|
var userCleanup = fileCleanup.DeleteFiles("account user file hard delete", userId, userFilePaths);
|
|
deletedFiles += userCleanup.Deleted;
|
|
missingFiles += userCleanup.Missing;
|
|
failedFiles += userCleanup.Failed;
|
|
|
|
try
|
|
{
|
|
var deleted = await users.HardDeleteAccountDataAsync(userId);
|
|
if (!deleted)
|
|
{
|
|
logger.LogError("Account hard delete failed to remove the AppUser row for user {UserID}.", userId);
|
|
return AccountDeletionResult.Failure("The account could not be deleted.");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.LogError(ex, "Account hard delete failed while removing remaining user data for user {UserID}.", userId);
|
|
return AccountDeletionResult.Failure("The account could not be deleted.");
|
|
}
|
|
|
|
if (failedFiles > 0)
|
|
{
|
|
logger.LogWarning("Account hard delete completed for user {UserID}, but file cleanup had {FailedFileCount} failures, {DeletedFileCount} deleted files, and {MissingFileCount} missing files.",
|
|
userId,
|
|
failedFiles,
|
|
deletedFiles,
|
|
missingFiles);
|
|
}
|
|
else
|
|
{
|
|
logger.LogInformation("Account hard delete completed for user {UserID}: {DeletedProjectCount} projects, {DeletedFileCount} files deleted, {MissingFileCount} files missing.",
|
|
userId,
|
|
deletedProjects,
|
|
deletedFiles,
|
|
missingFiles);
|
|
}
|
|
|
|
return AccountDeletionResult.Success(deletedProjects, deletedFiles, missingFiles, failedFiles);
|
|
}
|
|
}
|