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;
///
/// Arac hatalarini istemcinin gorebilecegi mesaja cevirir. SDK cevrilmemis istisnayi
/// "An error occurred invoking" olarak iletir ve model neden reddedildigini bilemez. Yetki reddinde eksik yetkiler adiyla, is kurali hatasinda
/// () zaten yerellestirilmis mesaj iletilir. Diger istisnalar
/// cevrilmez: ic ayrinti (SQL, yigin) istemciye sizmaz.
///
public class McpToolErrorTranslator(
IPermissionChecker permissionChecker,
IStringLocalizer localizer) : ITransientDependency
{
public static bool CanTranslate(Exception exception)
=> exception is AbpAuthorizationException or UserFriendlyException;
public async Task TranslateAsync(Exception exception, string? toolName)
=> exception is AbpAuthorizationException authorization
? await DescribeMissingPermissionsAsync(authorization, toolName)
: exception.Message;
///
/// CheckAsync("...") reddi yetki adini tasir; [Authorize] attribute'u tasimaz. Ikinci
/// durumda aracin adi bilinen yetkileri kullanicinin yetkileriyle karsilastirilir.
///
private async Task DescribeMissingPermissionsAsync(AbpAuthorizationException exception, string? toolName)
{
var candidates = new List(McpToolNames.KnownPermissionsOf(toolName));
if (exception.Data["PolicyName"] is string policyName && !string.IsNullOrWhiteSpace(policyName))
{
candidates.Add(policyName);
}
var grants = await permissionChecker.IsGrantedAsync([.. candidates.Distinct(StringComparer.Ordinal)]);
var missing = grants.Result
.Where(result => result.Value != PermissionGrantResult.Granted)
.Select(result => Describe(result.Key))
.ToList();
var target = toolName ?? McpConsts.EndpointPath;
return missing.Count == 0
? localizer[McpErrorCodes.PermissionDeniedUnspecified, target]
: localizer[McpErrorCodes.PermissionDenied, target, string.Join(", ", missing)];
}
/// Yetkinin gorunen adi ve kodu; rol ekraninda aranabilsin diye kod her zaman yazilir.
private string Describe(string permissionName)
{
var displayName = localizer[permissionName];
return displayName.ResourceNotFound || displayName.Value == permissionName
? permissionName
: $"{displayName.Value} ({permissionName})";
}
}