144 lines
5.4 KiB
C#
144 lines
5.4 KiB
C#
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.Extensions.Logging;
|
|
using RobotNet10.MapEditor.Shared.DTOs.Responses;
|
|
using RobotNet10.MapManager.Services;
|
|
|
|
namespace RobotNet10.MapManager.Controllers;
|
|
|
|
/// <summary>
|
|
/// Controller for managing background images for layout levels
|
|
/// </summary>
|
|
[ApiController]
|
|
[Route("api/images")]
|
|
[Authorize]
|
|
public class ImagesController(
|
|
IImageStorageService imageStorageService,
|
|
ILogger<ImagesController> logger) : ControllerBase
|
|
{
|
|
private readonly IImageStorageService _imageStorageService = imageStorageService;
|
|
private readonly ILogger<ImagesController> _logger = logger;
|
|
|
|
/// <summary>
|
|
/// Get background image for a layout level
|
|
/// </summary>
|
|
/// <param name="layoutLevelId">Layout level ID</param>
|
|
/// <returns>Image file (PNG)</returns>
|
|
[HttpGet("layout/{layoutLevelId}")]
|
|
[ProducesResponseType(typeof(FileStreamResult), 200)]
|
|
[ProducesResponseType(404)]
|
|
public async Task<IActionResult> GetLayoutImage(Guid layoutLevelId)
|
|
{
|
|
try
|
|
{
|
|
var imageStream = await _imageStorageService.GetImageAsync(layoutLevelId);
|
|
|
|
if (imageStream == null)
|
|
{
|
|
if (_logger.IsEnabled(LogLevel.Warning)) _logger.LogWarning("Image not found for layout level {LevelId}", layoutLevelId);
|
|
return NotFound(CreateErrorResponse($"Image not found for layout level '{layoutLevelId}'", "IMAGE_NOT_FOUND"));
|
|
}
|
|
|
|
return File(imageStream, "image/png", $"{layoutLevelId}.png");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (_logger.IsEnabled(LogLevel.Error)) _logger.LogError(ex, "Error retrieving image for layout level {LevelId}", layoutLevelId);
|
|
return StatusCode(500, CreateErrorResponse("Internal server error while retrieving image", "INTERNAL_ERROR"));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Upload or replace background image for a layout level
|
|
/// </summary>
|
|
/// <param name="layoutLevelId">Layout level ID</param>
|
|
/// <param name="file">Image file (PNG format)</param>
|
|
/// <returns>Success message</returns>
|
|
[HttpPost("layout/{layoutLevelId}")]
|
|
[ProducesResponseType(200)]
|
|
[ProducesResponseType(400)]
|
|
public async Task<IActionResult> UploadLayoutImage(Guid layoutLevelId, IFormFile file)
|
|
{
|
|
// Validate file
|
|
if (file == null || file.Length == 0)
|
|
{
|
|
return BadRequest(CreateErrorResponse("No file provided", "VALIDATION_ERROR"));
|
|
}
|
|
|
|
// Validate file type
|
|
if (!file.ContentType.Equals("image/png", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return BadRequest(CreateErrorResponse("Only PNG images are supported", "VALIDATION_ERROR"));
|
|
}
|
|
|
|
// Validate file size (max 10MB)
|
|
const long maxFileSize = 10 * 1024 * 1024; // 10MB
|
|
if (file.Length > maxFileSize)
|
|
{
|
|
return BadRequest(CreateErrorResponse($"File size exceeds maximum of {maxFileSize / 1024 / 1024}MB", "VALIDATION_ERROR"));
|
|
}
|
|
|
|
try
|
|
{
|
|
using var stream = file.OpenReadStream();
|
|
await _imageStorageService.SaveImageAsync(layoutLevelId, stream);
|
|
|
|
return Ok(new
|
|
{
|
|
message = "Image uploaded successfully",
|
|
layoutLevelId,
|
|
fileName = $"{layoutLevelId}.png",
|
|
size = file.Length
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (_logger.IsEnabled(LogLevel.Error)) _logger.LogError(ex, "Error uploading image for layout level {LevelId}", layoutLevelId);
|
|
return StatusCode(500, CreateErrorResponse("Internal server error while uploading image", "INTERNAL_ERROR"));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delete background image for a layout level
|
|
/// </summary>
|
|
/// <param name="layoutLevelId">Layout level ID</param>
|
|
/// <returns>No content on success</returns>
|
|
[HttpDelete("layout/{layoutLevelId}")]
|
|
[ProducesResponseType(204)]
|
|
[ProducesResponseType(404)]
|
|
public async Task<IActionResult> DeleteLayoutImage(Guid layoutLevelId)
|
|
{
|
|
try
|
|
{
|
|
var deleted = await _imageStorageService.DeleteImageAsync(layoutLevelId);
|
|
|
|
if (!deleted)
|
|
{
|
|
if (_logger.IsEnabled(LogLevel.Warning)) _logger.LogWarning("Image not found for deletion: {LevelId}", layoutLevelId);
|
|
return NotFound(CreateErrorResponse($"Image not found for layout level '{layoutLevelId}'", "IMAGE_NOT_FOUND"));
|
|
}
|
|
|
|
return NoContent();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (_logger.IsEnabled(LogLevel.Error)) _logger.LogError(ex, "Error deleting image for layout level {LevelId}", layoutLevelId);
|
|
return StatusCode(500, CreateErrorResponse("Internal server error while deleting image", "INTERNAL_ERROR"));
|
|
}
|
|
}
|
|
|
|
private static ErrorResponseDto CreateErrorResponse(
|
|
string error,
|
|
string? errorCode = null,
|
|
Dictionary<string, object>? details = null)
|
|
{
|
|
return new ErrorResponseDto
|
|
{
|
|
Error = error,
|
|
ErrorCode = errorCode,
|
|
Details = details
|
|
};
|
|
}
|
|
}
|