- DrawingsController: rename 'name/{name}' to 'by-name/{name}' to
eliminate ambiguous match with '{name}/dxf' on path /drawings/name/dxf
- NestsController: add regex constraint to '{nestName}/download' and
'{nestName}/plates' to prevent collision with year-parameterized routes
when nestName is a 4-digit integer
- PepMcp/PepTools.cs: update GetDrawingByName URL to match renamed route
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
269 lines
9.2 KiB
C#
269 lines
9.2 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Options;
|
|
using PepApi.Core.Configuration;
|
|
using PepApi.Core.Models;
|
|
using PepLib.Data;
|
|
using PepLib.IO;
|
|
|
|
namespace PepApi.Core.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("drawings")]
|
|
public class DrawingsController : ControllerBase
|
|
{
|
|
private readonly PepDB _db;
|
|
private readonly PepSettings _settings;
|
|
|
|
public DrawingsController(PepDB db, IOptions<PepSettings> settings)
|
|
{
|
|
_db = db;
|
|
_settings = settings.Value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a list of drawings with optional filtering.
|
|
/// </summary>
|
|
[HttpGet]
|
|
public async Task<ActionResult<List<DrawingSummary>>> GetDrawings([FromQuery] DrawingFilterData? filter)
|
|
{
|
|
var drawings = await _db.Drawings
|
|
.Select(d => new DrawingSummary
|
|
{
|
|
ID = d.ID,
|
|
Name = d.Name,
|
|
Customer = d.Customer,
|
|
CustID = d.CustID,
|
|
Revision = d.Revision,
|
|
Description = d.Description,
|
|
Material = d.Material,
|
|
MaterialGrade = d.MatGrade,
|
|
Status = d.Status,
|
|
Type = d.Type,
|
|
Application = d.Application,
|
|
Programmer = d.Programmer,
|
|
CreatedBy = d.CreatedBy,
|
|
Width = d.Width,
|
|
Length = d.Length,
|
|
TrueArea = d.TrueArea,
|
|
CutLength = d.CutLength,
|
|
CreationDate = d.CreationDate,
|
|
LastEditDate = d.LastEditDate,
|
|
ModifiedDate = d.ModifiedDate,
|
|
HasBevel = d.HasBevel != 0,
|
|
HasLeadIn = d.HasLeadIn != 0,
|
|
HasTab = d.HasTab != 0
|
|
})
|
|
.ToListAsync();
|
|
|
|
if (filter != null)
|
|
{
|
|
var filtered = filter.Apply(drawings.AsQueryable()).ToList();
|
|
var paginated = filtered.Skip(filter.Offset).Take(filter.Limit).ToList();
|
|
return Ok(paginated);
|
|
}
|
|
|
|
return Ok(drawings.Take(100).ToList());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a drawing by ID.
|
|
/// </summary>
|
|
[HttpGet("{id:int}")]
|
|
public async Task<ActionResult<DrawingDetails>> GetDrawingById(int id)
|
|
{
|
|
var drawing = await _db.Drawings
|
|
.Where(d => d.ID == id)
|
|
.FirstOrDefaultAsync();
|
|
|
|
if (drawing == null)
|
|
return NotFound(new { message = "Drawing not found" });
|
|
|
|
return Ok(ConvertToDetails(drawing));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a drawing by exact name.
|
|
/// </summary>
|
|
[HttpGet("by-name/{name}")]
|
|
public async Task<ActionResult<DrawingDetails>> GetDrawingByName(string name)
|
|
{
|
|
var drawing = await _db.Drawings
|
|
.Where(d => d.Name.ToUpper() == name.ToUpper())
|
|
.FirstOrDefaultAsync();
|
|
|
|
if (drawing == null)
|
|
return NotFound(new { message = "Drawing not found" });
|
|
|
|
return Ok(ConvertToDetails(drawing));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Search drawings by partial name.
|
|
/// </summary>
|
|
[HttpGet("search")]
|
|
public async Task<ActionResult<DrawingSearchResponse>> SearchDrawings(
|
|
[FromQuery] string search,
|
|
[FromQuery] int limit = 100)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(search))
|
|
return BadRequest(new { message = "Search term is required" });
|
|
|
|
var searchUpper = search.Trim().ToUpper();
|
|
|
|
var allMatches = await _db.Drawings
|
|
.Where(d => d.Name.ToUpper().Contains(searchUpper))
|
|
.Select(d => new DrawingSummary
|
|
{
|
|
ID = d.ID,
|
|
Name = d.Name,
|
|
Customer = d.Customer,
|
|
CustID = d.CustID,
|
|
Revision = d.Revision,
|
|
Description = d.Description,
|
|
Material = d.Material,
|
|
MaterialGrade = d.MatGrade,
|
|
Status = d.Status,
|
|
Type = d.Type,
|
|
Application = d.Application,
|
|
Programmer = d.Programmer,
|
|
CreatedBy = d.CreatedBy,
|
|
Width = d.Width,
|
|
Length = d.Length,
|
|
TrueArea = d.TrueArea,
|
|
CutLength = d.CutLength,
|
|
CreationDate = d.CreationDate,
|
|
LastEditDate = d.LastEditDate,
|
|
ModifiedDate = d.ModifiedDate,
|
|
HasBevel = d.HasBevel != 0,
|
|
HasLeadIn = d.HasLeadIn != 0,
|
|
HasTab = d.HasTab != 0
|
|
})
|
|
.ToListAsync();
|
|
|
|
var limitedResults = limit > 0 ? allMatches.Take(limit).ToList() : allMatches;
|
|
|
|
return Ok(new DrawingSearchResponse
|
|
{
|
|
SearchTerm = search,
|
|
TotalMatches = allMatches.Count,
|
|
ResultsReturned = limitedResults.Count,
|
|
Results = limitedResults
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Export a drawing as a DXF file.
|
|
/// </summary>
|
|
[HttpGet("{name}/dxf")]
|
|
public async Task<IActionResult> GetDrawingDxf(string name)
|
|
{
|
|
var drawing = await _db.Drawings
|
|
.Where(d => d.Name.ToUpper() == name.ToUpper())
|
|
.FirstOrDefaultAsync();
|
|
|
|
if (drawing == null)
|
|
return NotFound(new { message = "Drawing not found in database" });
|
|
|
|
if (string.IsNullOrEmpty(_settings.DrawingsDirectory))
|
|
return StatusCode(503, new { message = "DrawingsDirectory is not configured" });
|
|
|
|
var filePath = Path.Combine(_settings.DrawingsDirectory, drawing.File);
|
|
|
|
if (!System.IO.File.Exists(filePath))
|
|
return NotFound(new { message = $"Drawing file not found: {drawing.File}" });
|
|
|
|
PepLib.Models.Drawing pep;
|
|
try
|
|
{
|
|
pep = PepLib.Models.Drawing.Load(filePath);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return StatusCode(500, new { message = $"Failed to load drawing: {ex.Message}" });
|
|
}
|
|
|
|
var stream = DrawingDxfExporter.Export(pep);
|
|
return File(stream, "application/dxf", $"{name}.dxf");
|
|
}
|
|
|
|
private static DrawingDetails ConvertToDetails(Drawing drawing)
|
|
{
|
|
return new DrawingDetails
|
|
{
|
|
ID = drawing.ID,
|
|
Name = drawing.Name,
|
|
CustID = drawing.CustID,
|
|
Revision = drawing.Revision,
|
|
Path = drawing.Path,
|
|
File = drawing.File,
|
|
InUseBy = drawing.InUseBy,
|
|
InUseDate = drawing.InUseDate,
|
|
Status = drawing.Status,
|
|
StatusModifiedBy = drawing.StatusModifiedBy,
|
|
StatusModifiedDate = drawing.StatusModifiedDate,
|
|
CreationDate = drawing.CreationDate,
|
|
LastEditDate = drawing.LastEditDate,
|
|
LastRefDate = drawing.LastRefDate,
|
|
Description = drawing.Description,
|
|
Customer = drawing.Customer,
|
|
Comment = drawing.Comment,
|
|
Notes = drawing.Notes,
|
|
Grain = drawing.Grain,
|
|
GrainAngle = drawing.GrainAngle,
|
|
Material = drawing.Material,
|
|
MaterialGrade = drawing.MatGrade,
|
|
Programmer = drawing.Programmer,
|
|
CreatedBy = drawing.CreatedBy,
|
|
Type = drawing.Type,
|
|
CommonCut = drawing.CommonCut,
|
|
CombineCut = drawing.CombineCut,
|
|
Errors = drawing.Errors,
|
|
Hardness = drawing.Hardness,
|
|
Specification = drawing.Specification,
|
|
NestInCutOuts = drawing.NestInCutOuts,
|
|
UserDefined1 = drawing.UserDefined1,
|
|
UserDefined2 = drawing.UserDefined2,
|
|
UserDefined3 = drawing.UserDefined3,
|
|
UserDefined4 = drawing.UserDefined4,
|
|
UserDefined5 = drawing.UserDefined5,
|
|
UserDefined6 = drawing.UserDefined6,
|
|
Machine = drawing.Machine,
|
|
Application = drawing.Application,
|
|
PartCount = drawing.PartCount,
|
|
Color = drawing.Color,
|
|
CombineMethod = drawing.CombineMethod,
|
|
SeqCutouts = drawing.SeqCutouts,
|
|
AllowMirror = drawing.AllowMirror,
|
|
SourceFile = drawing.SourceFile,
|
|
SourceDate = drawing.SourceDate,
|
|
SourceSize = drawing.SourceSize,
|
|
CadScaled = drawing.CadScaled,
|
|
CadDimVerified = drawing.CadDimVerified,
|
|
CadDimCount = drawing.CadDimCount,
|
|
Width = drawing.Width,
|
|
Length = drawing.Length,
|
|
RectArea = drawing.RectArea,
|
|
ExtArea = drawing.ExtArea,
|
|
TrueArea = drawing.TrueArea,
|
|
ExtUtil = drawing.ExtUtil,
|
|
TrueUtil = drawing.TrueUtil,
|
|
SmallestAreaAng = drawing.SmallestAreaAng,
|
|
SmallestAreaLen = drawing.SmallestAreaLen,
|
|
SmallestAreaWid = drawing.SmallestAreaWid,
|
|
SmallestYAng = drawing.SmallestYAng,
|
|
SmallestYLen = drawing.SmallestYLen,
|
|
SmallestYWid = drawing.SmallestYWid,
|
|
CutLength = drawing.CutLength,
|
|
ScribeLength = drawing.ScribeLength,
|
|
Checked = drawing.Checked,
|
|
PepBendStatus = drawing.PepBendStatus,
|
|
HasBevel = drawing.HasBevel != 0,
|
|
HasLeadIn = drawing.HasLeadIn != 0,
|
|
HasTab = drawing.HasTab != 0,
|
|
ModifiedDate = drawing.ModifiedDate,
|
|
ModifiedBy = drawing.ModifiedBy
|
|
};
|
|
}
|
|
}
|