Initial commit

This commit is contained in:
2026-07-03 16:37:12 +07:00
commit 63b8c1ea8b
1931 changed files with 640587 additions and 0 deletions

View File

@@ -0,0 +1,48 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace RobotNet10.FleetManager.Controllers;
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class LogsManagerController(Services.Logger<LogsManagerController> Logger) : ControllerBase
{
private readonly string LoggerDirectory = Path.Combine(AppContext.BaseDirectory, "logs");
[HttpGet]
public async Task<IEnumerable<string>> GetLogs([FromQuery(Name = "date")] DateTime date)
{
string temp = "";
try
{
string fileName = $"{date:yyyy-MM-dd}.log";
string path = Path.Combine(LoggerDirectory, fileName);
if (!Path.GetFullPath(path).StartsWith(Path.GetFullPath(LoggerDirectory)))
{
Logger.Warning($"GetLogs: Invalid path detected.");
return [];
}
if (!System.IO.File.Exists(path))
{
Logger.Warning($"GetLogs: Log file not found for date {date:d} - {path}.");
return [];
}
temp = Path.Combine(LoggerDirectory, $"{Guid.NewGuid()}.log");
System.IO.File.Copy(path, temp);
return await System.IO.File.ReadAllLinesAsync(temp);
}
catch (Exception ex)
{
Logger.Warning($"GetLogs: System error occurred - {ex.Message}");
return [];
}
finally
{
if (System.IO.File.Exists(temp)) System.IO.File.Delete(temp);
}
}
}

View File

