AdoS8ConfigAlertRulesController.cs 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. using Admin.NET.Plugin.AiDOP.Infrastructure.S8;
  2. using Admin.NET.Plugin.AiDOP.Const.S8;
  3. using Admin.NET.Plugin.AiDOP.Entity.S8;
  4. using Admin.NET.Plugin.AiDOP.Infrastructure;
  5. using Admin.NET.Plugin.AiDOP.Service.S8;
  6. namespace Admin.NET.Plugin.AiDOP.Controllers.S8;
  7. [ApiController]
  8. [Route("api/aidop/s8/config/alert-rules")]
  9. [NonUnify]
  10. public class AdoS8ConfigAlertRulesController : ControllerBase
  11. {
  12. // 写能力已永久退役:不得为了构造一个不会被使用的 scope 而读取组织库。
  13. // Service 写方法必须在读取该占位值或访问任何仓储前抛 S8WriteRetiredException。
  14. private static readonly S8TrustedScope RetiredWriteScope = new(0, 0);
  15. private readonly S8AlertRuleService _svc;
  16. private readonly S8TrustedScopeResolver _scope;
  17. public AdoS8ConfigAlertRulesController(S8AlertRuleService svc, S8TrustedScopeResolver scope)
  18. {
  19. _svc = svc;
  20. _scope = scope;
  21. }
  22. [HttpGet]
  23. [S8Permission(S8PermissionCatalog.ConfigRead)]
  24. public async Task<IActionResult> ListAsync([FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1)
  25. {
  26. // Compatibility-only. Security scope is resolved server-side.
  27. _ = tenantId; _ = factoryId;
  28. var scope = await _scope.ResolveAsync();
  29. return Ok(await _svc.ListAsync(scope.TenantId, scope.FactoryId));
  30. }
  31. // ================================================================================
  32. // S8-STEP6D-CFG-ALERT-LEGACY-WRITE-GUARD-CERT-1:POST / PUT / DELETE 已退役 → 410 Gone。
  33. //
  34. // 410 而非 400/403/404 是刻意选择:语义为「该能力曾经存在、现已永久退役」。
  35. // 400 会暗示「改对入参还能存」,404 会暗示「换个 Id 还能存」,都与事实不符。
  36. //
  37. // ⚠️ catch 顺序:S8WriteRetiredException 必须排在 S8NotFoundException / S8BizException 之前,
  38. // 否则会被基类分支先接住、降级成 404/400。
  39. // 返回固定文案常量(不是 ex.ToString()/堆栈/类型名),避免泄漏内部实现。
  40. // GET 保持不变,历史兼容数据仍可读。
  41. // ================================================================================
  42. private IActionResult Retired() =>
  43. StatusCode(Microsoft.AspNetCore.Http.StatusCodes.Status410Gone,
  44. new { message = S8WriteRetiredException.UserMessage });
  45. [HttpPost]
  46. [S8Permission(S8PermissionCatalog.ConfigWatchRule)]
  47. public async Task<IActionResult> CreateAsync([FromBody] AdoS8AlertRule body)
  48. {
  49. try { return Ok(await _svc.CreateAsync(body, RetiredWriteScope)); }
  50. catch (S8WriteRetiredException) { return Retired(); }
  51. catch (S8NotFoundException) { return NotFound(); }
  52. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  53. }
  54. [HttpPut("{id:long}")]
  55. [S8Permission(S8PermissionCatalog.ConfigWatchRule)]
  56. public async Task<IActionResult> UpdateAsync(long id, [FromBody] AdoS8AlertRule body)
  57. {
  58. try { return Ok(await _svc.UpdateAsync(id, body, RetiredWriteScope)); }
  59. catch (S8WriteRetiredException) { return Retired(); }
  60. catch (S8NotFoundException) { return NotFound(); }
  61. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  62. }
  63. [HttpDelete("{id:long}")]
  64. [S8Permission(S8PermissionCatalog.ConfigWatchRule)]
  65. public async Task<IActionResult> DeleteAsync(long id)
  66. {
  67. try { await _svc.DeleteAsync(id, RetiredWriteScope); }
  68. catch (S8WriteRetiredException) { return Retired(); }
  69. catch (S8NotFoundException) { return NotFound(); }
  70. return Ok();
  71. }
  72. }