using Sozsoft.Platform.Domain.DeveloperKit; using Sozsoft.Platform.Entities; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.Text.Json; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Application.Services; using Volo.Abp.Domain.Repositories; namespace Sozsoft.Platform.Application; [RemoteService] [Route("api/app/crudendpoint")] public class CrudEndpointAppService : ApplicationService { private readonly IRepository _endpointRepository; private readonly IDynamicEntityManager _dynamicManager; public CrudEndpointAppService( IRepository endpointRepository, IDynamicEntityManager dynamicManager) { _endpointRepository = endpointRepository; _dynamicManager = dynamicManager; } /// /// Every query string entry that is not a paging parameter is a column filter: /// ?RoleId=… compares for equality, ?Name.contains=… applies the /// named operator. The column names are validated against the table schema in /// the manager, so an unknown column fails loudly instead of returning the /// unfiltered collection. /// [HttpGet("{entityName}")] public async Task?> GetEntityListAsync(string entityName) { await EnsureEndpointAsync(entityName, "GET", "GetList"); return await _dynamicManager.GetEntityListAsync(entityName, ReadQueryFilters()); } /// /// Route values are not filters, so only the query string is read. A repeated /// parameter keeps its comma joined form, which is what the in operator /// expects. /// private Dictionary ReadQueryFilters() { var filters = new Dictionary(StringComparer.OrdinalIgnoreCase); var query = LazyServiceProvider.LazyGetService()?.HttpContext?.Request?.Query; if (query == null) return filters; foreach (var entry in query) filters[entry.Key] = string.Join(",", entry.Value.ToArray()); return filters; } [HttpGet("{entityName}/{id}")] public async Task GetEntityByIdAsync(string entityName, Guid id) { await EnsureEndpointAsync(entityName, "GET", "GetById"); return await _dynamicManager.GetEntityByIdAsync(entityName, id); } [HttpPost("{entityName}")] public async Task CreateEntityAsync(string entityName, [FromBody] JsonElement data) { await EnsureEndpointAsync(entityName, "POST", "Create"); return await _dynamicManager.CreateEntityAsync(entityName, data); } [HttpPut("{entityName}/{id}")] public async Task UpdateEntityAsync(string entityName, Guid id, [FromBody] JsonElement data) { await EnsureEndpointAsync(entityName, "PUT", "Update"); return await _dynamicManager.UpdateEntityAsync(entityName, id, data); } [HttpDelete("{entityName}/{id}")] public async Task DeleteEntityAsync(string entityName, Guid id) { await EnsureEndpointAsync(entityName, "DELETE", "Delete"); return await _dynamicManager.DeleteEntityAsync(entityName, id); } private async Task EnsureEndpointAsync(string entityName, string method, string operation) { var exists = await _endpointRepository.AnyAsync(x => x.EntityName.ToLower() == entityName.ToLower() && x.Method == method && x.OperationType == operation && x.IsActive); if (!exists) throw new UserFriendlyException($"No active endpoint defined for {entityName} {operation}"); } }