erp-platform/api/src/Kurs.Platform.Application/CustomEndpoints/CustomEndpointAppService.cs
2025-10-07 23:55:42 +03:00

278 lines
10 KiB
C#
Raw 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;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Kurs.Platform.DynamicData;
using Kurs.Platform.Entities;
using Kurs.Platform.Extensions;
using Kurs.Platform.Queries;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Tracing;
using Volo.Abp.Uow;
namespace Kurs.Platform.CustomEndpoints;
[Authorize]
[Route("api/app/custom-endpoint")]
public class CustomEndpointAppService : PlatformAppService
{
private readonly IRepository<CustomEndpoint, Guid> repo;
private readonly IHttpContextAccessor httpContextAccessor;
private readonly IDataSourceManager dataSourceManager;
private readonly IDynamicDataManager dynamicDataManager;
private readonly DefaultValueHelper defaultValueHelper;
public CustomEndpointAppService(
IRepository<CustomEndpoint, Guid> repo,
IHttpContextAccessor httpContextAccessor,
IDataSourceManager dataSourceManager,
IDynamicDataManager dynamicDataManager,
DefaultValueHelper defaultValueHelper)
{
this.repo = repo;
this.httpContextAccessor = httpContextAccessor;
this.dataSourceManager = dataSourceManager;
this.dynamicDataManager = dynamicDataManager;
this.defaultValueHelper = defaultValueHelper;
}
[HttpGet("{**path}")]
[Authorize(PlatformConsts.AppCodes.CustomEndpoints.Get)]
public async Task<IActionResult> GetAsync()
{
return await Execute("GET");
}
[HttpPost("{**path}")]
[Authorize(PlatformConsts.AppCodes.CustomEndpoints.Post)]
public async Task<IActionResult> PostAsync()
{
return await Execute("POST");
}
private async Task<IActionResult> Execute(string method)
{
using var uow = UnitOfWorkManager.Begin(new AbpUnitOfWorkOptions(false), true);
try
{
// Request.Path = /api/app/custom-endpoint/yxcdfn/8
var rawPath = httpContextAccessor.HttpContext.Request.Path.ToString();
var decodedPath = Uri.UnescapeDataString(rawPath); // URL decode işlemi
var path = decodedPath
.Replace("/api/app/custom-endpoint", "", StringComparison.OrdinalIgnoreCase)
.EnsureStartsWith('/')
.EnsureEndsWith('/');
Logger.LogInformation("Custom Endpoint çağrısı. Kullanıcı:{user} Path:[{method}]{path}", CurrentUser.UserName, "GET", path);
var api = await repo.FirstOrDefaultAsync(a => path.StartsWith(a.Url) && a.Method == method);
if (api is null)
{
Logger.LogInformation("Custom Endpoint bulunamadı");
return new NotFoundResult();
}
Logger.LogInformation("Custom Endpoint bulundu. {api}", api.Name);
var canUse = api.Permissions.Any(a =>
(a.ResourceType == "User" && a.ResourceId == CurrentUser.UserName) ||
(a.ResourceType == "Role" && CurrentUser.Roles.Contains(a.ResourceId)) ||
(a.ResourceType == "Global"));
if (!canUse)
{
Logger.LogWarning("Custom Endpoint yetki yok");
return new UnauthorizedResult();
}
Dictionary<string, object> param = [];
// Parametreler:
// 1- Statik
foreach (var item in api.Parameters.Where(a => a.Type == PlatformConsts.CustomEndpointConsts.ParameterTypes.Static))
{
var value = defaultValueHelper.GetDefaultValue(item.DefaultValue);
param.Add(item.Name, value);
}
// 2- Query
var queryParams = httpContextAccessor.HttpContext.Request.Query;
foreach (var item in api.Parameters.Where(a => a.Type == PlatformConsts.CustomEndpointConsts.ParameterTypes.Query))
{
if (queryParams.TryGetValue(item.Name, out var value))
{
param.Add(item.Name, value);
}
else
{
if (item.IsRequired)
{
throw new Volo.Abp.UserFriendlyException(L[PlatformConsts.AppErrorCodes.ParameterNotValid, item.Name]);
}
else
{
param.Add(item.Name, defaultValueHelper.GetDefaultValue(item.DefaultValue));
}
}
}
// 3- Path
foreach (var item in api.Parameters.Where(a => a.Type == PlatformConsts.CustomEndpointConsts.ParameterTypes.Path && !a.Path.IsNullOrWhiteSpace()))
{
var itemPath = item.Path.EnsureStartsWith('/').EnsureEndsWith('/');
var index = itemPath.IndexOf($"/:{item.Name}/");
if (index == -1)
{
throw new Volo.Abp.UserFriendlyException(L[PlatformConsts.AppErrorCodes.ParameterNotValid, item.Name]);
}
var segmentCount = itemPath[..(index + 1)].Count(a => a == '/');
var value = path.GetSegment('/', segmentCount);
param.Add(item.Name, value ?? defaultValueHelper.GetDefaultValue(item.DefaultValue));
}
// 4- Body
if (method == "POST")
{
var body = await httpContextAccessor.HttpContext.Request.ReadFormAsync();
foreach (var item in api.Parameters.Where(a => a.Type == PlatformConsts.CustomEndpointConsts.ParameterTypes.Body))
{
if (body.TryGetValue(item.Name, out var value))
{
param.Add(item.Name, value);
}
else
{
if (item.IsRequired)
{
throw new Volo.Abp.UserFriendlyException(L[PlatformConsts.AppErrorCodes.ParameterNotValid, item.Name]);
}
else
{
param.Add(item.Name, defaultValueHelper.GetDefaultValue(item.DefaultValue));
}
}
}
}
Logger.LogInformation("Parametreler: {param}", param);
var (dynamicDataRepository, connectionString, _) = await dynamicDataManager.GetAsync(api.DataSourceCode == "!Tenant", api.DataSourceCode);
var result = await dynamicDataRepository.QueryAsync(api.Sql, connectionString, param);
Logger.LogInformation("Sonuç başarılı");
Logger.LogInformation("{result}", result);
await uow.CompleteAsync();
return new ObjectResult(result);
}
catch (Volo.Abp.UserFriendlyException ex)
{
Logger.LogException(ex);
await uow.RollbackAsync();
return new JsonResult(new
{
Message = ex.Message,
CorrelationId = LazyServiceProvider.GetRequiredService<ICorrelationIdProvider>().Get(),
})
{
StatusCode = 500,
};
}
catch (Exception ex)
{
Logger.LogException(ex);
await uow.RollbackAsync();
return new JsonResult(new
{
Message = L[PlatformConsts.AppErrorCodes.InternalError].Value,
CorrelationId = LazyServiceProvider.GetRequiredService<ICorrelationIdProvider>().Get()
})
{
StatusCode = 500,
};
}
}
}
//TODO: Custom Endpoint rol, permission seed
/*
Token İsteği Örnek:
POST /connect/token HTTP/1.1
Host: localhost:44344
Content-Type: application/x-www-form-urlencoded
username=system%40sozsoft.com
&password=...
&grant_type=password
&client_id=Platform_PublicApi
&scope=offline_access%20Platform
Custom Endpoint Seed:
SELECT * FROM PLanguage WHERE IsEnabled = @IsEnabled AND CultureName = @CultureName
INSERT INTO [dbo].[Orders]
([CustomerName]
,[ProductName]
,[OrderDate]
,[Quantity])
OUTPUT Inserted.*
VALUES
(@CustomerName, @ProductName, @OrderDate, @Quantity)
SELECT * FROM Orders WHERE Id = SCOPE_IDENTITY()
[{ "Type": "S", "Name": "CultureName", "DefaultValue": "ar" }]
[{ "Type": "Q", "Name": "CultureName", "DefaultValue": "ar" }]
[
{ "Type": "P", "Name": "IsEnabled", "DefaultValue": "en", "Path": "/yxcdfn/8/:IsEnabled/:CultureName/" },
{ "Type": "P", "Name": "CultureName", "DefaultValue": "en", "Path": "/yxcdfn/8/:IsEnabled/:CultureName/" }
]
[
{ "Type": "B", "Name": "CustomerName", "DefaultValue": "" },
{ "Type": "B", "Name": "ProductName", "DefaultValue": "" },
{ "Type": "B", "Name": "OrderDate", "DefaultValue": "@NOW" },
{ "Type": "B", "Name": "Quantity", "DefaultValue": "" }
]
Guid? TenantId
string Name
string Description
string Url -> https://api.sozsoft.com/api/app/dinamik/yxfgu
string Method -> GET
string Params = [
{ Type: 'Static', Name: 'StartDate', DefaultValue: '234' },
{ Type: 'Query', Name: 'StartDate', DefaultValue: '', IsRequired: false },
{ Type: 'Path', Name: 'FaturaId', DefaultValue: '', Path: '/yxfgu/fatura/:FaturaId/kalem/357' },
{ Type: 'Path', Name: 'KalemId', DefaultValue: '', Path: '/yxfgu/fatura/xxx/kalem/:KalemId' },
{ Type: 'Body', Name: 'StartDate', DefaultValue: '' },
]
string Sql -> SELECT * FROM VSatislar WHERE MusteriId = @MusteriId AND StartDate >= @StartDate
string Permissions = [
{ ResourceType: 'User', ResourceId: 'system' },
{ ResourceType: 'User', ResourceId: 'sedat' },
]
Query Parameter
URL: https://api.sozsoft.com/api/app/dinamik/yxfgu
Method: GET
Parameters: ?StartDate=2024-12-31&EndDate=2025-12-31
Path Parameter
URL: https://api.sozsoft.com/api/app/dinamik/yxfgu/fatura/467/kalem/357
Method: GET
Parameters: FaturaId=467
Body Parameter
URL: https://api.sozsoft.com/api/app/dinamik/yxfgu?UrunId=5
Method: POST
Parameters: ?StartDate=2024-12-31&EndDate=2025-12-31
Body: { Tutar: 2000, Tarih: '2024-12-31' }
*/