auth layer implemented

This commit is contained in:
Kalana B. Thilakarathna
2026-10-09 09:58:45 +05:30
parent 5b2ac8cc14
commit 558afc6f9d
22 changed files with 4731 additions and 82 deletions
@@ -1,4 +1,5 @@
using Distribution.Infra.Authorization; using Distribution.Infra.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Distribution.Features.Claims; namespace Distribution.Features.Claims;
@@ -7,10 +8,12 @@ namespace Distribution.Features.Claims;
public class ClaimController(ClaimService service, ICurrentUserService currentUser) : ControllerBase public class ClaimController(ClaimService service, ICurrentUserService currentUser) : ControllerBase
{ {
[HttpGet("api/claims")] [HttpGet("api/claims")]
[Authorize("claim.view")]
public async Task<IActionResult> GetAll() => public async Task<IActionResult> GetAll() =>
Ok(await service.GetAllAsync()); Ok(await service.GetAllAsync());
[HttpGet("api/claims/{id:guid}")] [HttpGet("api/claims/{id:guid}")]
[Authorize("claim.view")]
public async Task<IActionResult> GetById(Guid id) public async Task<IActionResult> GetById(Guid id)
{ {
var result = await service.GetByIdAsync(id); var result = await service.GetByIdAsync(id);
@@ -18,6 +21,7 @@ public class ClaimController(ClaimService service, ICurrentUserService currentUs
} }
[HttpPost("api/claims")] [HttpPost("api/claims")]
[Authorize("claim.manage")]
public async Task<IActionResult> Create(CreateClaimRequest request, CancellationToken ct) public async Task<IActionResult> Create(CreateClaimRequest request, CancellationToken ct)
{ {
try try
@@ -29,6 +33,7 @@ public class ClaimController(ClaimService service, ICurrentUserService currentUs
} }
[HttpPut("api/claims/{id:guid}")] [HttpPut("api/claims/{id:guid}")]
[Authorize("claim.manage")]
public async Task<IActionResult> Update(Guid id, UpdateClaimRequest request, CancellationToken ct) public async Task<IActionResult> Update(Guid id, UpdateClaimRequest request, CancellationToken ct)
{ {
try try
@@ -40,6 +45,7 @@ public class ClaimController(ClaimService service, ICurrentUserService currentUs
} }
[HttpPost("api/claims/{id:guid}/settle")] [HttpPost("api/claims/{id:guid}/settle")]
[Authorize("claim.manage")]
public async Task<IActionResult> Settle(Guid id, SettleClaimRequest request, CancellationToken ct) public async Task<IActionResult> Settle(Guid id, SettleClaimRequest request, CancellationToken ct)
{ {
var userId = currentUser.UserId ?? request.SettledByUserId; var userId = currentUser.UserId ?? request.SettledByUserId;
@@ -1,4 +1,5 @@
using Distribution.Models; using Distribution.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Distribution.Features.DeliveryRide; namespace Distribution.Features.DeliveryRide;
@@ -8,6 +9,7 @@ namespace Distribution.Features.DeliveryRide;
public class DeliveryTaskController(DeliveryTaskService service) : ControllerBase public class DeliveryTaskController(DeliveryTaskService service) : ControllerBase
{ {
[HttpPost("rides/{rideId:guid}/tasks/generate")] [HttpPost("rides/{rideId:guid}/tasks/generate")]
[Authorize("delivery-task.manage")]
public async Task<IActionResult> Generate(Guid rideId, CancellationToken ct) public async Task<IActionResult> Generate(Guid rideId, CancellationToken ct)
{ {
try try
@@ -21,6 +23,7 @@ public class DeliveryTaskController(DeliveryTaskService service) : ControllerBas
[HttpGet("rides/{rideId:guid}/tasks")] [HttpGet("rides/{rideId:guid}/tasks")]
[HttpGet("rides/{rideId:guid}/delivery-tasks")] [HttpGet("rides/{rideId:guid}/delivery-tasks")]
[Authorize("delivery-task.view")]
public async Task<IActionResult> GetByRide(Guid rideId) public async Task<IActionResult> GetByRide(Guid rideId)
{ {
var result = await service.GetByRideIdAsync(rideId); var result = await service.GetByRideIdAsync(rideId);
@@ -28,6 +31,7 @@ public class DeliveryTaskController(DeliveryTaskService service) : ControllerBas
} }
[HttpGet("delivery-tasks")] [HttpGet("delivery-tasks")]
[Authorize("delivery-task.view")]
public async Task<IActionResult> GetAll( public async Task<IActionResult> GetAll(
[FromQuery] DeliveryTaskStatus? status, [FromQuery] DeliveryTaskStatus? status,
[FromQuery] int page = 1, [FromQuery] int page = 1,
@@ -38,6 +42,7 @@ public class DeliveryTaskController(DeliveryTaskService service) : ControllerBas
} }
[HttpGet("delivery-tasks/{id:guid}")] [HttpGet("delivery-tasks/{id:guid}")]
[Authorize("delivery-task.view")]
public async Task<IActionResult> GetById(Guid id) public async Task<IActionResult> GetById(Guid id)
{ {
var result = await service.GetByIdAsync(id); var result = await service.GetByIdAsync(id);
@@ -45,6 +50,7 @@ public class DeliveryTaskController(DeliveryTaskService service) : ControllerBas
} }
[HttpPut("delivery-tasks/{id:guid}/quantities")] [HttpPut("delivery-tasks/{id:guid}/quantities")]
[Authorize("delivery-task.manage")]
public async Task<IActionResult> SetQuantities(Guid id, SetQuantitiesRequest request, CancellationToken ct) public async Task<IActionResult> SetQuantities(Guid id, SetQuantitiesRequest request, CancellationToken ct)
{ {
try try
@@ -57,6 +63,7 @@ public class DeliveryTaskController(DeliveryTaskService service) : ControllerBas
} }
[HttpPost("delivery-tasks/{id:guid}/confirm")] [HttpPost("delivery-tasks/{id:guid}/confirm")]
[Authorize("delivery-task.manage")]
public async Task<IActionResult> Confirm(Guid id, CancellationToken ct) public async Task<IActionResult> Confirm(Guid id, CancellationToken ct)
{ {
try try
@@ -69,6 +76,7 @@ public class DeliveryTaskController(DeliveryTaskService service) : ControllerBas
} }
[HttpPost("delivery-tasks/{id:guid}/fail")] [HttpPost("delivery-tasks/{id:guid}/fail")]
[Authorize("delivery-task.manage")]
public async Task<IActionResult> Fail(Guid id, FailTaskRequest request, CancellationToken ct) public async Task<IActionResult> Fail(Guid id, FailTaskRequest request, CancellationToken ct)
{ {
try try
@@ -1,5 +1,6 @@
using Distribution.Features.DriverComplianceConfig; using Distribution.Features.DriverComplianceConfig;
using Distribution.Infra.Authorization; using Distribution.Infra.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Distribution.Features.DriverProfile; namespace Distribution.Features.DriverProfile;
@@ -12,6 +13,7 @@ public class DriverProfileController(
ICurrentUserService currentUser) : ControllerBase ICurrentUserService currentUser) : ControllerBase
{ {
[HttpGet] [HttpGet]
[Authorize("driver.view")]
public async Task<IActionResult> GetAll([FromQuery] int page = 1, [FromQuery] int pageSize = 20) public async Task<IActionResult> GetAll([FromQuery] int page = 1, [FromQuery] int pageSize = 20)
{ {
var result = await service.GetAllAsync(page, pageSize); var result = await service.GetAllAsync(page, pageSize);
@@ -19,6 +21,7 @@ public class DriverProfileController(
} }
[HttpGet("{id:guid}")] [HttpGet("{id:guid}")]
[Authorize("driver.view")]
public async Task<IActionResult> GetById(Guid id) public async Task<IActionResult> GetById(Guid id)
{ {
var result = await service.GetByIdAsync(id); var result = await service.GetByIdAsync(id);
@@ -26,6 +29,7 @@ public class DriverProfileController(
} }
[HttpPost] [HttpPost]
[Authorize("driver.manage")]
public async Task<IActionResult> Create(CreateDriverProfileRequest request, CancellationToken ct) public async Task<IActionResult> Create(CreateDriverProfileRequest request, CancellationToken ct)
{ {
try try
@@ -44,6 +48,7 @@ public class DriverProfileController(
} }
[HttpPut("{id:guid}")] [HttpPut("{id:guid}")]
[Authorize("driver.manage")]
public async Task<IActionResult> Update(Guid id, UpdateDriverProfileRequest request, CancellationToken ct) public async Task<IActionResult> Update(Guid id, UpdateDriverProfileRequest request, CancellationToken ct)
{ {
var result = await service.UpdateAsync(id, request, ct); var result = await service.UpdateAsync(id, request, ct);
@@ -51,6 +56,7 @@ public class DriverProfileController(
} }
[HttpDelete("{id:guid}")] [HttpDelete("{id:guid}")]
[Authorize("driver.manage")]
public async Task<IActionResult> Deactivate(Guid id, CancellationToken ct) public async Task<IActionResult> Deactivate(Guid id, CancellationToken ct)
{ {
var success = await service.DeactivateAsync(id, ct); var success = await service.DeactivateAsync(id, ct);
@@ -58,6 +64,7 @@ public class DriverProfileController(
} }
[HttpGet("compliance")] [HttpGet("compliance")]
[Authorize("driver.view")]
public async Task<IActionResult> GetCompliance() public async Task<IActionResult> GetCompliance()
{ {
var result = await complianceService.GetAsync(); var result = await complianceService.GetAsync();
@@ -65,6 +72,7 @@ public class DriverProfileController(
} }
[HttpPut("compliance")] [HttpPut("compliance")]
[Authorize("driver.manage")]
public async Task<IActionResult> UpsertCompliance(UpdateDriverComplianceConfigRequest request, CancellationToken ct) public async Task<IActionResult> UpsertCompliance(UpdateDriverComplianceConfigRequest request, CancellationToken ct)
{ {
var userId = currentUser.UserId ?? throw new UnauthorizedAccessException(); var userId = currentUser.UserId ?? throw new UnauthorizedAccessException();
+8 -1
View File
@@ -1,4 +1,5 @@
using Distribution.Infra.Authorization; using Distribution.Infra.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Distribution.Features.Grn; namespace Distribution.Features.Grn;
@@ -7,6 +8,7 @@ namespace Distribution.Features.Grn;
public class GrnController(GrnService service, ICurrentUserService currentUser) : ControllerBase public class GrnController(GrnService service, ICurrentUserService currentUser) : ControllerBase
{ {
[HttpGet("api/goods-receipts")] [HttpGet("api/goods-receipts")]
[Authorize("grn.view")]
public async Task<IActionResult> GetAll( public async Task<IActionResult> GetAll(
[FromQuery] Guid? purchaseOrderId, [FromQuery] Guid? purchaseOrderId,
[FromQuery] int page = 1, [FromQuery] int page = 1,
@@ -17,6 +19,7 @@ public class GrnController(GrnService service, ICurrentUserService currentUser)
} }
[HttpGet("api/goods-receipts/{id:guid}")] [HttpGet("api/goods-receipts/{id:guid}")]
[Authorize("grn.view")]
public async Task<IActionResult> GetById(Guid id) public async Task<IActionResult> GetById(Guid id)
{ {
var result = await service.GetByIdAsync(id); var result = await service.GetByIdAsync(id);
@@ -24,6 +27,7 @@ public class GrnController(GrnService service, ICurrentUserService currentUser)
} }
[HttpPost("api/goods-receipts")] [HttpPost("api/goods-receipts")]
[Authorize("grn.manage")]
public async Task<IActionResult> CreateFlat(CreateFlatGrnRequest request, CancellationToken ct) public async Task<IActionResult> CreateFlat(CreateFlatGrnRequest request, CancellationToken ct)
{ {
// TEMPORARY: currentUser.UserId is always unset due to the broken auth middleware // TEMPORARY: currentUser.UserId is always unset due to the broken auth middleware
@@ -42,6 +46,7 @@ public class GrnController(GrnService service, ICurrentUserService currentUser)
/// <summary>Goods received without a purchase order.</summary> /// <summary>Goods received without a purchase order.</summary>
[HttpPost("api/goods-receipts/direct")] [HttpPost("api/goods-receipts/direct")]
[Authorize("grn.manage")]
public async Task<IActionResult> CreateDirect(CreateDirectGrnRequest request, CancellationToken ct) public async Task<IActionResult> CreateDirect(CreateDirectGrnRequest request, CancellationToken ct)
{ {
var userId = currentUser.UserId ?? request.ReceivedByUserId; var userId = currentUser.UserId ?? request.ReceivedByUserId;
@@ -55,10 +60,12 @@ public class GrnController(GrnService service, ICurrentUserService currentUser)
} }
[HttpGet("api/purchase-orders/{id:guid}/goods-receipts")] [HttpGet("api/purchase-orders/{id:guid}/goods-receipts")]
[Authorize("grn.view")]
public async Task<IActionResult> GetByPurchaseOrder(Guid id) => public async Task<IActionResult> GetByPurchaseOrder(Guid id) =>
Ok(await service.GetByPurchaseOrderIdAsync(id)); Ok(await service.GetByPurchaseOrderIdAsync(id));
[HttpPost("api/purchase-orders/{id:guid}/goods-receipts")] [HttpPost("api/purchase-orders/{id:guid}/goods-receipts")]
[Authorize("grn.manage")]
public async Task<IActionResult> Create(Guid id, CreateGrnRequest request, CancellationToken ct) public async Task<IActionResult> Create(Guid id, CreateGrnRequest request, CancellationToken ct)
{ {
var userId = currentUser.UserId ?? request.ReceivedByUserId; var userId = currentUser.UserId ?? request.ReceivedByUserId;
@@ -1,14 +1,19 @@
using Distribution.Models;
using Distribution.Infra.Authorization; using Distribution.Infra.Authorization;
using Distribution.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Distribution.Features.LoadingEvent; namespace Distribution.Features.LoadingEvent;
[ApiController] [ApiController]
[Route("api/loading-sheets")] [Route("api/loading-sheets")]
public class LoadingSheetController(LoadingSheetService service, ICurrentUserService currentUser) : ControllerBase public class LoadingSheetController(
LoadingSheetService service,
IScopeAccessService scopeAccess,
ICurrentUserService currentUser) : ControllerBase
{ {
[HttpGet] [HttpGet]
[Authorize("loading-sheet.view")]
public async Task<IActionResult> GetAll( public async Task<IActionResult> GetAll(
[FromQuery] Guid? rideId, [FromQuery] Guid? rideId,
[FromQuery] LoadingSheetStatus? status, [FromQuery] LoadingSheetStatus? status,
@@ -17,11 +22,26 @@ public class LoadingSheetController(LoadingSheetService service, ICurrentUserSer
[FromQuery] int page = 1, [FromQuery] int page = 1,
[FromQuery] int pageSize = 20) [FromQuery] int pageSize = 20)
{ {
if (routeId.HasValue)
{
var userId = currentUser.UserId;
if (userId.HasValue && !await scopeAccess.HasRouteScopeAsync(userId.Value, routeId.Value))
return StatusCode(403);
}
if (regionId.HasValue)
{
var userId = currentUser.UserId;
if (userId.HasValue && !await scopeAccess.HasRegionScopeAsync(userId.Value, regionId.Value))
return StatusCode(403);
}
var result = await service.GetAllAsync(rideId, status, routeId, regionId, page, pageSize); var result = await service.GetAllAsync(rideId, status, routeId, regionId, page, pageSize);
return Ok(result); return Ok(result);
} }
[HttpGet("{id:guid}")] [HttpGet("{id:guid}")]
[Authorize("loading-sheet.view")]
public async Task<IActionResult> GetById(Guid id) public async Task<IActionResult> GetById(Guid id)
{ {
var result = await service.GetByIdAsync(id); var result = await service.GetByIdAsync(id);
@@ -29,6 +49,7 @@ public class LoadingSheetController(LoadingSheetService service, ICurrentUserSer
} }
[HttpPost] [HttpPost]
[Authorize("loading-sheet.manage")]
public async Task<IActionResult> Create(CreateLoadingSheetRequest request, CancellationToken ct) public async Task<IActionResult> Create(CreateLoadingSheetRequest request, CancellationToken ct)
{ {
// TEMPORARY: currentUser.UserId is always unset due to the broken auth middleware // TEMPORARY: currentUser.UserId is always unset due to the broken auth middleware
@@ -45,6 +66,7 @@ public class LoadingSheetController(LoadingSheetService service, ICurrentUserSer
} }
[HttpPut("{id:guid}/items")] [HttpPut("{id:guid}/items")]
[Authorize("loading-sheet.manage")]
public async Task<IActionResult> SetItems(Guid id, SetItemsRequest request, CancellationToken ct) public async Task<IActionResult> SetItems(Guid id, SetItemsRequest request, CancellationToken ct)
{ {
try try
@@ -57,6 +79,7 @@ public class LoadingSheetController(LoadingSheetService service, ICurrentUserSer
} }
[HttpPost("{id:guid}/confirm")] [HttpPost("{id:guid}/confirm")]
[Authorize("loading-sheet.manage")]
public async Task<IActionResult> Confirm(Guid id, ConfirmLoadingSheetRequest request, CancellationToken ct) public async Task<IActionResult> Confirm(Guid id, ConfirmLoadingSheetRequest request, CancellationToken ct)
{ {
// TEMPORARY: currentUser.UserId is always unset due to the broken auth middleware // TEMPORARY: currentUser.UserId is always unset due to the broken auth middleware
@@ -1,16 +1,31 @@
using Microsoft.AspNetCore.Mvc; using Distribution.Infra.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Distribution.Features.PriceList; namespace Distribution.Features.PriceList;
[ApiController] [ApiController]
[Route("api/price-lists")] [Route("api/price-lists")]
public class PriceListController(PriceListService service) : ControllerBase public class PriceListController(
PriceListService service,
IScopeAccessService scopeAccess,
ICurrentUserService currentUser) : ControllerBase
{ {
[HttpGet] [HttpGet]
public async Task<IActionResult> GetAll([FromQuery] Guid? regionId) => [Authorize("price-list.view")]
Ok(await service.GetAllAsync(regionId)); public async Task<IActionResult> GetAll([FromQuery] Guid? regionId)
{
if (regionId.HasValue)
{
var userId = currentUser.UserId;
if (userId.HasValue && !await scopeAccess.HasRegionScopeAsync(userId.Value, regionId.Value))
return StatusCode(403);
}
return Ok(await service.GetAllAsync(regionId));
}
[HttpGet("resolve")] [HttpGet("resolve")]
[Authorize("price-list.view")]
public async Task<IActionResult> Resolve([FromQuery] Guid itemId, [FromQuery] Guid storeId, [FromQuery] DateTime saleDate) public async Task<IActionResult> Resolve([FromQuery] Guid itemId, [FromQuery] Guid storeId, [FromQuery] DateTime saleDate)
{ {
var result = await service.ResolveByStoreAsync(itemId, storeId, saleDate); var result = await service.ResolveByStoreAsync(itemId, storeId, saleDate);
@@ -18,6 +33,7 @@ public class PriceListController(PriceListService service) : ControllerBase
} }
[HttpGet("{id:guid}")] [HttpGet("{id:guid}")]
[Authorize("price-list.view")]
public async Task<IActionResult> GetById(Guid id) public async Task<IActionResult> GetById(Guid id)
{ {
var result = await service.GetByIdAsync(id); var result = await service.GetByIdAsync(id);
@@ -25,6 +41,7 @@ public class PriceListController(PriceListService service) : ControllerBase
} }
[HttpPost] [HttpPost]
[Authorize("price-list.manage")]
public async Task<IActionResult> Create(CreatePriceListRequest request, CancellationToken ct) public async Task<IActionResult> Create(CreatePriceListRequest request, CancellationToken ct)
{ {
var result = await service.CreateAsync(request, ct); var result = await service.CreateAsync(request, ct);
@@ -32,6 +49,7 @@ public class PriceListController(PriceListService service) : ControllerBase
} }
[HttpPut("{id:guid}")] [HttpPut("{id:guid}")]
[Authorize("price-list.manage")]
public async Task<IActionResult> Update(Guid id, UpdatePriceListRequest request, CancellationToken ct) public async Task<IActionResult> Update(Guid id, UpdatePriceListRequest request, CancellationToken ct)
{ {
try try
@@ -46,6 +64,7 @@ public class PriceListController(PriceListService service) : ControllerBase
} }
[HttpDelete("{id:guid}")] [HttpDelete("{id:guid}")]
[Authorize("price-list.manage")]
public async Task<IActionResult> Delete(Guid id, CancellationToken ct) public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
{ {
var deleted = await service.DeleteAsync(id, ct); var deleted = await service.DeleteAsync(id, ct);
@@ -53,6 +72,7 @@ public class PriceListController(PriceListService service) : ControllerBase
} }
[HttpPut("{id:guid}/items/{sku}")] [HttpPut("{id:guid}/items/{sku}")]
[Authorize("price-list.manage")]
public async Task<IActionResult> UpsertItem(Guid id, string sku, UpsertPriceListItemRequest request, CancellationToken ct) public async Task<IActionResult> UpsertItem(Guid id, string sku, UpsertPriceListItemRequest request, CancellationToken ct)
{ {
try try
@@ -67,6 +87,7 @@ public class PriceListController(PriceListService service) : ControllerBase
} }
[HttpDelete("{id:guid}/items/{sku}")] [HttpDelete("{id:guid}/items/{sku}")]
[Authorize("price-list.manage")]
public async Task<IActionResult> RemoveItem(Guid id, string sku, CancellationToken ct) public async Task<IActionResult> RemoveItem(Guid id, string sku, CancellationToken ct)
{ {
try try
@@ -1,5 +1,6 @@
using Distribution.Infra.Authorization; using Distribution.Infra.Authorization;
using Distribution.Models; using Distribution.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Distribution.Features.Po; namespace Distribution.Features.Po;
@@ -9,10 +10,12 @@ namespace Distribution.Features.Po;
public class PoController(PoService service, ICurrentUserService currentUser) : ControllerBase public class PoController(PoService service, ICurrentUserService currentUser) : ControllerBase
{ {
[HttpGet] [HttpGet]
[Authorize("purchase-order.view")]
public async Task<IActionResult> GetAll([FromQuery] Guid? supplierId, [FromQuery] PurchaseOrderStatus? status) => public async Task<IActionResult> GetAll([FromQuery] Guid? supplierId, [FromQuery] PurchaseOrderStatus? status) =>
Ok(await service.GetAllAsync(supplierId, status)); Ok(await service.GetAllAsync(supplierId, status));
[HttpGet("{id:guid}")] [HttpGet("{id:guid}")]
[Authorize("purchase-order.view")]
public async Task<IActionResult> GetById(Guid id) public async Task<IActionResult> GetById(Guid id)
{ {
var result = await service.GetByIdAsync(id); var result = await service.GetByIdAsync(id);
@@ -20,6 +23,7 @@ public class PoController(PoService service, ICurrentUserService currentUser) :
} }
[HttpPost] [HttpPost]
[Authorize("purchase-order.manage")]
public async Task<IActionResult> Create(CreatePoRequest request, CancellationToken ct) public async Task<IActionResult> Create(CreatePoRequest request, CancellationToken ct)
{ {
// TEMPORARY: currentUser.UserId is always unset due to the broken auth middleware // TEMPORARY: currentUser.UserId is always unset due to the broken auth middleware
@@ -35,6 +39,7 @@ public class PoController(PoService service, ICurrentUserService currentUser) :
} }
[HttpPut("{id:guid}")] [HttpPut("{id:guid}")]
[Authorize("purchase-order.manage")]
public async Task<IActionResult> Update(Guid id, UpdatePoRequest request, CancellationToken ct) public async Task<IActionResult> Update(Guid id, UpdatePoRequest request, CancellationToken ct)
{ {
try try
@@ -46,6 +51,7 @@ public class PoController(PoService service, ICurrentUserService currentUser) :
} }
[HttpPost("{id:guid}/close")] [HttpPost("{id:guid}/close")]
[Authorize("purchase-order.manage")]
public async Task<IActionResult> Close(Guid id, CancellationToken ct) public async Task<IActionResult> Close(Guid id, CancellationToken ct)
{ {
try try
@@ -57,6 +63,7 @@ public class PoController(PoService service, ICurrentUserService currentUser) :
} }
[HttpPost("{id:guid}/cancel")] [HttpPost("{id:guid}/cancel")]
[Authorize("purchase-order.manage")]
public async Task<IActionResult> Cancel(Guid id, CancelPoRequest request, CancellationToken ct) public async Task<IActionResult> Cancel(Guid id, CancelPoRequest request, CancellationToken ct)
{ {
try try
@@ -68,6 +75,7 @@ public class PoController(PoService service, ICurrentUserService currentUser) :
} }
[HttpPost("{id:guid}/items/{itemId:guid}/cancel")] [HttpPost("{id:guid}/items/{itemId:guid}/cancel")]
[Authorize("purchase-order.manage")]
public async Task<IActionResult> CancelLine(Guid id, Guid itemId, CancelPoLineRequest request, CancellationToken ct) public async Task<IActionResult> CancelLine(Guid id, Guid itemId, CancelPoLineRequest request, CancellationToken ct)
{ {
try try
@@ -79,6 +87,7 @@ public class PoController(PoService service, ICurrentUserService currentUser) :
} }
[HttpPost("{id:guid}/match-invoice")] [HttpPost("{id:guid}/match-invoice")]
[Authorize("purchase-order.view")]
public async Task<IActionResult> MatchInvoice(Guid id, [FromQuery] Guid? invoiceId, [FromQuery] Guid? grnId) public async Task<IActionResult> MatchInvoice(Guid id, [FromQuery] Guid? invoiceId, [FromQuery] Guid? grnId)
{ {
var result = await service.MatchInvoiceToPoAsync(id, invoiceId, grnId); var result = await service.MatchInvoiceToPoAsync(id, invoiceId, grnId);
@@ -86,6 +95,7 @@ public class PoController(PoService service, ICurrentUserService currentUser) :
} }
[HttpPost("{id:guid}/resolve-variance")] [HttpPost("{id:guid}/resolve-variance")]
[Authorize("purchase-order.manage")]
public async Task<IActionResult> ResolveVariance(Guid id, ResolveInvoiceVarianceRequest request, CancellationToken ct) public async Task<IActionResult> ResolveVariance(Guid id, ResolveInvoiceVarianceRequest request, CancellationToken ct)
{ {
try try
@@ -1,4 +1,5 @@
using Distribution.Infra.Authorization; using Distribution.Infra.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Distribution.Features.PurchaseReturn; namespace Distribution.Features.PurchaseReturn;
@@ -7,6 +8,7 @@ namespace Distribution.Features.PurchaseReturn;
public class PurchaseReturnController(PurchaseReturnService service, ICurrentUserService currentUser) : ControllerBase public class PurchaseReturnController(PurchaseReturnService service, ICurrentUserService currentUser) : ControllerBase
{ {
[HttpGet("api/purchase-returns/{id:guid}")] [HttpGet("api/purchase-returns/{id:guid}")]
[Authorize("purchase-order.view")]
public async Task<IActionResult> GetById(Guid id) public async Task<IActionResult> GetById(Guid id)
{ {
var result = await service.GetByIdAsync(id); var result = await service.GetByIdAsync(id);
@@ -14,10 +16,12 @@ public class PurchaseReturnController(PurchaseReturnService service, ICurrentUse
} }
[HttpGet("api/purchase-orders/{id:guid}/returns")] [HttpGet("api/purchase-orders/{id:guid}/returns")]
[Authorize("purchase-order.view")]
public async Task<IActionResult> GetByPurchaseOrder(Guid id) => public async Task<IActionResult> GetByPurchaseOrder(Guid id) =>
Ok(await service.GetByPurchaseOrderIdAsync(id)); Ok(await service.GetByPurchaseOrderIdAsync(id));
[HttpPost("api/purchase-orders/{id:guid}/returns")] [HttpPost("api/purchase-orders/{id:guid}/returns")]
[Authorize("purchase-return.manage")]
public async Task<IActionResult> Create(Guid id, CreatePurchaseReturnRequest request, CancellationToken ct) public async Task<IActionResult> Create(Guid id, CreatePurchaseReturnRequest request, CancellationToken ct)
{ {
// TEMPORARY: currentUser.UserId is always unset due to the broken auth middleware // TEMPORARY: currentUser.UserId is always unset due to the broken auth middleware
@@ -1,28 +1,39 @@
using Microsoft.AspNetCore.Mvc; using Distribution.Infra.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Distribution.Features.Region; namespace Distribution.Features.Region;
[ApiController] [ApiController]
[Route("api/regions")] [Route("api/regions")]
public class RegionController(RegionService service) : ControllerBase public class RegionController(
RegionService service,
IScopeAccessService scopeAccess,
ICurrentUserService currentUser) : ControllerBase
{ {
[HttpGet] [HttpGet]
[Authorize("region.view")]
public async Task<IActionResult> GetAll() => public async Task<IActionResult> GetAll() =>
Ok(await service.GetAllAsync()); Ok(await service.GetAllAsync());
// Suggested code for the Add Region form; the user may override it.
[HttpGet("next-code")] [HttpGet("next-code")]
[Authorize("region.view")]
public async Task<IActionResult> GetNextCode() => public async Task<IActionResult> GetNextCode() =>
Ok(await service.GetNextCodeAsync()); Ok(await service.GetNextCodeAsync());
[HttpGet("{id:guid}")] [HttpGet("{id:guid}")]
[Authorize("region.view")]
public async Task<IActionResult> GetById(Guid id) public async Task<IActionResult> GetById(Guid id)
{ {
var userId = currentUser.UserId;
if (userId.HasValue && !await scopeAccess.HasRegionScopeAsync(userId.Value, id))
return StatusCode(403);
var result = await service.GetByIdAsync(id); var result = await service.GetByIdAsync(id);
return result is null ? NotFound() : Ok(result); return result is null ? NotFound() : Ok(result);
} }
[HttpPost] [HttpPost]
[Authorize("region.manage")]
public async Task<IActionResult> Create(CreateRegionRequest request, CancellationToken ct) public async Task<IActionResult> Create(CreateRegionRequest request, CancellationToken ct)
{ {
var result = await service.CreateAsync(request, ct); var result = await service.CreateAsync(request, ct);
@@ -30,6 +41,7 @@ public class RegionController(RegionService service) : ControllerBase
} }
[HttpPut("{id:guid}")] [HttpPut("{id:guid}")]
[Authorize("region.manage")]
public async Task<IActionResult> Update(Guid id, UpdateRegionRequest request, CancellationToken ct) public async Task<IActionResult> Update(Guid id, UpdateRegionRequest request, CancellationToken ct)
{ {
var result = await service.UpdateAsync(id, request, ct); var result = await service.UpdateAsync(id, request, ct);
@@ -37,6 +49,7 @@ public class RegionController(RegionService service) : ControllerBase
} }
[HttpDelete("{id:guid}")] [HttpDelete("{id:guid}")]
[Authorize("region.manage")]
public async Task<IActionResult> Delete(Guid id, CancellationToken ct) public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
{ {
var deleted = await service.DeleteAsync(id, ct); var deleted = await service.DeleteAsync(id, ct);
@@ -44,6 +57,7 @@ public class RegionController(RegionService service) : ControllerBase
} }
[HttpGet("{id:guid}/manager")] [HttpGet("{id:guid}/manager")]
[Authorize("region.view")]
public async Task<IActionResult> GetManager(Guid id) public async Task<IActionResult> GetManager(Guid id)
{ {
var result = await service.GetManagerAsync(id); var result = await service.GetManagerAsync(id);
@@ -51,6 +65,7 @@ public class RegionController(RegionService service) : ControllerBase
} }
[HttpPut("{id:guid}/manager")] [HttpPut("{id:guid}/manager")]
[Authorize("region.manage")]
public async Task<IActionResult> SetManager(Guid id, SetRegionManagerRequest request, CancellationToken ct) public async Task<IActionResult> SetManager(Guid id, SetRegionManagerRequest request, CancellationToken ct)
{ {
try try
@@ -65,14 +80,15 @@ public class RegionController(RegionService service) : ControllerBase
} }
[HttpDelete("{id:guid}/manager")] [HttpDelete("{id:guid}/manager")]
[Authorize("region.manage")]
public async Task<IActionResult> RemoveManager(Guid id, CancellationToken ct) public async Task<IActionResult> RemoveManager(Guid id, CancellationToken ct)
{ {
var removed = await service.RemoveManagerAsync(id, ct); var removed = await service.RemoveManagerAsync(id, ct);
return removed ? NoContent() : NotFound(); return removed ? NoContent() : NotFound();
} }
//targets/budgets/agencies/tax-rule.
[HttpPut("{id:guid}/manage")] [HttpPut("{id:guid}/manage")]
[Authorize("region.manage")]
public async Task<IActionResult> Manage(Guid id, ManageRegionRequest request, CancellationToken ct) public async Task<IActionResult> Manage(Guid id, ManageRegionRequest request, CancellationToken ct)
{ {
var result = await service.ManageAsync(id, request, ct); var result = await service.ManageAsync(id, request, ct);
@@ -80,6 +96,7 @@ public class RegionController(RegionService service) : ControllerBase
} }
[HttpGet("{id:guid}/hierarchy")] [HttpGet("{id:guid}/hierarchy")]
[Authorize("region.view")]
public async Task<IActionResult> GetHierarchy(Guid id) public async Task<IActionResult> GetHierarchy(Guid id)
{ {
var result = await service.GetHierarchyAsync(id); var result = await service.GetHierarchyAsync(id);
@@ -87,18 +104,20 @@ public class RegionController(RegionService service) : ControllerBase
} }
[HttpGet("{id:guid}/dashboard")] [HttpGet("{id:guid}/dashboard")]
[Authorize("region.view")]
public async Task<IActionResult> GetDashboard(Guid id, [FromQuery] string period) public async Task<IActionResult> GetDashboard(Guid id, [FromQuery] string period)
{ {
var result = await service.GetDashboardAsync(id, period); var result = await service.GetDashboardAsync(id, period);
return result is null ? NotFound() : Ok(result); return result is null ? NotFound() : Ok(result);
} }
// Flat CRUD-list view over targets/budgets/tax-rules/agency-maps across all regions.
[HttpGet("manage-entries")] [HttpGet("manage-entries")]
[Authorize("region.view")]
public async Task<IActionResult> GetManageEntries() => public async Task<IActionResult> GetManageEntries() =>
Ok(await service.GetManageEntriesAsync()); Ok(await service.GetManageEntriesAsync());
[HttpDelete("manage-entries/{entryType}/{id:guid}")] [HttpDelete("manage-entries/{entryType}/{id:guid}")]
[Authorize("region.manage")]
public async Task<IActionResult> DeleteManageEntry(RegionManageEntryType entryType, Guid id, CancellationToken ct) public async Task<IActionResult> DeleteManageEntry(RegionManageEntryType entryType, Guid id, CancellationToken ct)
{ {
var deleted = await service.DeleteManageEntryAsync(entryType, id, ct); var deleted = await service.DeleteManageEntryAsync(entryType, id, ct);
@@ -1,4 +1,5 @@
using Distribution.Infra.Authorization; using Distribution.Infra.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Distribution.Features.Returns; namespace Distribution.Features.Returns;
@@ -7,10 +8,12 @@ namespace Distribution.Features.Returns;
public class ReturnController(ReturnService service, ICurrentUserService currentUser) : ControllerBase public class ReturnController(ReturnService service, ICurrentUserService currentUser) : ControllerBase
{ {
[HttpGet("api/returns")] [HttpGet("api/returns")]
[Authorize("return.view")]
public async Task<IActionResult> GetAll() => public async Task<IActionResult> GetAll() =>
Ok(await service.GetAllAsync()); Ok(await service.GetAllAsync());
[HttpGet("api/returns/{id:guid}")] [HttpGet("api/returns/{id:guid}")]
[Authorize("return.view")]
public async Task<IActionResult> GetById(Guid id) public async Task<IActionResult> GetById(Guid id)
{ {
var result = await service.GetByIdAsync(id); var result = await service.GetByIdAsync(id);
@@ -18,6 +21,7 @@ public class ReturnController(ReturnService service, ICurrentUserService current
} }
[HttpPatch("api/returns/{id:guid}/reasons")] [HttpPatch("api/returns/{id:guid}/reasons")]
[Authorize("return.manage")]
public async Task<IActionResult> UpdateReasons(Guid id, UpdateSaleReturnReasonsRequest request, CancellationToken ct) public async Task<IActionResult> UpdateReasons(Guid id, UpdateSaleReturnReasonsRequest request, CancellationToken ct)
{ {
try try
@@ -29,10 +33,12 @@ public class ReturnController(ReturnService service, ICurrentUserService current
} }
[HttpGet("api/shop-pos/{id:guid}/returns")] [HttpGet("api/shop-pos/{id:guid}/returns")]
[Authorize("return.view")]
public async Task<IActionResult> GetByShopPO(Guid id) => public async Task<IActionResult> GetByShopPO(Guid id) =>
Ok(await service.GetByShopPOIdAsync(id)); Ok(await service.GetByShopPOIdAsync(id));
[HttpPost("api/shop-pos/{id:guid}/returns")] [HttpPost("api/shop-pos/{id:guid}/returns")]
[Authorize("return.manage")]
public async Task<IActionResult> Create(Guid id, CreateSaleReturnRequest request, CancellationToken ct) public async Task<IActionResult> Create(Guid id, CreateSaleReturnRequest request, CancellationToken ct)
{ {
var userId = currentUser.UserId ?? request.CreatedByUserId; var userId = currentUser.UserId ?? request.CreatedByUserId;
+21 -2
View File
@@ -1,23 +1,34 @@
using Microsoft.AspNetCore.Mvc; using Distribution.Infra.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Distribution.Features.Route; namespace Distribution.Features.Route;
[ApiController] [ApiController]
[Route("api/routes")] [Route("api/routes")]
public class RouteController(RouteService service) : ControllerBase public class RouteController(
RouteService service,
IScopeAccessService scopeAccess,
ICurrentUserService currentUser) : ControllerBase
{ {
[HttpGet] [HttpGet]
[Authorize("route.view")]
public async Task<IActionResult> GetAll() => public async Task<IActionResult> GetAll() =>
Ok(await service.GetAllAsync()); Ok(await service.GetAllAsync());
[HttpGet("{id:guid}")] [HttpGet("{id:guid}")]
[Authorize("route.view")]
public async Task<IActionResult> GetById(Guid id) public async Task<IActionResult> GetById(Guid id)
{ {
var userId = currentUser.UserId;
if (userId.HasValue && !await scopeAccess.HasRouteScopeAsync(userId.Value, id))
return StatusCode(403);
var result = await service.GetByIdAsync(id); var result = await service.GetByIdAsync(id);
return result is null ? NotFound() : Ok(result); return result is null ? NotFound() : Ok(result);
} }
[HttpPost] [HttpPost]
[Authorize("route.manage")]
public async Task<IActionResult> Create(CreateRouteRequest request, CancellationToken ct) public async Task<IActionResult> Create(CreateRouteRequest request, CancellationToken ct)
{ {
var result = await service.CreateAsync(request, ct); var result = await service.CreateAsync(request, ct);
@@ -25,6 +36,7 @@ public class RouteController(RouteService service) : ControllerBase
} }
[HttpPut("{id:guid}")] [HttpPut("{id:guid}")]
[Authorize("route.manage")]
public async Task<IActionResult> Update(Guid id, UpdateRouteRequest request, CancellationToken ct) public async Task<IActionResult> Update(Guid id, UpdateRouteRequest request, CancellationToken ct)
{ {
var result = await service.UpdateAsync(id, request, ct); var result = await service.UpdateAsync(id, request, ct);
@@ -32,6 +44,7 @@ public class RouteController(RouteService service) : ControllerBase
} }
[HttpPut("{id:guid}/region")] [HttpPut("{id:guid}/region")]
[Authorize("route.manage")]
public async Task<IActionResult> AssignToRegion(Guid id, AssignRouteToRegionRequest request, CancellationToken ct) public async Task<IActionResult> AssignToRegion(Guid id, AssignRouteToRegionRequest request, CancellationToken ct)
{ {
var result = await service.AssignToRegionAsync(id, request, ct); var result = await service.AssignToRegionAsync(id, request, ct);
@@ -39,6 +52,7 @@ public class RouteController(RouteService service) : ControllerBase
} }
[HttpDelete("{id:guid}")] [HttpDelete("{id:guid}")]
[Authorize("route.manage")]
public async Task<IActionResult> Delete(Guid id, CancellationToken ct) public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
{ {
var deleted = await service.DeleteAsync(id, ct); var deleted = await service.DeleteAsync(id, ct);
@@ -46,6 +60,7 @@ public class RouteController(RouteService service) : ControllerBase
} }
[HttpPost("{id:guid}/stores")] [HttpPost("{id:guid}/stores")]
[Authorize("route.manage")]
public async Task<IActionResult> AssignStores(Guid id, AssignStoresToRouteRequest request, CancellationToken ct) public async Task<IActionResult> AssignStores(Guid id, AssignStoresToRouteRequest request, CancellationToken ct)
{ {
var result = await service.AssignStoresToRouteAsync(id, request, ct); var result = await service.AssignStoresToRouteAsync(id, request, ct);
@@ -53,6 +68,7 @@ public class RouteController(RouteService service) : ControllerBase
} }
[HttpPut("{id:guid}/owner")] [HttpPut("{id:guid}/owner")]
[Authorize("route.manage")]
public async Task<IActionResult> AssignOwner(Guid id, AssignRouteOwnerRequest request, CancellationToken ct) public async Task<IActionResult> AssignOwner(Guid id, AssignRouteOwnerRequest request, CancellationToken ct)
{ {
var result = await service.AssignOwnerAsync(id, request, ct); var result = await service.AssignOwnerAsync(id, request, ct);
@@ -60,10 +76,12 @@ public class RouteController(RouteService service) : ControllerBase
} }
[HttpPost("{id:guid}/optimize")] [HttpPost("{id:guid}/optimize")]
[Authorize("route.manage")]
public IActionResult OptimizeSequence(Guid id) => public IActionResult OptimizeSequence(Guid id) =>
StatusCode(StatusCodes.Status501NotImplemented); StatusCode(StatusCodes.Status501NotImplemented);
[HttpPost("{id:guid}/visits/check-in")] [HttpPost("{id:guid}/visits/check-in")]
[Authorize("route.manage")]
public async Task<IActionResult> CheckIn(Guid id, RecordCheckInRequest request, CancellationToken ct) public async Task<IActionResult> CheckIn(Guid id, RecordCheckInRequest request, CancellationToken ct)
{ {
try try
@@ -75,6 +93,7 @@ public class RouteController(RouteService service) : ControllerBase
} }
[HttpPost("{id:guid}/visits/check-out")] [HttpPost("{id:guid}/visits/check-out")]
[Authorize("route.manage")]
public async Task<IActionResult> CheckOut(Guid id, RecordCheckOutRequest request, CancellationToken ct) public async Task<IActionResult> CheckOut(Guid id, RecordCheckOutRequest request, CancellationToken ct)
{ {
var result = await service.RecordCheckOutAsync(id, request, ct); var result = await service.RecordCheckOutAsync(id, request, ct);
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Distribution.Features.Scheme; namespace Distribution.Features.Scheme;
@@ -7,10 +8,12 @@ namespace Distribution.Features.Scheme;
public class SchemeController(SchemeService service) : ControllerBase public class SchemeController(SchemeService service) : ControllerBase
{ {
[HttpGet] [HttpGet]
[Authorize("scheme.view")]
public async Task<IActionResult> GetAll([FromQuery] Guid? regionId) => public async Task<IActionResult> GetAll([FromQuery] Guid? regionId) =>
Ok(await service.GetAllAsync(regionId)); Ok(await service.GetAllAsync(regionId));
[HttpGet("{id:guid}")] [HttpGet("{id:guid}")]
[Authorize("scheme.view")]
public async Task<IActionResult> GetById(Guid id) public async Task<IActionResult> GetById(Guid id)
{ {
var result = await service.GetByIdAsync(id); var result = await service.GetByIdAsync(id);
@@ -18,6 +21,7 @@ public class SchemeController(SchemeService service) : ControllerBase
} }
[HttpPost] [HttpPost]
[Authorize("scheme.manage")]
public async Task<IActionResult> Create(CreateSchemeRequest request, CancellationToken ct) public async Task<IActionResult> Create(CreateSchemeRequest request, CancellationToken ct)
{ {
try try
@@ -32,6 +36,7 @@ public class SchemeController(SchemeService service) : ControllerBase
} }
[HttpPut("{id:guid}")] [HttpPut("{id:guid}")]
[Authorize("scheme.manage")]
public async Task<IActionResult> Update(Guid id, UpdateSchemeRequest request, CancellationToken ct) public async Task<IActionResult> Update(Guid id, UpdateSchemeRequest request, CancellationToken ct)
{ {
try try
@@ -46,6 +51,7 @@ public class SchemeController(SchemeService service) : ControllerBase
} }
[HttpDelete("{id:guid}")] [HttpDelete("{id:guid}")]
[Authorize("scheme.manage")]
public async Task<IActionResult> Delete(Guid id, CancellationToken ct) public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
{ {
var deleted = await service.DeleteAsync(id, ct); var deleted = await service.DeleteAsync(id, ct);
@@ -53,6 +59,7 @@ public class SchemeController(SchemeService service) : ControllerBase
} }
[HttpPut("{id:guid}/free-goods-rule")] [HttpPut("{id:guid}/free-goods-rule")]
[Authorize("scheme.manage")]
public async Task<IActionResult> SetFreeGoodsRule(Guid id, SetFreeGoodsRuleRequest request, CancellationToken ct) public async Task<IActionResult> SetFreeGoodsRule(Guid id, SetFreeGoodsRuleRequest request, CancellationToken ct)
{ {
try try
@@ -67,6 +74,7 @@ public class SchemeController(SchemeService service) : ControllerBase
} }
[HttpDelete("{id:guid}/free-goods-rule")] [HttpDelete("{id:guid}/free-goods-rule")]
[Authorize("scheme.manage")]
public async Task<IActionResult> ClearFreeGoodsRule(Guid id, CancellationToken ct) public async Task<IActionResult> ClearFreeGoodsRule(Guid id, CancellationToken ct)
{ {
var result = await service.ClearFreeGoodsRuleAsync(id, ct); var result = await service.ClearFreeGoodsRuleAsync(id, ct);
@@ -74,6 +82,7 @@ public class SchemeController(SchemeService service) : ControllerBase
} }
[HttpPut("{id:guid}/bundle-components/{itemId:guid}")] [HttpPut("{id:guid}/bundle-components/{itemId:guid}")]
[Authorize("scheme.manage")]
public async Task<IActionResult> UpsertBundleComponent(Guid id, Guid itemId, UpsertBundleComponentRequest request, CancellationToken ct) public async Task<IActionResult> UpsertBundleComponent(Guid id, Guid itemId, UpsertBundleComponentRequest request, CancellationToken ct)
{ {
try try
@@ -88,6 +97,7 @@ public class SchemeController(SchemeService service) : ControllerBase
} }
[HttpDelete("{id:guid}/bundle-components/{itemId:guid}")] [HttpDelete("{id:guid}/bundle-components/{itemId:guid}")]
[Authorize("scheme.manage")]
public async Task<IActionResult> RemoveBundleComponent(Guid id, Guid itemId, CancellationToken ct) public async Task<IActionResult> RemoveBundleComponent(Guid id, Guid itemId, CancellationToken ct)
{ {
var result = await service.RemoveBundleComponentAsync(id, itemId, ct); var result = await service.RemoveBundleComponentAsync(id, itemId, ct);
@@ -95,6 +105,7 @@ public class SchemeController(SchemeService service) : ControllerBase
} }
[HttpGet("eligible")] [HttpGet("eligible")]
[Authorize("scheme.view")]
public async Task<IActionResult> GetEligible([FromQuery] Guid storeId, [FromQuery] Guid orderId) public async Task<IActionResult> GetEligible([FromQuery] Guid storeId, [FromQuery] Guid orderId)
{ {
var result = await service.EvaluateEligibilityAsync(storeId, orderId); var result = await service.EvaluateEligibilityAsync(storeId, orderId);
@@ -102,6 +113,7 @@ public class SchemeController(SchemeService service) : ControllerBase
} }
[HttpGet("{id:guid}/spend")] [HttpGet("{id:guid}/spend")]
[Authorize("scheme.view")]
public async Task<IActionResult> GetSpend(Guid id) public async Task<IActionResult> GetSpend(Guid id)
{ {
var result = await service.GetSpendAsync(id); var result = await service.GetSpendAsync(id);
@@ -109,6 +121,7 @@ public class SchemeController(SchemeService service) : ControllerBase
} }
[HttpGet("{id:guid}/roi")] [HttpGet("{id:guid}/roi")]
[Authorize("scheme.view")]
public async Task<IActionResult> GetROI(Guid id) public async Task<IActionResult> GetROI(Guid id)
{ {
var result = await service.GetROIAsync(id); var result = await service.GetROIAsync(id);
@@ -121,6 +134,7 @@ public class SchemeController(SchemeService service) : ControllerBase
public class SchemeOrderController(SchemeService service) : ControllerBase public class SchemeOrderController(SchemeService service) : ControllerBase
{ {
[HttpPost("{id:guid}/apply-scheme")] [HttpPost("{id:guid}/apply-scheme")]
[Authorize("scheme.manage")]
public async Task<IActionResult> ApplyScheme(Guid id, ApplySchemeRequest request, CancellationToken ct) public async Task<IActionResult> ApplyScheme(Guid id, ApplySchemeRequest request, CancellationToken ct)
{ {
try try
+14 -3
View File
@@ -1,5 +1,6 @@
using Distribution.Infra.Authorization; using Distribution.Infra.Authorization;
using Distribution.Models; using Distribution.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Distribution.Features.Stock; namespace Distribution.Features.Stock;
@@ -8,9 +9,10 @@ namespace Distribution.Features.Stock;
[Route("api/stock")] [Route("api/stock")]
public class StockController(StockService service, ICurrentUserService currentUser) : ControllerBase public class StockController(StockService service, ICurrentUserService currentUser) : ControllerBase
{ {
// ── Query ────────────────────────────────────────────────────────────── // ── Query ──────────────────────────────────────────────────────────────────
[HttpGet("balances")] [HttpGet("balances")]
[Authorize("stock.view")]
public async Task<IActionResult> GetBalances( public async Task<IActionResult> GetBalances(
[FromQuery] Guid? locationId, [FromQuery] Guid? locationId,
[FromQuery] LocationType? locationType, [FromQuery] LocationType? locationType,
@@ -23,6 +25,7 @@ public class StockController(StockService service, ICurrentUserService currentUs
} }
[HttpGet("low-stock")] [HttpGet("low-stock")]
[Authorize("stock.view")]
public async Task<IActionResult> GetLowStock([FromQuery] Guid? locationId) public async Task<IActionResult> GetLowStock([FromQuery] Guid? locationId)
{ {
var result = await service.GetLowStockAsync(locationId); var result = await service.GetLowStockAsync(locationId);
@@ -30,6 +33,7 @@ public class StockController(StockService service, ICurrentUserService currentUs
} }
[HttpGet("balances/{itemId}/total")] [HttpGet("balances/{itemId}/total")]
[Authorize("stock.view")]
public async Task<IActionResult> GetItemTotal(Guid itemId) public async Task<IActionResult> GetItemTotal(Guid itemId)
{ {
var result = await service.GetItemTotalAsync(itemId); var result = await service.GetItemTotalAsync(itemId);
@@ -39,6 +43,7 @@ public class StockController(StockService service, ICurrentUserService currentUs
/// <summary>Next free number for auto-generated serials (e.g. after ...-0005 the answer is 6).</summary> /// <summary>Next free number for auto-generated serials (e.g. after ...-0005 the answer is 6).</summary>
[HttpGet("serials/next-sequence")] [HttpGet("serials/next-sequence")]
[Authorize("stock.view")]
public async Task<IActionResult> GetNextSerialSequence([FromQuery] Guid itemId, [FromQuery] string prefix = "") public async Task<IActionResult> GetNextSerialSequence([FromQuery] Guid itemId, [FromQuery] string prefix = "")
{ {
var next = await service.GetNextSerialSequenceAsync(itemId, prefix); var next = await service.GetNextSerialSequenceAsync(itemId, prefix);
@@ -46,6 +51,7 @@ public class StockController(StockService service, ICurrentUserService currentUs
} }
[HttpGet("movements")] [HttpGet("movements")]
[Authorize("stock.view")]
public async Task<IActionResult> GetMovements( public async Task<IActionResult> GetMovements(
[FromQuery] Guid? locationId, [FromQuery] Guid? locationId,
[FromQuery] Guid? itemId, [FromQuery] Guid? itemId,
@@ -59,9 +65,10 @@ public class StockController(StockService service, ICurrentUserService currentUs
return Ok(result); return Ok(result);
} }
// ── Write ────────────────────────────────────────────────────────────── // ── Write ──────────────────────────────────────────────────────────────────
[HttpPost("transfer")] [HttpPost("transfer")]
[Authorize("stock.manage")]
public async Task<IActionResult> Transfer(TransferRequest request, CancellationToken ct) public async Task<IActionResult> Transfer(TransferRequest request, CancellationToken ct)
{ {
if (currentUser.UserId is null) return Unauthorized(); if (currentUser.UserId is null) return Unauthorized();
@@ -74,6 +81,7 @@ public class StockController(StockService service, ICurrentUserService currentUs
} }
[HttpPost("damage")] [HttpPost("damage")]
[Authorize("stock.manage")]
public async Task<IActionResult> RecordDamage(DamageRequest request, CancellationToken ct) public async Task<IActionResult> RecordDamage(DamageRequest request, CancellationToken ct)
{ {
if (currentUser.UserId is null) return Unauthorized(); if (currentUser.UserId is null) return Unauthorized();
@@ -86,6 +94,7 @@ public class StockController(StockService service, ICurrentUserService currentUs
} }
[HttpPost("customer-return")] [HttpPost("customer-return")]
[Authorize("stock.manage")]
public async Task<IActionResult> RecordCustomerReturn(CustomerReturnRequest request, CancellationToken ct) public async Task<IActionResult> RecordCustomerReturn(CustomerReturnRequest request, CancellationToken ct)
{ {
if (currentUser.UserId is null) return Unauthorized(); if (currentUser.UserId is null) return Unauthorized();
@@ -98,6 +107,7 @@ public class StockController(StockService service, ICurrentUserService currentUs
} }
[HttpPost("adjustment")] [HttpPost("adjustment")]
[Authorize("stock.manage")]
public async Task<IActionResult> Adjust(AdjustmentRequest request, CancellationToken ct) public async Task<IActionResult> Adjust(AdjustmentRequest request, CancellationToken ct)
{ {
// TEMPORARY: currentUser.UserId is always unset due to the broken auth middleware // TEMPORARY: currentUser.UserId is always unset due to the broken auth middleware
@@ -113,6 +123,7 @@ public class StockController(StockService service, ICurrentUserService currentUs
} }
[HttpPatch("movements/{id}/reason")] [HttpPatch("movements/{id}/reason")]
[Authorize("stock.manage")]
public async Task<IActionResult> UpdateMovementReason(Guid id, UpdateMovementReasonRequest request, CancellationToken ct) public async Task<IActionResult> UpdateMovementReason(Guid id, UpdateMovementReasonRequest request, CancellationToken ct)
{ {
try try
+23 -2
View File
@@ -1,13 +1,19 @@
using Distribution.Models; using Distribution.Infra.Authorization;
using Distribution.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Distribution.Features.Store; namespace Distribution.Features.Store;
[ApiController] [ApiController]
[Route("api/stores")] [Route("api/stores")]
public class StoreController(StoreService service) : ControllerBase public class StoreController(
StoreService service,
IScopeAccessService scopeAccess,
ICurrentUserService currentUser) : ControllerBase
{ {
[HttpGet] [HttpGet]
[Authorize("store.view")]
public async Task<IActionResult> GetAll( public async Task<IActionResult> GetAll(
[FromQuery] Guid? routeId, [FromQuery] Guid? routeId,
[FromQuery] string? search, [FromQuery] string? search,
@@ -16,13 +22,18 @@ public class StoreController(StoreService service) : ControllerBase
Ok(await service.GetAllAsync(routeId, search, page, pageSize)); Ok(await service.GetAllAsync(routeId, search, page, pageSize));
[HttpGet("{id:guid}")] [HttpGet("{id:guid}")]
[Authorize("store.view")]
public async Task<IActionResult> GetById(Guid id) public async Task<IActionResult> GetById(Guid id)
{ {
var userId = currentUser.UserId;
if (userId.HasValue && !await scopeAccess.HasStoreScopeAsync(userId.Value, id))
return StatusCode(403);
var result = await service.GetByIdAsync(id); var result = await service.GetByIdAsync(id);
return result is null ? NotFound() : Ok(result); return result is null ? NotFound() : Ok(result);
} }
[HttpPost] [HttpPost]
[Authorize("store.manage")]
public async Task<IActionResult> Create(CreateStoreRequest request, CancellationToken ct) public async Task<IActionResult> Create(CreateStoreRequest request, CancellationToken ct)
{ {
var result = await service.CreateAsync(request, ct); var result = await service.CreateAsync(request, ct);
@@ -30,6 +41,7 @@ public class StoreController(StoreService service) : ControllerBase
} }
[HttpPut("{id:guid}")] [HttpPut("{id:guid}")]
[Authorize("store.manage")]
public async Task<IActionResult> Update(Guid id, UpdateStoreRequest request, CancellationToken ct) public async Task<IActionResult> Update(Guid id, UpdateStoreRequest request, CancellationToken ct)
{ {
var result = await service.UpdateAsync(id, request, ct); var result = await service.UpdateAsync(id, request, ct);
@@ -37,6 +49,7 @@ public class StoreController(StoreService service) : ControllerBase
} }
[HttpDelete("{id:guid}")] [HttpDelete("{id:guid}")]
[Authorize("store.manage")]
public async Task<IActionResult> Delete(Guid id, CancellationToken ct) public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
{ {
var deleted = await service.DeleteAsync(id, ct); var deleted = await service.DeleteAsync(id, ct);
@@ -44,6 +57,7 @@ public class StoreController(StoreService service) : ControllerBase
} }
[HttpPut("{id:guid}/credit-limit")] [HttpPut("{id:guid}/credit-limit")]
[Authorize("store.manage")]
public async Task<IActionResult> UpdateCreditLimit(Guid id, UpdateCreditLimitRequest request, CancellationToken ct) public async Task<IActionResult> UpdateCreditLimit(Guid id, UpdateCreditLimitRequest request, CancellationToken ct)
{ {
var result = await service.UpdateCreditLimitAsync(id, request, ct); var result = await service.UpdateCreditLimitAsync(id, request, ct);
@@ -51,6 +65,7 @@ public class StoreController(StoreService service) : ControllerBase
} }
[HttpPut("{id:guid}/outstanding-balance")] [HttpPut("{id:guid}/outstanding-balance")]
[Authorize("store.manage")]
public async Task<IActionResult> UpdateOutstandingBalance(Guid id, UpdateOutstandingBalanceRequest request, CancellationToken ct) public async Task<IActionResult> UpdateOutstandingBalance(Guid id, UpdateOutstandingBalanceRequest request, CancellationToken ct)
{ {
var result = await service.UpdateOutstandingBalanceAsync(id, request, ct); var result = await service.UpdateOutstandingBalanceAsync(id, request, ct);
@@ -58,6 +73,7 @@ public class StoreController(StoreService service) : ControllerBase
} }
[HttpGet("{id:guid}/outstanding-balance")] [HttpGet("{id:guid}/outstanding-balance")]
[Authorize("store.view")]
public async Task<IActionResult> GetOutstandingBalance(Guid id) public async Task<IActionResult> GetOutstandingBalance(Guid id)
{ {
var result = await service.GetOutstandingBalanceAsync(id); var result = await service.GetOutstandingBalanceAsync(id);
@@ -65,6 +81,7 @@ public class StoreController(StoreService service) : ControllerBase
} }
[HttpPut("{id:guid}/segment")] [HttpPut("{id:guid}/segment")]
[Authorize("store.manage")]
public async Task<IActionResult> ClassifySegment(Guid id, ClassifySegmentRequest request, CancellationToken ct) public async Task<IActionResult> ClassifySegment(Guid id, ClassifySegmentRequest request, CancellationToken ct)
{ {
var result = await service.ClassifySegmentAsync(id, request, ct); var result = await service.ClassifySegmentAsync(id, request, ct);
@@ -72,6 +89,7 @@ public class StoreController(StoreService service) : ControllerBase
} }
[HttpGet("{id:guid}/visit-history")] [HttpGet("{id:guid}/visit-history")]
[Authorize("store.view")]
public async Task<IActionResult> GetVisitHistory(Guid id) public async Task<IActionResult> GetVisitHistory(Guid id)
{ {
var result = await service.GetVisitHistoryAsync(id); var result = await service.GetVisitHistoryAsync(id);
@@ -79,6 +97,7 @@ public class StoreController(StoreService service) : ControllerBase
} }
[HttpGet("{id:guid}/schemes/{schemeId:guid}/eligibility")] [HttpGet("{id:guid}/schemes/{schemeId:guid}/eligibility")]
[Authorize("store.view")]
public async Task<IActionResult> CheckSchemeEligibility(Guid id, Guid schemeId) public async Task<IActionResult> CheckSchemeEligibility(Guid id, Guid schemeId)
{ {
var result = await service.CheckSchemeEligibilityAsync(id, schemeId); var result = await service.CheckSchemeEligibilityAsync(id, schemeId);
@@ -86,6 +105,7 @@ public class StoreController(StoreService service) : ControllerBase
} }
[HttpGet("{id:guid}/dashboard")] [HttpGet("{id:guid}/dashboard")]
[Authorize("store.view")]
public async Task<IActionResult> GetDashboard(Guid id, [FromQuery] string period) public async Task<IActionResult> GetDashboard(Guid id, [FromQuery] string period)
{ {
var result = await service.GetDashboardAsync(id, period); var result = await service.GetDashboardAsync(id, period);
@@ -93,6 +113,7 @@ public class StoreController(StoreService service) : ControllerBase
} }
[HttpPatch("{id:guid}/status")] [HttpPatch("{id:guid}/status")]
[Authorize("store.manage")]
public async Task<IActionResult> PatchStatus(Guid id, PatchStoreStatusRequest request, CancellationToken ct) public async Task<IActionResult> PatchStatus(Guid id, PatchStoreStatusRequest request, CancellationToken ct)
{ {
var result = await service.SetActiveStatusAsync(id, request.IsActive, ct); var result = await service.SetActiveStatusAsync(id, request.IsActive, ct);
@@ -1,4 +1,5 @@
using Distribution.Infra.Authorization; using Distribution.Infra.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Distribution.Features.SupplierClaims; namespace Distribution.Features.SupplierClaims;
@@ -7,10 +8,12 @@ namespace Distribution.Features.SupplierClaims;
public class SupplierClaimController(SupplierClaimService service, ICurrentUserService currentUser) : ControllerBase public class SupplierClaimController(SupplierClaimService service, ICurrentUserService currentUser) : ControllerBase
{ {
[HttpGet("api/supplier-claims")] [HttpGet("api/supplier-claims")]
[Authorize("supplier-claim.view")]
public async Task<IActionResult> GetAll() => public async Task<IActionResult> GetAll() =>
Ok(await service.GetAllAsync()); Ok(await service.GetAllAsync());
[HttpGet("api/supplier-claims/{id:guid}")] [HttpGet("api/supplier-claims/{id:guid}")]
[Authorize("supplier-claim.view")]
public async Task<IActionResult> GetById(Guid id) public async Task<IActionResult> GetById(Guid id)
{ {
var result = await service.GetByIdAsync(id); var result = await service.GetByIdAsync(id);
@@ -18,10 +21,12 @@ public class SupplierClaimController(SupplierClaimService service, ICurrentUserS
} }
[HttpGet("api/purchase-orders/{id:guid}/claims")] [HttpGet("api/purchase-orders/{id:guid}/claims")]
[Authorize("supplier-claim.view")]
public async Task<IActionResult> GetByPurchaseOrder(Guid id) => public async Task<IActionResult> GetByPurchaseOrder(Guid id) =>
Ok(await service.GetByPurchaseOrderIdAsync(id)); Ok(await service.GetByPurchaseOrderIdAsync(id));
[HttpPost("api/purchase-orders/{id:guid}/claims")] [HttpPost("api/purchase-orders/{id:guid}/claims")]
[Authorize("supplier-claim.manage")]
public async Task<IActionResult> Create(Guid id, CreateSupplierClaimRequest request, CancellationToken ct) public async Task<IActionResult> Create(Guid id, CreateSupplierClaimRequest request, CancellationToken ct)
{ {
// TEMPORARY: currentUser.UserId is always unset due to the broken auth middleware // TEMPORARY: currentUser.UserId is always unset due to the broken auth middleware
@@ -37,6 +42,7 @@ public class SupplierClaimController(SupplierClaimService service, ICurrentUserS
} }
[HttpPut("api/supplier-claims/{id:guid}")] [HttpPut("api/supplier-claims/{id:guid}")]
[Authorize("supplier-claim.manage")]
public async Task<IActionResult> Update(Guid id, UpdateSupplierClaimRequest request, CancellationToken ct) public async Task<IActionResult> Update(Guid id, UpdateSupplierClaimRequest request, CancellationToken ct)
{ {
try try
@@ -48,6 +54,7 @@ public class SupplierClaimController(SupplierClaimService service, ICurrentUserS
} }
[HttpPost("api/supplier-claims/{id:guid}/approve")] [HttpPost("api/supplier-claims/{id:guid}/approve")]
[Authorize("supplier-claim.manage")]
public async Task<IActionResult> Approve(Guid id, ApproveSupplierClaimRequest request, CancellationToken ct) public async Task<IActionResult> Approve(Guid id, ApproveSupplierClaimRequest request, CancellationToken ct)
{ {
var userId = currentUser.UserId ?? request.ApprovedByUserId; var userId = currentUser.UserId ?? request.ApprovedByUserId;
@@ -62,6 +69,7 @@ public class SupplierClaimController(SupplierClaimService service, ICurrentUserS
} }
[HttpPost("api/supplier-claims/{id:guid}/reject")] [HttpPost("api/supplier-claims/{id:guid}/reject")]
[Authorize("supplier-claim.manage")]
public async Task<IActionResult> Reject(Guid id, RejectSupplierClaimRequest request, CancellationToken ct) public async Task<IActionResult> Reject(Guid id, RejectSupplierClaimRequest request, CancellationToken ct)
{ {
var userId = currentUser.UserId ?? request.RejectedByUserId; var userId = currentUser.UserId ?? request.RejectedByUserId;
@@ -1,5 +1,6 @@
using Distribution.Infra.Authorization; using Distribution.Infra.Authorization;
using Distribution.Models; using Distribution.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Distribution.Features.SysConfig; namespace Distribution.Features.SysConfig;
@@ -9,11 +10,12 @@ namespace Distribution.Features.SysConfig;
public class SysConfigController(SysConfigService service, ICurrentUserService currentUser) : ControllerBase public class SysConfigController(SysConfigService service, ICurrentUserService currentUser) : ControllerBase
{ {
[HttpGet] [HttpGet]
[Authorize("sys-config.view")]
public async Task<IActionResult> GetAll() => public async Task<IActionResult> GetAll() =>
Ok(await service.GetAllAsync()); Ok(await service.GetAllAsync());
// Typed shortcut — must be declared before {key} to take precedence
[HttpGet("invoice-creation-mode")] [HttpGet("invoice-creation-mode")]
[Authorize("sys-config.view")]
public async Task<IActionResult> GetInvoiceCreationMode() public async Task<IActionResult> GetInvoiceCreationMode()
{ {
var mode = await service.GetInvoiceCreationModeAsync(); var mode = await service.GetInvoiceCreationModeAsync();
@@ -21,6 +23,7 @@ public class SysConfigController(SysConfigService service, ICurrentUserService c
} }
[HttpPut("invoice-creation-mode")] [HttpPut("invoice-creation-mode")]
[Authorize("sys-config.manage")]
public async Task<IActionResult> SetInvoiceCreationMode(SetInvoiceCreationModeRequest request, CancellationToken ct) public async Task<IActionResult> SetInvoiceCreationMode(SetInvoiceCreationModeRequest request, CancellationToken ct)
{ {
var userId = currentUser.UserId ?? throw new UnauthorizedAccessException(); var userId = currentUser.UserId ?? throw new UnauthorizedAccessException();
@@ -33,6 +36,7 @@ public class SysConfigController(SysConfigService service, ICurrentUserService c
} }
[HttpGet("{key}")] [HttpGet("{key}")]
[Authorize("sys-config.view")]
public async Task<IActionResult> GetByKey(string key) public async Task<IActionResult> GetByKey(string key)
{ {
var result = await service.GetByKeyAsync(key); var result = await service.GetByKeyAsync(key);
@@ -40,6 +44,7 @@ public class SysConfigController(SysConfigService service, ICurrentUserService c
} }
[HttpPut("{key}")] [HttpPut("{key}")]
[Authorize("sys-config.manage")]
public async Task<IActionResult> Set(string key, SetSysConfigRequest request, CancellationToken ct) public async Task<IActionResult> Set(string key, SetSysConfigRequest request, CancellationToken ct)
{ {
var userId = currentUser.UserId ?? request.UserId; var userId = currentUser.UserId ?? request.UserId;
@@ -1,23 +1,24 @@
using Microsoft.AspNetCore.Authorization;
//namespace Distribution.Infra.Authorization;
//public class PermissionAuthorizationHandler : AuthorizationHandler<PermissionRequirement> namespace Distribution.Infra.Authorization;
//{
// private readonly IPermissionService _permissionService;
// public PermissionAuthorizationHandler(IPermissionService permissionService) public class PermissionAuthorizationHandler : AuthorizationHandler<PermissionRequirement>
// { {
// _permissionService = permissionService; private readonly IPermissionService _permissionService;
// }
// protected override async Task HandleRequirementAsync( public PermissionAuthorizationHandler(IPermissionService permissionService)
// AuthorizationHandlerContext context, PermissionRequirement requirement) {
// { _permissionService = permissionService;
// var roleIdClaim = context.User.FindFirst("role_id")?.Value; }
// if (!Guid.TryParse(roleIdClaim, out var roleId))
// return;
// if (await _permissionService.HasPermissionAsync(roleId, requirement.PermissionCode)) protected override async Task HandleRequirementAsync(
// context.Succeed(requirement); AuthorizationHandlerContext context, PermissionRequirement requirement)
// } {
//} var roleIdClaim = context.User.FindFirst("role_id")?.Value;
if (!Guid.TryParse(roleIdClaim, out var roleId))
return;
if (await _permissionService.HasPermissionAsync(roleId, requirement.PermissionCode))
context.Succeed(requirement);
}
}
@@ -1,31 +1,32 @@
//using Microsoft.Extensions.Options; using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
//namespace Distribution.Infra.Authorization; namespace Distribution.Infra.Authorization;
//public class PermissionPolicyProvider : IAuthorizationPolicyProvider public class PermissionPolicyProvider : IAuthorizationPolicyProvider
//{ {
// private readonly DefaultAuthorizationPolicyProvider _fallback; private readonly DefaultAuthorizationPolicyProvider _fallback;
// public PermissionPolicyProvider(IOptions<AuthorizationOptions> options) public PermissionPolicyProvider(IOptions<AuthorizationOptions> options)
// { {
// _fallback = new DefaultAuthorizationPolicyProvider(options); _fallback = new DefaultAuthorizationPolicyProvider(options);
// } }
// public Task<AuthorizationPolicy> GetDefaultPolicyAsync() => _fallback.GetDefaultPolicyAsync(); public Task<AuthorizationPolicy> GetDefaultPolicyAsync() => _fallback.GetDefaultPolicyAsync();
// public Task<AuthorizationPolicy?> GetFallbackPolicyAsync() => _fallback.GetFallbackPolicyAsync(); public Task<AuthorizationPolicy?> GetFallbackPolicyAsync() => _fallback.GetFallbackPolicyAsync();
// public Task<AuthorizationPolicy?> GetPolicyAsync(string policyName) public Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
// { {
// if (policyName.Contains('.')) if (policyName.Contains('.'))
// { {
// var policy = new AuthorizationPolicyBuilder() var policy = new AuthorizationPolicyBuilder()
// .RequireAuthenticatedUser() .RequireAuthenticatedUser()
// .AddRequirements(new PermissionRequirement(policyName)) .AddRequirements(new PermissionRequirement(policyName))
// .Build(); .Build();
// return Task.FromResult<AuthorizationPolicy?>(policy); return Task.FromResult<AuthorizationPolicy?>(policy);
// } }
// return _fallback.GetPolicyAsync(policyName); return _fallback.GetPolicyAsync(policyName);
// } }
//} }
@@ -1,12 +1,13 @@
using Microsoft.AspNetCore.Authorization;
//namespace Distribution.Infra.Authorization;
//public class PermissionRequirement : IAuthorizationRequirement namespace Distribution.Infra.Authorization;
//{
// public string PermissionCode { get; }
// public PermissionRequirement(string permissionCode) public class PermissionRequirement : IAuthorizationRequirement
// { {
// PermissionCode = permissionCode; public string PermissionCode { get; }
// }
//} public PermissionRequirement(string permissionCode)
{
PermissionCode = permissionCode;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,22 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Distribution.Migrations
{
/// <inheritdoc />
public partial class SeedPermissionsAndRolePermissions : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}
+13 -2
View File
@@ -36,6 +36,8 @@ using Distribution.Features.SysConfig;
using Distribution.Features.Warehouse; using Distribution.Features.Warehouse;
using Distribution.Infra.Authorization; using Distribution.Infra.Authorization;
using Distribution.Infra.UoW; using Distribution.Infra.UoW;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
@@ -126,6 +128,9 @@ builder.Services.AddScoped<IPermissionRepository, PermissionRepository>();
builder.Services.AddScoped<IScopeRepository, ScopeRepository>(); builder.Services.AddScoped<IScopeRepository, ScopeRepository>();
builder.Services.AddScoped<IPermissionService, PermissionService>(); builder.Services.AddScoped<IPermissionService, PermissionService>();
builder.Services.AddScoped<IScopeAccessService, ScopeAccessService>(); builder.Services.AddScoped<IScopeAccessService, ScopeAccessService>();
builder.Services.AddAuthorization();
builder.Services.AddSingleton<IAuthorizationPolicyProvider, PermissionPolicyProvider>();
builder.Services.AddScoped<IAuthorizationHandler, PermissionAuthorizationHandler>();
// ── Auth Service connector ─────────────────────────────────────────────────── // ── Auth Service connector ───────────────────────────────────────────────────
builder.Services.Configure<AuthServiceOptions>( builder.Services.Configure<AuthServiceOptions>(
builder.Configuration.GetSection(AuthServiceOptions.SectionName)); builder.Configuration.GetSection(AuthServiceOptions.SectionName));
@@ -147,8 +152,12 @@ builder.Services.AddCors(options =>
.AllowAnyHeader() .AllowAnyHeader()
.AllowAnyMethod())); .AllowAnyMethod()));
builder.Services.AddControllers() builder.Services.AddControllers(options =>
.AddJsonOptions(options => options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter())); {
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
options.Filters.Add(new AuthorizeFilter(policy));
})
.AddJsonOptions(options => options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddEndpointsApiExplorer();
builder.Services.AddOpenApi(); builder.Services.AddOpenApi();
builder.Services.AddSwaggerGen(); builder.Services.AddSwaggerGen();
@@ -164,6 +173,8 @@ if (app.Environment.IsDevelopment())
//app.UseHttpsRedirection(); //app.UseHttpsRedirection();
app.UseCors(); app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<AuthMiddleware>(); app.UseMiddleware<AuthMiddleware>();
app.MapControllers(); app.MapControllers();