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,189 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using RobotNet10.MapEditor.Shared.DTOs.Node;
using RobotNet10.MapEditor.Shared.DTOs.Requests;
using RobotNet10.MapEditor.Shared.DTOs.Responses;
using RobotNet10.MapEditor.Shared.DTOs.Station;
using RobotNet10.MapManager.Services;
namespace RobotNet10.MapManager.Controllers;
/// <summary>
/// Controller for managing stations
/// </summary>
[ApiController]
[Route("api/stations")]
[Authorize]
public class StationsController(
IStationService stationService,
ILogger<StationsController> logger) : ControllerBase
{
private readonly IStationService _stationService = stationService;
private readonly ILogger<StationsController> _logger = logger;
/// <summary>
/// Create a new station
/// </summary>
/// <param name="request">Station creation request</param>
/// <returns>Created station</returns>
[HttpPost]
[ProducesResponseType(typeof(StationDto), 201)]
[ProducesResponseType(400)]
public async Task<ActionResult<StationDto>> CreateStation([FromBody] CreateStationRequest request)
{
try
{
var station = await _stationService.CreateAsync(request);
var dto = MapToDto(station);
return CreatedAtAction(
nameof(GetStation),
new { stationId = station.Id },
dto);
}
catch (InvalidOperationException ex)
{
_logger.LogWarning(ex, "Failed to create station: {StationId}", request.StationId);
return BadRequest(CreateErrorResponse(ex.Message, "VALIDATION_ERROR"));
}
}
/// <summary>
/// Get all stations for a layout level
/// </summary>
/// <param name="layoutLevelId">Layout level ID</param>
/// <returns>List of stations with interaction nodes</returns>
[HttpGet("level/{layoutLevelId}")]
[ProducesResponseType(typeof(List<StationDto>), 200)]
public async Task<ActionResult<List<StationDto>>> GetStationsByLevel(Guid layoutLevelId)
{
var stations = await _stationService.GetStationsByLevelAsync(layoutLevelId, includeInteractionNodes: true);
var dtos = stations.Select(MapToDto).ToList();
return Ok(dtos);
}
/// <summary>
/// Get station by ID
/// </summary>
/// <param name="stationId">Station database ID</param>
/// <returns>Station details with interaction nodes</returns>
[HttpGet("{stationId}")]
[ProducesResponseType(typeof(StationDto), 200)]
[ProducesResponseType(404)]
public async Task<ActionResult<StationDto>> GetStation(Guid stationId)
{
var station = await _stationService.GetByIdAsync(stationId, includeInteractionNodes: true);
if (station == null)
{
return NotFound(CreateErrorResponse($"Station with ID '{stationId}' not found", "STATION_NOT_FOUND"));
}
return Ok(MapToDto(station));
}
/// <summary>
/// Update station
/// </summary>
/// <param name="stationId">Station database ID</param>
/// <param name="request">Update request</param>
/// <returns>Updated station</returns>
[HttpPut("{stationId}")]
[ProducesResponseType(typeof(StationDto), 200)]
[ProducesResponseType(400)]
[ProducesResponseType(404)]
public async Task<ActionResult<StationDto>> UpdateStation(
Guid stationId,
[FromBody] UpdateStationRequest request)
{
try
{
var station = await _stationService.UpdateAsync(stationId, request);
return Ok(MapToDto(station));
}
catch (InvalidOperationException ex)
{
if (_logger.IsEnabled(LogLevel.Warning)) _logger.LogWarning(ex, "Failed to update station: {StationId}", stationId);
if (ex.Message.Contains("not found"))
return NotFound(CreateErrorResponse(ex.Message, "STATION_NOT_FOUND"));
return BadRequest(CreateErrorResponse(ex.Message, "VALIDATION_ERROR"));
}
}
/// <summary>
/// Delete station
/// Deletes station and cascade deletes interaction nodes (but NOT the linked nodes)
/// </summary>
/// <param name="stationId">Station database ID</param>
/// <returns>No content on success</returns>
[HttpDelete("{stationId}")]
[ProducesResponseType(204)]
[ProducesResponseType(404)]
public async Task<IActionResult> DeleteStation(Guid stationId)
{
var deleted = await _stationService.DeleteAsync(stationId);
if (!deleted)
{
return NotFound(CreateErrorResponse($"Station with ID '{stationId}' not found", "STATION_NOT_FOUND"));
}
return NoContent();
}
// Helper method to map entity to DTO
private static StationDto MapToDto(Data.Station station)
{
return new StationDto
{
Id = station.Id,
LevelId = station.LevelId,
StationId = station.StationId,
StationName = station.StationName,
StationDescription = station.StationDescription,
StationHeight = station.StationHeight,
X = station.X,
Y = station.Y,
Theta = station.Theta,
InteractionNodes = station.InteractionNodes?.Select(sin => new StationInteractionNodeDto
{
Id = sin.Id,
StationId = sin.StationId,
NodeId = sin.NodeId,
Node = sin.Node != null ? new NodeDto
{
Id = sin.Node.Id,
NodeId = sin.Node.NodeId,
NodeName = sin.Node.NodeName,
X = sin.Node.X,
Y = sin.Node.Y,
VehicleProperties = sin.Node.VehicleProperties?.Select(vp => new NodeVehiclePropertyDto
{
Id = vp.Id,
VehicleTypeId = vp.VehicleTypeId,
Theta = vp.Theta,
Actions = vp.Actions
}).ToList()
} : null
}).ToList()
};
}
private static ErrorResponseDto CreateErrorResponse(
string error,
string? errorCode = null,
Dictionary<string, object>? details = null)
{
return new ErrorResponseDto
{
Error = error,
ErrorCode = errorCode,
Details = details
};
}
}