sozsoft-platform/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.HttpApi/McpToolErrorTranslator.cs
2026-10-17 21:51:10 +03:00

59 lines
2.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Localization;
using Sozsoft.Platform.Localization;
using Volo.Abp;
using Volo.Abp.Authorization;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.DependencyInjection;
namespace Sozsoft.Mcp;
/// <summary>
/// Aracin arkasindaki platform servislerinden (wizard, custom component, ListForm verisi) ve sinif
/// duzeyindeki <c>[Authorize]</c>'dan gelen istisnalari istemcinin gorebilecegi mesaja cevirir. MCP'nin
/// kendi reddi istisna degildir, <see cref="McpProblem"/> olarak doner. SDK cevrilmemis istisnayi
/// "An error occurred invoking" olarak iletir ve model neden reddedildigini bilemez. Yetki reddinde
/// eksik yetkiler adiyla, is kurali hatasinda (<see cref="UserFriendlyException"/>) zaten
/// yerellestirilmis mesaj iletilir. Diger istisnalar cevrilmez: ic ayrinti (SQL, yigin) istemciye sizmaz.
/// </summary>
public class McpToolErrorTranslator(
IPermissionChecker permissionChecker,
IStringLocalizer<PlatformResource> localizer) : ITransientDependency
{
public static bool CanTranslate(Exception exception)
=> exception is AbpAuthorizationException or UserFriendlyException;
public async Task<string> TranslateAsync(Exception exception, string? toolName)
=> exception is AbpAuthorizationException authorization
? await DescribeMissingPermissionsAsync(authorization, toolName)
: exception.Message;
/// <summary>
/// <c>CheckAsync("...")</c> reddi yetki adini tasir; <c>[Authorize]</c> attribute'u tasimaz. Ikinci
/// durumda aracin adi bilinen yetkileri kullanicinin yetkileriyle karsilastirilir.
/// </summary>
private async Task<string> DescribeMissingPermissionsAsync(AbpAuthorizationException exception, string? toolName)
{
var candidates = new List<string>(McpToolNames.KnownPermissionsOf(toolName));
if (exception.Data["PolicyName"] is string policyName && !string.IsNullOrWhiteSpace(policyName))
{
candidates.Add(policyName);
}
var granted = await permissionChecker.GetGrantedNamesAsync(candidates);
var missing = candidates
.Distinct(StringComparer.Ordinal)
.Where(permission => !granted.Contains(permission))
.Select(permission => McpPermissionText.Describe(localizer, permission))
.ToList();
var target = toolName ?? McpConsts.EndpointPath;
return missing.Count == 0
? localizer[McpErrorCodes.PermissionDeniedUnspecified, target]
: localizer[McpErrorCodes.PermissionDenied, target, string.Join(", ", missing)];
}
}