@@ -0,0 +1,254 @@
using Microsoft.AspNetCore.Mvc;
using RobotNet10.FleetManager.Data;
using RobotNet10.FleetManager.Services;
using RobotNet10.FleetManager.Shared.DTOs.Robot;
using RobotNet10.FleetManager.Shared.DTOs.Responses;
namespace RobotNet10.FleetManager.Controllers;
/// <summary>
/// API controller for managing robots.
/// Provides RESTful endpoints for CRUD operations on robots.
/// </summary>
/// <remarks>
/// All endpoints return appropriate HTTP status codes and error responses.
/// Supports filtering by model ID and map ID.
/// </remarks>
[ApiController]
[Route("api/robots")]
public class RobotController(IRobotService robotService, Services.Logger<RobotController> logger) : ControllerBase
{
private readonly IRobotService _robotService = robotService;
private readonly Services.Logger<RobotController> _logger = logger;
/// <summary>
/// Get all robots with optional filters
/// </summary>
[HttpGet]
[ProducesResponseType(typeof(List<RobotDto>), StatusCodes.Status200OK)]
public async Task<ActionResult<List<RobotDto>>> GetAll([FromQuery] Guid? modelId, [FromQuery] Guid? mapId)
{
try
{
var robots = await _robotService.GetAllAsync(modelId, mapId);
var dtos = robots.Select(r => MapToDto(r)).ToList();
return Ok(dtos);
}
catch (Exception ex)
{
_logger.Error($"Error getting all robots: {ex.Message}");
return StatusCode(500, new ErrorResponseDto { Error = "An error occurred while retrieving robots." });
}
}
/// <summary>
/// Get robot by ID
/// </summary>
[HttpGet("{id}")]
[ProducesResponseType(typeof(RobotDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<RobotDto>> GetById(Guid id)
{
try
{
var robot = await _robotService.GetByIdAsync(id);
if (robot == null)
{
return NotFound(new ErrorResponseDto { Error = $"Robot with ID {id} not found." });
}
return Ok(MapToDto(robot));
}
catch (Exception ex)
{
_logger.Error($"Error getting robot {id}: {ex.Message}");
return StatusCode(500, new ErrorResponseDto { Error = "An error occurred while retrieving the robot." });
}
}
/// <summary>
/// Get robot by RobotId (string identifier)
/// </summary>
[HttpGet("robotId/{robotId}")]
[ProducesResponseType(typeof(RobotDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<RobotDto>> GetByRobotId(string robotId)
{
try
{
var robot = await _robotService.GetByRobotIdAsync(robotId);
if (robot == null)
{
return NotFound(new ErrorResponseDto { Error = $"Robot with RobotId '{robotId}' not found." });
}
return Ok(MapToDto(robot));
}
catch (Exception ex)
{
_logger.Error($"Error getting robot with RobotId '{robotId}': {ex.Message}");
return StatusCode(500, new ErrorResponseDto { Error = "An error occurred while retrieving the robot." });
}
}
/// <summary>
/// Search robots by query string
/// </summary>
[HttpGet("search")]
[ProducesResponseType(typeof(List<RobotDto>), StatusCodes.Status200OK)]
public async Task<ActionResult<List<RobotDto>>> Search([FromQuery] string query)
{
try
{
var robots = await _robotService.SearchAsync(query);
var dtos = robots.Select(r => MapToDto(r)).ToList();
return Ok(dtos);
}
catch (Exception ex)
{
_logger.Error($"Error searching robots with query '{query}': {ex.Message}");
return StatusCode(500, new ErrorResponseDto { Error = "An error occurred while searching robots." });
}
}
/// <summary>
/// Get all robots by model ID
/// </summary>
[HttpGet("model/{modelId}")]
[ProducesResponseType(typeof(List<RobotDto>), StatusCodes.Status200OK)]
public async Task<ActionResult<List<RobotDto>>> GetByModelId(Guid modelId)
{
try
{
var robots = await _robotService.GetByModelIdAsync(modelId);
var dtos = robots.Select(r => MapToDto(r)).ToList();
return Ok(dtos);
}
catch (Exception ex)
{
_logger.Error($"Error getting robots by model {modelId}: {ex.Message}");
return StatusCode(500, new ErrorResponseDto { Error = "An error occurred while retrieving robots." });
}
}
/// <summary>
/// Create a new robot
/// </summary>
[HttpPost]
[ProducesResponseType(typeof(RobotDto), StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<RobotDto>> Create([FromBody] CreateRobotRequest request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new ErrorResponseDto
{
Error = "Validation failed",
Details = ModelState.ToDictionary(
kvp => kvp.Key,
kvp => (object)(kvp.Value?.Errors.Select(e => e.ErrorMessage).ToArray() ?? Array.Empty<string>()))
});
}
var robot = await _robotService.CreateAsync(request);
var dto = MapToDto(robot);
return CreatedAtAction(nameof(GetById), new { id = robot.Id }, dto);
}
catch (InvalidOperationException ex)
{
return BadRequest(new ErrorResponseDto { Error = ex.Message });
}
catch (KeyNotFoundException ex)
{
return BadRequest(new ErrorResponseDto { Error = ex.Message });
}
catch (Exception ex)
{
_logger.Error($"Error creating robot: {ex.Message}");
return StatusCode(500, new ErrorResponseDto { Error = "An error occurred while creating the robot." });
}
}
/// <summary>
/// Update an existing robot
/// </summary>
[HttpPut("{id}")]
[ProducesResponseType(typeof(RobotDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<RobotDto>> Update(Guid id, [FromBody] UpdateRobotRequest request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new ErrorResponseDto
{
Error = "Validation failed",
Details = ModelState.ToDictionary(
kvp => kvp.Key,
kvp => (object)(kvp.Value?.Errors.Select(e => e.ErrorMessage).ToArray() ?? Array.Empty<string>()))
});
}
var robot = await _robotService.UpdateAsync(id, request);
var dto = MapToDto(robot);
return Ok(dto);
}
catch (KeyNotFoundException ex)
{
return NotFound(new ErrorResponseDto { Error = ex.Message });
}
catch (InvalidOperationException ex)
{
return BadRequest(new ErrorResponseDto { Error = ex.Message });
}
catch (Exception ex)
{
_logger.Error($"Error updating robot {id}: {ex.Message}");
return StatusCode(500, new ErrorResponseDto { Error = "An error occurred while updating the robot." });
}
}
/// <summary>
/// Delete a robot
/// </summary>
[HttpDelete("{id}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> Delete(Guid id)
{
try
{
var deleted = await _robotService.DeleteAsync(id);
if (!deleted)
{
return NotFound(new ErrorResponseDto { Error = $"Robot with ID {id} not found." });
}
return NoContent();
}
catch (Exception ex)
{
_logger.Error($"Error deleting robot {id}: {ex.Message}");
return StatusCode(500, new ErrorResponseDto { Error = "An error occurred while deleting the robot." });
}
}
private static RobotDto MapToDto(Robot robot)
{
return new RobotDto
{
Id = robot.Id,
RobotId = robot.RobotId,
Name = robot.Name,
ModelId = robot.ModelId,
ModelName = robot.Model?.ModelName,
MapId = robot.MapId,
CreatedDate = robot.CreatedDate,
UpdatedDate = robot.UpdatedDate
};
}
}

View File

@@ -0,0 +1,149 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RobotNet10.FleetManager.Data;
using RobotNet10.FleetManager.Services;
using RobotNet10.FleetManager.Services.RobotManager;
using RobotNet10.FleetManager.Services.RobotManager.Models;
using RobotNet10.FleetManager.Shared.Models;
using RobotNet10.MapManager.Services;
using RobotNet10.Shared;
namespace RobotNet10.FleetManager.Controllers;
[Route("api/[controller]")]
[ApiController]
[AllowAnonymous]
public class RobotManagerController(IRobotService RobotService, ILayoutDataService LayoutManager, IRobotManagerService RobotManager, Services.Logger<RobotManagerController> Logger) : ControllerBase
{
[HttpPost]
[Route("MoveToNode")]
public async Task<MessageResult> MoveToNode([FromBody] RobotMoveToNodeModel model)
{
try
{
if (string.IsNullOrEmpty(model.NodeName)) return new(false, "NodeName cannot be empty..");
var robot = await RobotService.GetByRobotIdAsync(model.RobotId);
if (robot is null) return new(false, "RobotId does not exist.");
if (robot.MapId is null || robot.MapId == Guid.Empty) return new(false, "The robot has not been assigned a map.");
var robotController = RobotManager.GetRobotController(model.RobotId);
if (robotController is null || !robotController.IsOnline) return new(false, "The robot is not online.");
if (robotController.Data is null || robotController.Data.State is null) return new(false, "The robot is broken connection.");
var map = await LayoutManager.GetLayoutDataAsync(robot.MapId ?? Guid.Empty);
var node = map.Nodes.FirstOrDefault(n => n.NodeName == model.NodeName && n.LevelId == map.LayoutLevelId);
if (node is null) return new(false, "This Node does not exist.");
if (!robotController.IsReady) return new(false, "The robot is busy.");
var move = await robotController.MoveToNodeAsync(model.NodeName, model.LastAngle);
if (move.IsSuccess) return new(true);
Logger.Warning($"RobotManager API: MoveToNode for robot {model.RobotId} to node {model.NodeName} failed: {move.Message}");
return new(false, "Request failed.");
}
catch (Exception ex)
{
Logger.Error($"RobotManager API: MoveToNode for robot {model.RobotId} to node {model.NodeName} error: {ex.Message}");
return new(false, "An error occurred.");
}
}
[HttpDelete]
[Route("MoveToNode/{robotId}")]
public async Task<MessageResult> Cancel(string robotId)
{
try
{
var robot = await RobotService.GetByRobotIdAsync(robotId);
if (robot is null) return new(false, "RobotId does not exist.");
var robotController = RobotManager.GetRobotController(robotId);
if (robotController is null || !robotController.IsOnline) return new(false, "The robot is not online.");
if (robotController.Data is null || robotController.Data.State is null) return new(false, "The robot is broken connection.");
var cancel = await robotController.CancelOrderAsync();
if (cancel.IsSuccess) return new(true);
Logger.Warning($"RobotManager API: Cancel order for robot {robotId} failed: {cancel.Message}");
return new(false, "Request failed.");
}
catch (Exception ex)
{
Logger.Error($"RobotManager API: Cancel order for robot {robotId} error: {ex.Message}");
return new(false, "An error occurred.");
}
}
[HttpPost]
[Route("InstantActions")]
public async Task<MessageResult> InstantAction([FromBody] RobotInstantActionModel model)
{
try
{
var robot = await RobotService.GetByRobotIdAsync(model.RobotId);
if (robot is null) return new(false, "RobotId does not exist.");
if (robot.MapId is null || robot.MapId == Guid.Empty) return new(false, "The robot has not been assigned a map.");
var robotController = RobotManager.GetRobotController(model.RobotId);
if (robotController is null || !robotController.IsOnline) return new(false, "The robot is not online.");
if (robotController.Data is null || robotController.Data.State is null) return new(false, "The robot is broken connection.");
var instantAction = await robotController.SendInstantActionAsync(model.Action);
if (instantAction.IsSuccess) return new(true);
Logger.Warning($"RobotManager API: Send instant action for robot {model.RobotId} failed: {instantAction.Message}");
return new(false, "Request failed.");
}
catch (Exception ex)
{
Logger.Error($"RobotManager API: Send instant action for robot {model.RobotId}, action type {model.Action.ActionType} error: {ex.Message}");
return new(false, "An error occurred.");
}
}
[HttpGet]
[Route("State/{robotId}")]
public async Task<MessageResult<RobotData>> GetState(string robotId)
{
try
{
var robot = await RobotService.GetByRobotIdAsync(robotId);
if (robot is null) return new(false, null, "RobotId does not exist.");
if (robot.MapId is null || robot.MapId == Guid.Empty) return new(false, null, "The robot has not been assigned a map.");
var robotController = RobotManager.GetRobotController(robotId);
if (robotController is null || !robotController.IsOnline) return new(false, null, "The robot is not online.");
if (robotController.Data is null || robotController.Data.State is null) return new(false, null, "The robot is broken connection.");
return new(true, robotController.Data, "");
}
catch (Exception ex)
{
Logger.Error($"RobotManager API: GetState for robot {robotId} error: {ex.Message}");
return new(false, null, "An error occurred.");
}
}
[HttpGet]
[Route("OnlineStatus/{robotId}")]
public async Task<MessageResult<bool>> GetOnlineStatus(string robotId)
{
try
{
var robot = await RobotService.GetByRobotIdAsync(robotId);
if (robot is null) return new(false, false, "RobotId does not exist.");
var robotController = RobotManager.GetRobotController(robotId);
var isOnline = robotController?.IsOnline ?? false;
return new(true, isOnline, "");
}
catch (Exception ex)
{
Logger.Error($"RobotManager API: GetOnlineStatus for robot {robotId} error: {ex.Message}");
return new(false, false, "An error occurred.");
}
}
}

View File

@@ -0,0 +1,239 @@
using Microsoft.AspNetCore.Mvc;
using RobotNet10.FleetManager.Data;
using RobotNet10.FleetManager.Services;
using RobotNet10.FleetManager.Shared.DTOs.RobotModel;
using RobotNet10.FleetManager.Shared.DTOs.Responses;
namespace RobotNet10.FleetManager.Controllers;
/// <summary>
/// API controller for managing robot models.
/// Provides RESTful endpoints for CRUD operations on robot models.
/// </summary>
/// <remarks>
/// All endpoints return appropriate HTTP status codes and error responses.
/// Image operations are handled separately via RobotModelImagesController.
/// </remarks>
[ApiController]
[Route("api/robot-models")]
public class RobotModelController(IRobotModelService robotModelService, Services.Logger<RobotModelController> logger) : ControllerBase
{
private readonly IRobotModelService _robotModelService = robotModelService;
private readonly Services.Logger<RobotModelController> _logger = logger;
/// <summary>
/// Get all robot models
/// </summary>
[HttpGet]
[ProducesResponseType(typeof(List<RobotModelDto>), StatusCodes.Status200OK)]
public async Task<ActionResult<List<RobotModelDto>>> GetAll()
{
try
{
var models = await _robotModelService.GetAllAsync();
var dtos = models.Select(m => MapToDto(m)).ToList();
return Ok(dtos);
}
catch (Exception ex)
{
_logger.Error($"Error getting all robot models: {ex.Message}");
return StatusCode(500, new ErrorResponseDto { Error = "An error occurred while retrieving robot models." });
}
}
/// <summary>
/// Get robot model by ID
/// </summary>
[HttpGet("{id}")]
[ProducesResponseType(typeof(RobotModelDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<RobotModelDto>> GetById(Guid id)
{
try
{
var model = await _robotModelService.GetByIdAsync(id);
if (model == null)
{
return NotFound(new ErrorResponseDto { Error = $"Robot model with ID {id} not found." });
}
return Ok(MapToDto(model));
}
catch (Exception ex)
{
_logger.Error($"Error getting robot model {id}: {ex.Message}");
return StatusCode(500, new ErrorResponseDto { Error = "An error occurred while retrieving the robot model." });
}
}
/// <summary>
/// Search robot models by query string
/// </summary>
[HttpGet("search")]
[ProducesResponseType(typeof(List<RobotModelDto>), StatusCodes.Status200OK)]
public async Task<ActionResult<List<RobotModelDto>>> Search([FromQuery] string query)
{
try
{
var models = await _robotModelService.SearchAsync(query);
var dtos = models.Select(m => MapToDto(m)).ToList();
return Ok(dtos);
}
catch (Exception ex)
{
_logger.Error($"Error searching robot models with query '{query}': {ex.Message}");
return StatusCode(500, new ErrorResponseDto { Error = "An error occurred while searching robot models." });
}
}
/// <summary>
/// Get usage information for a robot model
/// </summary>
[HttpGet("{id}/usage")]
[ProducesResponseType(typeof(RobotModelUsageInfoDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<RobotModelUsageInfoDto>> GetUsageInfo(Guid id)
{
try
{
var usageInfo = await _robotModelService.GetUsageInfoAsync(id);
return Ok(usageInfo);
}
catch (KeyNotFoundException ex)
{
return NotFound(new ErrorResponseDto { Error = ex.Message });
}
catch (Exception ex)
{
_logger.Error($"Error getting usage info for robot model {id}: {ex.Message}");
return StatusCode(500, new ErrorResponseDto { Error = "An error occurred while retrieving usage information." });
}
}
/// <summary>
/// Create a new robot model
/// </summary>
[HttpPost]
[ProducesResponseType(typeof(RobotModelDto), StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<RobotModelDto>> Create([FromBody] CreateRobotModelRequest request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new ErrorResponseDto
{
Error = "Validation failed",
Details = ModelState.ToDictionary(
kvp => kvp.Key,
kvp => (object)(kvp.Value?.Errors.Select(e => e.ErrorMessage).ToArray() ?? Array.Empty<string>()))
});
}
var model = await _robotModelService.CreateAsync(request);
var dto = MapToDto(model);
return CreatedAtAction(nameof(GetById), new { id = model.Id }, dto);
}
catch (InvalidOperationException ex)
{
return BadRequest(new ErrorResponseDto { Error = ex.Message });
}
catch (Exception ex)
{
_logger.Error($"Error creating robot model: {ex.Message}");
return StatusCode(500, new ErrorResponseDto { Error = "An error occurred while creating the robot model." });
}
}
/// <summary>
/// Update an existing robot model
/// </summary>
[HttpPut("{id}")]
[ProducesResponseType(typeof(RobotModelDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<RobotModelDto>> Update(Guid id, [FromBody] UpdateRobotModelRequest request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new ErrorResponseDto
{
Error = "Validation failed",
Details = ModelState.ToDictionary(
kvp => kvp.Key,
kvp => (object)(kvp.Value?.Errors.Select(e => e.ErrorMessage).ToArray() ?? Array.Empty<string>()))
});
}
var model = await _robotModelService.UpdateAsync(id, request);
var dto = MapToDto(model);
return Ok(dto);
}
catch (KeyNotFoundException ex)
{
return NotFound(new ErrorResponseDto { Error = ex.Message });
}
catch (InvalidOperationException ex)
{
return BadRequest(new ErrorResponseDto { Error = ex.Message });
}
catch (Exception ex)
{
_logger.Error($"Error updating robot model {id}: {ex.Message}");
return StatusCode(500, new ErrorResponseDto { Error = "An error occurred while updating the robot model." });
}
}
/// <summary>
/// Delete a robot model
/// </summary>
[HttpDelete("{id}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> Delete(Guid id)
{
try
{
var deleted = await _robotModelService.DeleteAsync(id);
if (!deleted)
{
return NotFound(new ErrorResponseDto { Error = $"Robot model with ID {id} not found." });
}
return NoContent();
}
catch (InvalidOperationException ex)
{
return BadRequest(new ErrorResponseDto { Error = ex.Message });
}
catch (Exception ex)
{
_logger.Error($"Error deleting robot model {id}: {ex.Message}");
return StatusCode(500, new ErrorResponseDto { Error = "An error occurred while deleting the robot model." });
}
}
private static RobotModelDto MapToDto(RobotModel model)
{
return new RobotModelDto
{
Id = model.Id,
ModelName = model.ModelName,
Length = model.Length,
Width = model.Width,
ImageWidth = model.ImageWidth,
ImageHeight = model.ImageHeight,
NavigationPointX = model.NavigationPointX,
NavigationPointY = model.NavigationPointY,
NavigationType = model.NavigationType,
VehicleTypeId = model.VehicleTypeId,
CreatedDate = model.CreatedDate,
UpdatedDate = model.UpdatedDate,
RobotCount = model.Robots?.Count ?? 0
};
}
}

View File

@@ -0,0 +1,157 @@
using Microsoft.AspNetCore.Mvc;
using RobotNet10.FleetManager.Services;
using RobotNet10.FleetManager.Shared.DTOs.Responses;
namespace RobotNet10.FleetManager.Controllers;
/// <summary>
/// API controller for managing robot model images
/// </summary>
[ApiController]
[Route("api/robot-models/{robotModelId}/image")]
public class RobotModelImagesController(
IRobotModelImageStorageService imageStorageService,
IRobotModelService robotModelService,
Services.Logger<RobotModelImagesController> logger) : ControllerBase
{
private readonly IRobotModelImageStorageService _imageStorageService = imageStorageService;
private readonly IRobotModelService _robotModelService = robotModelService;
private readonly Services.Logger<RobotModelImagesController> _logger = logger;
private const long MaxFileSize = 10 * 1024 * 1024; // 10MB
/// <summary>
/// Get robot model image
/// </summary>
[HttpGet]
[ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> GetImage(Guid robotModelId)
{
try
{
// Verify robot model exists
var model = await _robotModelService.GetByIdAsync(robotModelId);
if (model == null)
{
return NotFound(new ErrorResponseDto { Error = $"Robot model with ID {robotModelId} not found." });
}
var imageStream = await _imageStorageService.GetImageAsync(robotModelId);
if (imageStream == null)
{
return NotFound(new ErrorResponseDto { Error = $"Image for robot model {robotModelId} not found." });
}
return File(imageStream, "image/png", $"{robotModelId}.png");
}
catch (Exception ex)
{
_logger.Error($"Error getting image for robot model {robotModelId}: {ex.Message}");
return StatusCode(500, new ErrorResponseDto { Error = "An error occurred while retrieving the image." });
}
}
/// <summary>
/// Upload robot model image
/// </summary>
[HttpPost]
[RequestSizeLimit(MaxFileSize)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> UploadImage(Guid robotModelId, IFormFile file)
{
try
{
// Verify robot model exists
var model = await _robotModelService.GetByIdAsync(robotModelId);
if (model == null)
{
return NotFound(new ErrorResponseDto { Error = $"Robot model with ID {robotModelId} not found." });
}
// Validate file
if (file == null || file.Length == 0)
{
return BadRequest(new ErrorResponseDto { Error = "No file provided." });
}
if (file.Length > MaxFileSize)
{
return BadRequest(new ErrorResponseDto { Error = $"File size exceeds maximum allowed size of {MaxFileSize / (1024 * 1024)}MB." });
}
// Validate file extension
var extension = Path.GetExtension(file.FileName).ToLowerInvariant();
if (extension != ".png")
{
return BadRequest(new ErrorResponseDto { Error = "Only PNG files are allowed." });
}
// Read image dimensions
using (var stream = file.OpenReadStream())
{
var (width, height) = await _imageStorageService.GetImageDimensionsAsync(stream);
// Save image
stream.Position = 0;
await _imageStorageService.SaveImageAsync(robotModelId, stream);
// Update robot model with image dimensions
await _robotModelService.UpdateAsync(robotModelId, new Shared.DTOs.RobotModel.UpdateRobotModelRequest
{
ImageWidth = width,
ImageHeight = height
});
}
return Ok(new { Error = "Image uploaded successfully." });
}
catch (InvalidOperationException ex)
{
return BadRequest(new ErrorResponseDto { Error = ex.Message });
}
catch (KeyNotFoundException ex)
{
return NotFound(new ErrorResponseDto { Error = ex.Message });
}
catch (Exception ex)
{
_logger.Error($"Error uploading image for robot model {robotModelId}: {ex.Message}");
return StatusCode(500, new ErrorResponseDto { Error = "An error occurred while uploading the image." });
}
}
/// <summary>
/// Delete robot model image
/// </summary>
[HttpDelete]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> DeleteImage(Guid robotModelId)
{
try
{
// Verify robot model exists
var model = await _robotModelService.GetByIdAsync(robotModelId);
if (model == null)
{
return NotFound(new ErrorResponseDto { Error = $"Robot model with ID {robotModelId} not found." });
}
var deleted = await _imageStorageService.DeleteImageAsync(robotModelId);
if (!deleted)
{
return NotFound(new ErrorResponseDto { Error = $"Image for robot model {robotModelId} not found." });
}
return NoContent();
}
catch (Exception ex)
{
_logger.Error($"Error deleting image for robot model {robotModelId}: {ex.Message}");
return StatusCode(500, new ErrorResponseDto { Error = "An error occurred while deleting the image." });
}
}
}