LANCommander/LANCommander.Server/Controllers/Api/RedistributablesController.cs
Pat Hartl 6ec919d1be Separate import and export functionality
This refactor splits the import and export functionality out of the ImportContext and adds an ExportContext. This also introduced separate importer and exporter implementations.

Additionally, adding archive, save, scripts, and server files to the final export archive has been implemented at the exporter implementation for each instead of handling it in the context. This should be a good pattern if other files need to be added down the road.
2025-07-27 17:51:50 -05:00

145 lines
5.5 KiB
C#

using AutoMapper;
using LANCommander.Server.Data.Models;
using LANCommander.Server.Extensions;
using LANCommander.Server.ImportExport;
using LANCommander.Server.Models;
using LANCommander.Server.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LANCommander.Server.Controllers.Api
{
[Authorize(AuthenticationSchemes = "Bearer")]
[Route("api/[controller]")]
[ApiController]
public class RedistributablesController : BaseApiController
{
private readonly IMapper Mapper;
private readonly RedistributableService RedistributableService;
private readonly StorageLocationService StorageLocationService;
private readonly ArchiveService ArchiveService;
private readonly ImportContext ImportContext;
public RedistributablesController(
ILogger<RedistributablesController> logger,
IMapper mapper,
RedistributableService redistributableService,
StorageLocationService storageLocationService,
ArchiveService archiveService,
ImportContext importContext) : base(logger)
{
Mapper = mapper;
RedistributableService = redistributableService;
StorageLocationService = storageLocationService;
ArchiveService = archiveService;
ImportContext = importContext;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<SDK.Models.Redistributable>>> GetAsync()
{
return Ok(Mapper.Map<IEnumerable<SDK.Models.Redistributable>>(await RedistributableService.GetAsync()));
}
[HttpGet("{id}")]
public async Task<ActionResult<SDK.Models.Redistributable>> GetAsync(Guid id)
{
var redistributable = await RedistributableService
.Include(r => r.Archives)
.Include(r => r.Scripts)
.GetAsync(id);
if (redistributable == null)
return NotFound();
return Ok(Mapper.Map<SDK.Models.Redistributable>(redistributable));
}
[HttpGet("{id}/Download")]
public async Task<IActionResult> DownloadAsync(Guid id)
{
var redistributable = await RedistributableService
.Include(r => r.Archives)
.GetAsync(id);
if (redistributable == null)
return NotFound();
if (redistributable.Archives == null || redistributable.Archives.Count == 0)
return NotFound();
var archive = redistributable.Archives.OrderByDescending(a => a.CreatedOn).First();
var filename = await ArchiveService.GetArchiveFileLocationAsync(archive);
if (!System.IO.File.Exists(filename))
return NotFound();
return File(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read), "application/octet-stream", $"{redistributable.Name.SanitizeFilename()}.zip");
}
[Authorize(Roles = RoleService.AdministratorRoleName)]
[HttpPost("Import/{objectKey}")]
public async Task<IActionResult> ImportAsync(Guid objectKey)
{
try
{
var uploadedPath = await ArchiveService.GetArchiveFileLocationAsync(objectKey.ToString());
var result = await ImportContext.InitializeImportAsync(uploadedPath);
return Ok(result);
}
catch (Exception ex)
{
Logger?.LogError(ex, "Could not import redistributable from upload");
return BadRequest(ex.Message);
}
}
[Authorize(Roles = RoleService.AdministratorRoleName)]
[HttpPost("UploadArchive")]
public async Task<IActionResult> UploadArchiveAsync(SDK.Models.UploadArchiveRequest request)
{
try
{
var storageLocation = await StorageLocationService.FirstOrDefaultAsync(l => request.StorageLocationId.HasValue ? l.Id == request.StorageLocationId.Value : l.Default);
var archive = await ArchiveService.FirstOrDefaultAsync(a => a.RedistributableId == request.Id && a.Version == request.Version);
var archivePath = await ArchiveService.GetArchiveFileLocationAsync(archive);
if (archive != null)
{
System.IO.File.Delete(archivePath);
archive.ObjectKey = request.ObjectKey.ToString();
archive.Changelog = request.Changelog;
archive.CompressedSize = new System.IO.FileInfo(archivePath).Length;
archive.StorageLocation = storageLocation;
archive = await ArchiveService.UpdateAsync(archive);
}
else
{
archive = new Archive()
{
ObjectKey = request.ObjectKey.ToString(),
Changelog = request.Changelog,
RedistributableId = request.Id,
CompressedSize = new System.IO.FileInfo(archivePath).Length,
StorageLocation = storageLocation,
};
await ArchiveService.AddAsync(archive);
}
return Ok();
}
catch (Exception ex)
{
Logger?.LogError(ex, "Could not upload redistributable archive");
return BadRequest(ex.Message);
}
}
}
}