Skip to content

Commit

Permalink
Refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
KrzysztofPajak committed Jan 1, 2025
1 parent 68790b9 commit a543137
Show file tree
Hide file tree
Showing 35 changed files with 241 additions and 753 deletions.
3 changes: 1 addition & 2 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,12 @@
<PackageVersion Include="FluentValidation" Version="11.11.0" />
<PackageVersion Include="Microsoft.AspNetCore.JsonPatch" Version="9.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="9.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.OData" Version="9.1.1" />
<PackageVersion Include="MongoDB.AspNetCore.OData" Version="1.1.0" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="7.2.0" />
<PackageVersion Include="Swashbuckle.AspNetCore.Annotations" Version="7.2.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.Facebook" Version="9.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.Google" Version="9.0.0" />
<PackageVersion Include="Braintree" Version="5.28.0" />
<PackageVersion Include="System.Linq.Dynamic.Core" Version="1.5.1" />
<PackageVersion Include="System.Xml.XPath.XmlDocument" Version="4.7.0" />
<PackageVersion Include="Stripe.net" Version="47.1.0" />
<PackageVersion Include="elFinder.Net.AspNetCore" Version="1.5.0" />
Expand Down
48 changes: 48 additions & 0 deletions src/Modules/Grand.Module.Api/Attributes/EnableQueryAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using System.Linq.Dynamic.Core;
using Microsoft.AspNetCore.Http;

namespace Grand.Module.Api.Attributes;

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class EnableQueryAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext context)
{
if (context.Result is not ObjectResult result || result.Value == null)
return;

if (result.Value is IQueryable queryable)
{
queryable = ApplyQueryOptions(queryable, context.HttpContext.Request.Query, context.HttpContext.Response);
result.Value = queryable;
}
}

