using System.Text.RegularExpressions; namespace OrderSupportTicket.TestServer; /// /// 与客户端 OrderSupportTicket.Services.TicketApiService 保持一致的参数规则。 /// public static class ContractValidator { private static readonly Regex AppIdRegex = new(@"^wx[0-9a-f]{16}$", RegexOptions.Compiled | RegexOptions.CultureInvariant); private static readonly Regex OrderIdRegex = new(@"^[0-9]{10,64}$", RegexOptions.Compiled | RegexOptions.CultureInvariant); private static readonly Regex PurchaseAccountRegex = new(@"^[\p{L}\p{N}_.@-]{2,120}$", RegexOptions.Compiled); private static readonly Regex OperationIdRegex = new(@"^[A-Za-z0-9_.:-]{1,128}$", RegexOptions.Compiled | RegexOptions.CultureInvariant); private static readonly HashSet Statuses = new(StringComparer.OrdinalIgnoreCase) { "waiting_reply", "replied", "completed" }; public static string PurchaseAccount(string? value) { var normalized = value?.Trim(); if (string.IsNullOrWhiteSpace(normalized) || !PurchaseAccountRegex.IsMatch(normalized)) { throw BadRequest( "purchaseAccount 必填,且只能为 2~120 位中英文、数字或 _.@-。", "invalid_purchase_account"); } return normalized; } public static string AppId(string? value) { var normalized = value?.Trim(); if (string.IsNullOrWhiteSpace(normalized) || !AppIdRegex.IsMatch(normalized)) { throw BadRequest( "appId 必须为 wx 加 16 位小写十六进制字符。", "invalid_app_id"); } return normalized; } public static string WechatOrderId(string? value) { var normalized = value?.Trim(); if (string.IsNullOrWhiteSpace(normalized) || !OrderIdRegex.IsMatch(normalized)) { throw BadRequest( "wechatOrderId 必须保持为 10~64 位数字字符串。", "invalid_wechat_order_id"); } return normalized; } public static string Description(string? value) { var normalized = value?.Trim(); if (string.IsNullOrWhiteSpace(normalized) || normalized.Length > 2000) { throw BadRequest( "description 必须为 1~2000 字。", "invalid_description"); } return normalized; } public static string MessageText(string? value) { var normalized = value?.Trim(); if (string.IsNullOrWhiteSpace(normalized) || normalized.Length > 4000) { throw BadRequest( "text 必须为 1~4000 字。", "invalid_message_text"); } return normalized; } public static string? OptionalOperationId(string? value, string parameterName) { if (string.IsNullOrWhiteSpace(value)) { return null; } return OperationId(value, parameterName); } public static string OperationId(string? value, string parameterName) { var normalized = value?.Trim(); if (string.IsNullOrWhiteSpace(normalized) || !OperationIdRegex.IsMatch(normalized)) { throw BadRequest( parameterName + " 必须为 1~128 位字母、数字或 _.:-。", "invalid_operation_id"); } return normalized; } public static string? Status(string? value) { if (string.IsNullOrWhiteSpace(value)) { return null; } var normalized = value.Trim().ToLowerInvariant(); if (!Statuses.Contains(normalized)) { throw BadRequest( "status 只能为 waiting_reply、replied 或 completed。", "invalid_status"); } return normalized; } public static int Limit(int value, int fallback) { if (value == 0) { value = fallback; } if (value is < 1 or > 100) { throw BadRequest("limit 必须为 1~100。", "invalid_limit"); } return value; } public static ApiException BadRequest(string message, string code) => new(StatusCodes.Status400BadRequest, message, code); public static ApiException NotFound(string message, string code = "work_order_not_found") => new(StatusCodes.Status404NotFound, message, code); }