Files
2026-10-18 20:36:40 +08:00

157 lines
4.5 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Text.RegularExpressions;
namespace OrderSupportTicket.TestServer;
/// <summary>
/// 与客户端 OrderSupportTicket.Services.TicketApiService 保持一致的参数规则。
/// </summary>
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<string> 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);
}