PlotDirector/PlotLine/Services/ProjectExportService.cs
2026-06-08 15:23:15 +01:00

69 lines
2.2 KiB
C#

using System.Text.Json;
using PlotLine.Data;
using PlotLine.Models;
namespace PlotLine.Services;
public interface IProjectExportService
{
Task<ProjectBackupResult?> ExportAsync(int projectId);
}
public sealed class ProjectExportService(
IProjectBackupRepository backups,
IProjectActivityService activity,
ICurrentUserService currentUser,
ILogger<ProjectExportService> logger) : IProjectExportService
{
private static readonly JsonSerializerOptions JsonOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
};
public async Task<ProjectBackupResult?> ExportAsync(int projectId)
{
if (!currentUser.UserId.HasValue)
{
return null;
}
var backup = await backups.GetProjectBackupAsync(projectId, currentUser.UserId.Value);
if (backup?.Project is null)
{
logger.LogWarning("Project backup export requested for missing project {ProjectID}.", projectId);
return null;
}
var json = JsonSerializer.Serialize(backup, JsonOptions);
var fileName = BuildFileName(backup.Project.ProjectName, backup.ExportedAtUtc);
logger.LogInformation("Project backup export generated for project {ProjectID} with {ByteCount} JSON bytes.", projectId, json.Length);
await activity.RecordAsync(projectId, "Exported", "Project", projectId, backup.Project.ProjectName, "Project backup exported.");
return new ProjectBackupResult
{
FileName = fileName,
ContentType = "application/json",
Json = json
};
}
private static string BuildFileName(string projectName, DateTime exportedAtUtc)
{
var safeTitle = new string(projectName
.Select(c => Path.GetInvalidFileNameChars().Contains(c) ? '_' : c)
.ToArray())
.Trim();
safeTitle = string.Join("_", safeTitle.Split(' ', StringSplitOptions.RemoveEmptyEntries));
if (string.IsNullOrWhiteSpace(safeTitle))
{
safeTitle = "PlotDirector_Project";
}
return $"{safeTitle}_{exportedAtUtc:yyyy-MM-dd_HHmm}.plotdirector";
}
}