private IQueryable ApplyQueryOptions(IQueryable queryable, IQueryCollection query, HttpResponse response)
{
if (query.TryGetValue("$filter", out var filter))
queryable = queryable.Where(filter.ToString());

if (query.TryGetValue("$orderby", out var orderBy))
queryable = queryable.OrderBy(orderBy.ToString());

if (query.TryGetValue("$select", out var select))
queryable = queryable.Select($"new({select})");

if (query.TryGetValue("$skip", out var skipValue) && int.TryParse(skipValue, out var skip))
queryable = queryable.Skip(skip);

if (query.TryGetValue("$top", out var topValue) && int.TryParse(topValue, out var top))
queryable = queryable.Take(top);

if (query.TryGetValue("$count", out var countValue) && bool.TryParse(countValue, out var includeCount) && includeCount)
{
var totalCount = queryable.Count();
response?.Headers?.Append("X-Total-Count", totalCount.ToString());
}

return queryable;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace Grand.Module.Api.Infrastructure;
namespace Grand.Module.Api.Attributes;

public class ModelValidationAttribute : ActionFilterAttribute
{
Expand Down
3 changes: 1 addition & 2 deletions src/Modules/Grand.Module.Api/Constants/Configurations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

public static class Configurations
{
public const string ODataRoutePrefix = "odata";
public const string ODataModelBuilderNamespace = "Default";
public const string RestRoutePrefix = "api";
public const string CorsPolicyName = "CorsPolicy";
public const int MaxLimit = 100;
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
using Grand.Module.Api.Filters;
using Grand.Module.Api.Infrastructure;
using Grand.Module.Api.Attributes;
using Grand.Module.Api.Filters;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Routing.Attributes;
using Microsoft.AspNetCore.OData.Routing.Controllers;

namespace Grand.Module.Api.Controllers;

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ODataRouteComponent]
[AuthorizeApiAdmin]
[ServiceFilter(typeof(ModelValidationAttribute))]
public abstract class BaseODataController : ODataController
[Produces("application/json")]
public abstract class BaseApiController : ControllerBase
{
public override ForbidResult Forbid()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@
using MediatR;
using Microsoft.AspNetCore.JsonPatch;
using Microsoft.AspNetCore.Mvc;
using MongoDB.AspNetCore.OData;
using Swashbuckle.AspNetCore.Annotations;
using System.Net;
using Grand.Module.Api.Constants;
using Microsoft.AspNetCore.Http;
using Grand.Module.Api.Attributes;

namespace Grand.Module.Api.Controllers.OData;
namespace Grand.Module.Api.Controllers;

[Route($"{Configurations.ODataRoutePrefix}/Brand")]
[Route($"{Configurations.RestRoutePrefix}/Brand")]
[ApiExplorerSettings(IgnoreApi = false, GroupName = "v1")]
public class BrandController : BaseODataController
public class BrandController : BaseApiController
{
private readonly IMediator _mediator;
private readonly IPermissionService _permissionService;
Expand All @@ -29,9 +30,9 @@ public BrandController(IMediator mediator, IPermissionService permissionService)

[SwaggerOperation("Get entities from Brand", OperationId = "GetBrands")]
[HttpGet]
[MongoEnableQuery]
[EnableQuery]
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
[ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<BrandDto>))]
public async Task<IActionResult> Get()
{
if (!await _permissionService.Authorize(PermissionSystemName.Brands)) return Forbid();
Expand Down Expand Up @@ -68,16 +69,16 @@ public async Task<IActionResult> Post([FromBody] BrandDto model)
}

[SwaggerOperation("Update entity in Brand", OperationId = "UpdateBrand")]
[HttpPut]
[HttpPut("{key}")]
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
[ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
public async Task<IActionResult> Put([FromBody] BrandDto model)
public async Task<IActionResult> Put([FromRoute] string key, [FromBody] BrandDto model)
{
if (!await _permissionService.Authorize(PermissionSystemName.Brands)) return Forbid();

var brand = await _mediator.Send(new GetGenericQuery<BrandDto, Brand>(model.Id));
var brand = await _mediator.Send(new GetGenericQuery<BrandDto, Brand>(key));
if (!brand.Any()) return NotFound();

model = await _mediator.Send(new UpdateBrandCommand { Model = model });
Expand All @@ -90,6 +91,13 @@ public async Task<IActionResult> Put([FromBody] BrandDto model)
[ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]

///sample
///{
/// "op": "replace",
/// "path": "/name",
/// "value": "new name"
///}
public async Task<IActionResult> Patch([FromRoute] string key, [FromBody] JsonPatchDocument<BrandDto> model)
{
if (string.IsNullOrEmpty(key))
Expand All @@ -107,11 +115,11 @@ public async Task<IActionResult> Patch([FromRoute] string key, [FromBody] JsonPa
}

[SwaggerOperation("Delete entity in Brand", OperationId = "DeleteBrand")]
[HttpDelete]
[HttpDelete("{key}")]
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
[ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
public async Task<IActionResult> Delete(string key)
public async Task<IActionResult> Delete([FromRoute] string key)
{
if (!await _permissionService.Authorize(PermissionSystemName.Brands)) return Forbid();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@
using Grand.Domain.Catalog;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using MongoDB.AspNetCore.OData;
using Swashbuckle.AspNetCore.Annotations;
using System.Net;
using Grand.Module.Api.Constants;
using Grand.Module.Api.Attributes;

namespace Grand.Module.Api.Controllers.OData;
namespace Grand.Module.Api.Controllers;

[Route($"{Configurations.ODataRoutePrefix}/BrandLayout")]
[Route($"{Configurations.RestRoutePrefix}/BrandLayout")]
[ApiExplorerSettings(IgnoreApi = false, GroupName = "v1")]
public class BrandLayoutController : BaseODataController
public class BrandLayoutController : BaseApiController
{
private readonly IMediator _mediator;
private readonly IPermissionService _permissionService;
Expand Down Expand Up @@ -43,7 +42,7 @@ public async Task<IActionResult> Get(string key)

[SwaggerOperation("Get entities from BrandLayout", OperationId = "GetBrandLayouts")]
[HttpGet]
[MongoEnableQuery(HandleNullPropagation = HandleNullPropagationOption.False)]
[EnableQuery]
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
[ProducesResponseType((int)HttpStatusCode.OK)]
public async Task<IActionResult> Get()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,16 @@
using MediatR;
using Microsoft.AspNetCore.JsonPatch;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using MongoDB.AspNetCore.OData;
using Swashbuckle.AspNetCore.Annotations;
using System.Net;
using Grand.Module.Api.Constants;
using Grand.Module.Api.Attributes;

namespace Grand.Module.Api.Controllers.OData;
namespace Grand.Module.Api.Controllers;

[Route($"{Configurations.ODataRoutePrefix}/Category")]
[Route($"{Configurations.RestRoutePrefix}/Category")]
[ApiExplorerSettings(IgnoreApi = false, GroupName = "v1")]
public class CategoryController : BaseODataController
public class CategoryController : BaseApiController
{
private readonly IMediator _mediator;
private readonly IPermissionService _permissionService;
Expand Down Expand Up @@ -47,7 +46,7 @@ public async Task<IActionResult> Get([FromRoute] string key)

[SwaggerOperation("Get entities from Category", OperationId = "GetCategories")]
[HttpGet]
[MongoEnableQuery(HandleNullPropagation = HandleNullPropagationOption.False)]
[EnableQuery]
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
[ProducesResponseType((int)HttpStatusCode.OK)]
public async Task<IActionResult> Get()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@
using Grand.Domain.Catalog;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using MongoDB.AspNetCore.OData;
using Swashbuckle.AspNetCore.Annotations;
using System.Net;
using Grand.Module.Api.Constants;
using Grand.Module.Api.Attributes;

namespace Grand.Module.Api.Controllers.OData;
namespace Grand.Module.Api.Controllers;

[Route($"{Configurations.ODataRoutePrefix}/CategoryLayout")]
[Route($"{Configurations.RestRoutePrefix}/CategoryLayout")]
[ApiExplorerSettings(IgnoreApi = false, GroupName = "v1")]
public class CategoryLayoutController : BaseODataController
public class CategoryLayoutController : BaseApiController
{
private readonly IMediator _mediator;
private readonly IPermissionService _permissionService;
Expand Down Expand Up @@ -45,7 +44,7 @@ public async Task<IActionResult> Get([FromRoute] string key)

[SwaggerOperation("Get entities from CategoryLayout", OperationId = "GetCategoryLayout")]
[HttpGet]
[MongoEnableQuery(HandleNullPropagation = HandleNullPropagationOption.False)]
[EnableQuery]
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
[ProducesResponseType((int)HttpStatusCode.OK)]
public async Task<IActionResult> Get()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,19 @@
using Grand.Module.Api.Commands.Models.Catalog;
using Grand.Module.Api.Constants;
using Grand.Module.Api.DTOs.Catalog;
using Grand.Module.Api.Attributes;
using Grand.Module.Api.Queries.Models.Common;
using MediatR;
using Microsoft.AspNetCore.JsonPatch;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using MongoDB.AspNetCore.OData;
using Swashbuckle.AspNetCore.Annotations;
using System.Net;

namespace Grand.Module.Api.Controllers.OData;
namespace Grand.Module.Api.Controllers;

[Route($"{Configurations.ODataRoutePrefix}/Collection")]
[Route($"{Configurations.RestRoutePrefix}/Collection")]
[ApiExplorerSettings(IgnoreApi = false, GroupName = "v1")]
public class CollectionController : BaseODataController
public class CollectionController : BaseApiController
{
private readonly IMediator _mediator;
private readonly IPermissionService _permissionService;
Expand Down Expand Up @@ -45,7 +44,7 @@ public async Task<IActionResult> Get([FromRoute] string key)

[SwaggerOperation("Get entities from Collection", OperationId = "GetCollections")]
[HttpGet]
[MongoEnableQuery(HandleNullPropagation = HandleNullPropagationOption.False)]
[EnableQuery]
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
[ProducesResponseType((int)HttpStatusCode.OK)]
public async Task<IActionResult> Get()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@
using Grand.Domain.Catalog;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using MongoDB.AspNetCore.OData;
using Swashbuckle.AspNetCore.Annotations;
using System.Net;
using Grand.Module.Api.Constants;
using Grand.Module.Api.Attributes;

namespace Grand.Module.Api.Controllers.OData;
namespace Grand.Module.Api.Controllers;

[Route($"{Configurations.ODataRoutePrefix}/CollectionLayout")]
[Route($"{Configurations.RestRoutePrefix}/CollectionLayout")]
[ApiExplorerSettings(IgnoreApi = false, GroupName = "v1")]
public class CollectionLayoutController : BaseODataController
public class CollectionLayoutController : BaseApiController
{
private readonly IMediator _mediator;
private readonly IPermissionService _permissionService;
Expand Down Expand Up @@ -43,7 +42,7 @@ public async Task<IActionResult> Get([FromRoute] string key)

[SwaggerOperation("Get entities from CollectionLayout", OperationId = "GetCollectionLayouts")]
[HttpGet]
[MongoEnableQuery(HandleNullPropagation = HandleNullPropagationOption.False)]
[EnableQuery]
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
[ProducesResponseType((int)HttpStatusCode.OK)]
public async Task<IActionResult> Get()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@
using Grand.Domain.Directory;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using MongoDB.AspNetCore.OData;
using Swashbuckle.AspNetCore.Annotations;
using System.Net;
using Grand.Module.Api.Constants;
using Grand.Module.Api.Attributes;

namespace Grand.Module.Api.Controllers.OData;
namespace Grand.Module.Api.Controllers;

[Route($"{Configurations.ODataRoutePrefix}/Country")]
[Route($"{Configurations.RestRoutePrefix}/Country")]
[ApiExplorerSettings(IgnoreApi = false, GroupName = "v1")]
public class CountryController : BaseODataController
public class CountryController : BaseApiController
{
private readonly IMediator _mediator;
private readonly IPermissionService _permissionService;
Expand Down Expand Up @@ -44,7 +43,7 @@ public async Task<IActionResult> Get([FromRoute] string key)

[SwaggerOperation("Get entities from Country", OperationId = "GetCountries")]
[HttpGet]
[MongoEnableQuery(HandleNullPropagation = HandleNullPropagationOption.False)]
[EnableQuery]
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
[ProducesResponseType((int)HttpStatusCode.OK)]
public async Task<IActionResult> Get()
Expand Down
Loading

0 comments on commit a543137

Please sign in to comment.