fix: resolve API route name collisions

- 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>
This commit is contained in:
aj
2026-06-27 07:20:53 -04:00
co-authored by Claude Sonnet 4.6
parent 9fcc9df209
commit 5e0856b5d1
3 changed files with 43 additions and 10 deletions
+31 -5
View File
@@ -101,7 +101,7 @@ public class NestsController : ControllerBase
return File(bytes, mimeType, fileName);
}
[HttpGet("{nestName}/download")]
[HttpGet("{nestName:regex(^(?!\\d{{4}}$).+)}/download")]
public async Task<IActionResult> DownloadFile(string nestName)
{
var filePath = await GetNestPathAsync(nestName);
@@ -131,7 +131,7 @@ public class NestsController : ControllerBase
return Ok(combined);
}
[HttpGet("{nestName}/plates")]
[HttpGet("{nestName:regex(^(?!\\d{{4}}$).+)}/plates")]
public async Task<ActionResult<List<Plate>>> GetPlates(string nestName)
{
var nestFile = await GetNestPathAsync(nestName);
@@ -346,13 +346,22 @@ public class NestsController : ControllerBase
var pepPath = Path.Combine(_nestDirectory, nestName + ".pep");
if (System.IO.File.Exists(pepPath))
return pepPath;
var pepMatch = FindFileByPrefix(_nestDirectory, nestName, ".pep");
if (pepMatch != null)
return pepMatch;
}
// Older nests use .zip in year subdirectory
var zipPath = Path.Combine(_nestDirectory, year.Value.ToString(), nestName + ".zip");
var yearDir = Path.Combine(_nestDirectory, year.Value.ToString());
var zipPath = Path.Combine(yearDir, nestName + ".zip");
if (System.IO.File.Exists(zipPath))
return zipPath;
var zipMatch = FindFileByPrefix(yearDir, nestName, ".zip");
if (zipMatch != null)
return zipMatch;
return null;
}
@@ -361,25 +370,42 @@ public class NestsController : ControllerBase
if (System.IO.File.Exists(flatPepPath))
return flatPepPath;
var flatPepMatch = FindFileByPrefix(_nestDirectory, nestName, ".pep");
if (flatPepMatch != null)
return flatPepMatch;
// Fall back to year-based directory lookup for older nests
var upperName = nestName.ToUpper();
var nestHeader = await _db.NestHeaders
.Where(n => n.NestName.ToUpper() == nestName.ToUpper() && n.DateProgrammed != null)
.Where(n => (n.NestName.ToUpper() == upperName || n.NestName.ToUpper().StartsWith(upperName + "-"))
&& n.DateProgrammed != null)
.OrderByDescending(n => n.DateProgrammed)
.FirstOrDefaultAsync();
if (nestHeader == null)
return null;
var fullName = nestHeader.NestName;
var dbYear = nestHeader.DateProgrammed!.Value.Year;
// Older nests used .zip extension
var yearZipPath = Path.Combine(_nestDirectory, dbYear.ToString(), nestName + ".zip");
var yearZipPath = Path.Combine(_nestDirectory, dbYear.ToString(), fullName + ".zip");
if (System.IO.File.Exists(yearZipPath))
return yearZipPath;
return null;
}
private static string? FindFileByPrefix(string directory, string prefix, string extension)
{
if (!Directory.Exists(directory))
return null;
var pattern = prefix + "-*" + extension;
var matches = Directory.GetFiles(directory, pattern);
return matches.Length > 0 ? matches.Order().First() : null;
}
private async Task<NestDetails> GetNestDetailsAsync(string nestFilePath)
{
var nest = Nest.Load(nestFilePath);