Compare commits

...

16 Commits

Author SHA1 Message Date
6ec76fc975 devops: added dockerfile and other configs 2025-09-01 10:18:35 -06:00
OscarMmtz
1c193b68bb Merge pull request 'Add physical delete' (#6) from feature/add-physical-delete into development
Reviewed-on: https://gitea.white-enciso.pro/AgileWebs/Core.Inventory.BFF/pulls/6
Reviewed-by: efrain_marin <efrain.marin@agilewebs.com>
Reviewed-by: Sergio Matías <sergio.matias@agilewebs.com>
2025-08-08 21:10:13 +00:00
Oscar Morales
d4d0a4d2d1 Add physical delete 2025-08-08 11:13:46 -06:00
efrain_marin
cf957eb3e0 Merge pull request 'feat: added endpoint DeleteProduct (BFF)' (#5) from feature/create-Product-and-ProductTag-CRUD into development
Reviewed-on: https://gitea.white-enciso.pro/AgileWebs/Core.Inventory.BFF/pulls/5
Reviewed-by: Sergio Matías <sergio.matias@agilewebs.com>
Reviewed-by: OscarMmtz <oscar.morales@agilewebs.com>
2025-08-07 22:12:05 +00:00
Efrain Marin
bed3202892 feat: added endpoint DeleteProduct
- feat: Added Product controller and endpoints
- feat: package updated
2025-08-06 18:11:19 -06:00
OscarMmtz
6826319089 Merge pull request 'Add TagOverride CRUD' (#4) from feature/add-tag-override-crud into development
Reviewed-on: https://gitea.white-enciso.pro/AgileWebs/Core.Inventory.BFF/pulls/4
Reviewed-by: Sergio Matías <sergio.matias@agilewebs.com>
Reviewed-by: efrain_marin <efrain.marin@agilewebs.com>
2025-08-06 17:46:35 +00:00
Oscar Morales
b4fbee2989 Add TagOverride CRUD 2025-08-05 12:32:19 -06:00
efrain_marin
e1a97514af Merge pull request 'feat: Added Product controller and endpoints (BFF)' (#3) from feature/create-Product-and-ProductTag-CRUD into development
Reviewed-on: https://gitea.white-enciso.pro/AgileWebs/Core.Inventory.BFF/pulls/3
Reviewed-by: Sergio Matías <sergio.matias@agilewebs.com>
Reviewed-by: OscarMmtz <oscar.morales@agilewebs.com>
2025-08-05 16:14:43 +00:00
Efrain Marin
f31ec86352 feat: Added Product controller and endpoints
- updated Core.Adapters.Lib package version
2025-08-03 20:29:16 -06:00
OscarMmtz
11d1d21f3a Merge pull request 'Add Tag CRUD' (#2) from feature/add-tag-crud into development
Reviewed-on: https://gitea.white-enciso.pro/AgileWebs/Core.Inventory.BFF/pulls/2
Reviewed-by: Sergio Matías <sergio.matias@agilewebs.com>
2025-08-01 22:12:09 +00:00
Oscar Morales
b9a38fbdcb Add Tag CRUD 2025-08-01 11:45:37 -06:00
OscarMmtz
07a521ac17 Merge pull request 'Add TagType CRUD' (#1) from feature/add-tag-type-crud into development
Reviewed-on: https://gitea.white-enciso.pro/AgileWebs/Core.Inventory.BFF/pulls/1
Reviewed-by: Sergio Matías <sergio.matias@agilewebs.com>
2025-08-01 14:46:45 +00:00
Oscar Morales
93d15861a1 Add TagType CRUD 2025-07-31 19:08:07 -06:00
Ignacio Gomez
977aa577cc Final fixes for demo 2025-06-27 23:11:23 -06:00
Ignacio Gomez
15d0d24313 Added new endpoint for variants GetAll 2025-06-27 18:11:21 -06:00
Ignacio Gomez
3e8100e1c5 First version of BFF 2025-06-23 01:55:17 -06:00
68 changed files with 2441 additions and 61 deletions

12
.dockerignore Normal file
View File

@ -0,0 +1,12 @@
**/bin
**/obj
**/out
**/.vs
**/.idea
**/.git
**/.gitignore
**/node_modules
*.user
*.swp
*.swo
.DS_Store

View File

@ -0,0 +1,49 @@

using Lib.Architecture.BuildingBlocks;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Refit;
namespace Core.Inventory.BFF.API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class BaseController(ILogger<BaseController> logger) : ControllerBase
{
private readonly ILogger<BaseController> _logger = logger;
protected Guid TrackingId => (Guid)(HttpContext.Items["TrackingId"] ?? Guid.NewGuid());
protected async Task<IActionResult> Handle<T>(Func<Task<ApiResponse<T>>> apiCall) where T : class
{
var response = await apiCall().ConfigureAwait(false);
_logger.LogInformation($"{TrackingId} - {response.RequestMessage?.Method} {response.RequestMessage?.RequestUri} - Status: {response.StatusCode}");
return FromAPIResponse(response);
}
private IActionResult FromAPIResponse<T>(ApiResponse<T> response) where T : class
{
if (response.IsSuccessful)
return StatusCode((int)response.StatusCode, response.Content);
else
{
dynamic errorContent = string.Empty;
try
{
errorContent = JsonConvert.DeserializeObject<string>(response.Error?.Content ?? string.Empty) ?? string.Empty;
}
catch (Exception)
{
errorContent = JsonConvert.DeserializeObject<HttpError>(response.Error?.Content);
if (errorContent?.Error?.ErrorCode is null && errorContent?.Error?.Message is null && errorContent?.Error?.Target is null)
errorContent = JsonConvert.DeserializeObject<GenericErrorResponse>(response.Error?.Content);
}
return StatusCode((int)response.StatusCode, errorContent);
}
}
}
}

View File

@ -0,0 +1,142 @@
using Asp.Versioning;
using Core.Adapters.Lib;
using Core.Inventory.External.Clients.Inventory;
using Core.Inventory.External.Clients.Inventory.Requests.Base;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
namespace Core.Inventory.BFF.API.Controllers
{
/// <summary>
/// Handles all requests for furniture base operations.
/// </summary>
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
[Consumes("application/json")]
[Produces("application/json")]
public class FurnitureBaseController(IInventoryServiceClient inventoryClient, ILogger<FurnitureBaseController> logger) : BaseController(logger)
{
/// <summary>
/// Gets all furniture base records.
/// </summary>
[HttpGet("GetAll")]
[ProducesResponseType(typeof(IEnumerable<FurnitureBase>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetAllBaseAsync(CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(GetAllBaseAsync)} - Request received.");
return await Handle(() => inventoryClient.GetAllBaseAsync(TrackingId.ToString(), cancellationToken));
}
catch (Exception ex)
{
logger.LogError(ex, $"{nameof(GetAllBaseAsync)} - An error occurred.");
throw;
}
}
/// <summary>
/// Gets a furniture base by its identifier.
/// </summary>
[HttpPost("GetById")]
[ProducesResponseType(typeof(FurnitureBase), StatusCodes.Status200OK)]
public async Task<IActionResult> GetByIdAsync([FromBody] GetFurnitureBaseByIdRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(GetByIdAsync)} - Request received. Payload: {JsonSerializer.Serialize(request)}");
if (string.IsNullOrWhiteSpace(request.MongoId))
return BadRequest("FurnitureBase MongoId is required.");
return await Handle(() => inventoryClient.GetByIdAsync(TrackingId.ToString(), request, cancellationToken));
}
catch (Exception ex)
{
logger.LogError(ex, $"{nameof(GetByIdAsync)} - An error occurred. Payload: {JsonSerializer.Serialize(request)}");
throw;
}
}
/// <summary>
/// Creates a new furniture base record.
/// </summary>
[HttpPost("Create")]
[ProducesResponseType(typeof(FurnitureBase), StatusCodes.Status201Created)]
public async Task<IActionResult> CreateAsync([FromBody] CreateFurnitureBaseRequest newFurniture, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(CreateAsync)} - Request received. Payload: {JsonSerializer.Serialize(newFurniture)}");
if (newFurniture == null) return BadRequest("Invalid furniture object");
if (string.IsNullOrEmpty(newFurniture.ModelName)) return BadRequest("Invalid furniture name");
if (string.IsNullOrEmpty(newFurniture.Material)) return BadRequest("Invalid furniture material");
if (string.IsNullOrEmpty(newFurniture.Condition)) return BadRequest("Invalid furniture condition");
return await Handle(() => inventoryClient.CreateAsync(TrackingId.ToString(), newFurniture, cancellationToken));
}
catch (Exception ex)
{
logger.LogError(ex, $"{nameof(CreateAsync)} - An error occurred. Payload: {JsonSerializer.Serialize(newFurniture)}");
throw;
}
}
/// <summary>
/// Updates a furniture base record.
/// </summary>
[HttpPut("Update")]
[ProducesResponseType(typeof(FurnitureBase), StatusCodes.Status200OK)]
public async Task<IActionResult> UpdateAsync([FromBody] UpdateFurnitureBaseRequest newFurniture, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(UpdateAsync)} - Request received. Payload: {JsonSerializer.Serialize(newFurniture)}");
if (newFurniture == null) return BadRequest("Invalid furniture object");
if (string.IsNullOrEmpty(newFurniture.ModelName)) return BadRequest("Invalid furniture model name");
if (string.IsNullOrEmpty(newFurniture.Material)) return BadRequest("Invalid furniture material");
if (string.IsNullOrEmpty(newFurniture.Condition)) return BadRequest("Invalid furniture condition");
if (string.IsNullOrWhiteSpace(newFurniture.Id)) return BadRequest("Id is required.");
return await Handle(() => inventoryClient.UpdateFurnitureBaseAsync(TrackingId.ToString(), newFurniture, cancellationToken));
}
catch (Exception ex)
{
logger.LogError(ex, $"{nameof(UpdateAsync)} - An error occurred. Payload: {JsonSerializer.Serialize(newFurniture)}");
throw;
}
}
/// <summary>
/// Changes the status of a furniture base.
/// </summary>
[HttpPatch("ChangeStatus")]
[ProducesResponseType(typeof(FurnitureBase), StatusCodes.Status200OK)]
public async Task<IActionResult> ChangeStatusAsync([FromBody] ChangeFurnitureBaseStatusRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(ChangeStatusAsync)} - Request received. Payload: {JsonSerializer.Serialize(request)}");
if (string.IsNullOrWhiteSpace(request.MongoId)) return BadRequest("Id is required.");
return await Handle(() => inventoryClient.ChangeFurnitureBaseStatusAsync(TrackingId.ToString(), request, cancellationToken));
}
catch (Exception ex)
{
logger.LogError(ex, $"{nameof(ChangeStatusAsync)} - An error occurred. Payload: {JsonSerializer.Serialize(request)}");
throw;
}
}
}
}

View File

@ -0,0 +1,186 @@
using Asp.Versioning;
using Core.Adapters.Lib;
using Core.Inventory.External.Clients.Inventory;
using Core.Inventory.External.Clients.Inventory.Requests.Variant;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
namespace Core.Inventory.BFF.API.Controllers
{
/// <summary>
/// Handles all requests for furniture variant operations.
/// </summary>
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
[Consumes("application/json")]
[Produces("application/json")]
public class FurnitureVariantController(IInventoryServiceClient inventoryClient, ILogger<FurnitureVariantController> logger) : BaseController(logger)
{
/// <summary>
/// Gets all furniture base records.
/// </summary>
[HttpGet("GetAll")]
[ProducesResponseType(typeof(IEnumerable<FurnitureVariant>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetAllVariantsAsync(CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(GetAllVariantsAsync)} - Request received.");
return await Handle(() => inventoryClient.GetAllVariantsAsync(TrackingId.ToString(), cancellationToken));
}
catch (Exception ex)
{
logger.LogError(ex, $"{nameof(GetAllVariantsAsync)} - An error occurred.");
throw;
}
}
/// <summary>
/// Gets furniture variants by model ID.
/// </summary>
[HttpPost("GetAllByModelId")]
[ProducesResponseType(typeof(IEnumerable<FurnitureVariant>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetAllByModelIdAsync([FromBody] GetAllFurnitureVariantsByModelIdRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(GetAllByModelIdAsync)} - Request received. Payload: {JsonSerializer.Serialize(request)}");
if (string.IsNullOrWhiteSpace(request.ModelId)) return BadRequest("ModelId is required.");
return await Handle(() => inventoryClient.GetAllVariantsByModelIdAsync(TrackingId.ToString(), request, cancellationToken));
}
catch (Exception ex)
{
logger.LogError(ex, $"{nameof(GetAllByModelIdAsync)} - An error occurred. Payload: {JsonSerializer.Serialize(request)}");
throw;
}
}
/// <summary>
/// Gets a furniture variant by its MongoId.
/// </summary>
[HttpPost("GetById")]
[ProducesResponseType(typeof(FurnitureVariant), StatusCodes.Status200OK)]
public async Task<IActionResult> GetByIdAsync([FromBody] GetFurnitureVariantByIdRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(GetByIdAsync)} - Request received. Payload: {JsonSerializer.Serialize(request)}");
if (string.IsNullOrWhiteSpace(request.MongoId)) return BadRequest("MongoId is required.");
return await Handle(() => inventoryClient.GetFurnitureVariantByIdAsync(TrackingId.ToString(), request, cancellationToken));
}
catch (Exception ex)
{
logger.LogError(ex, $"{nameof(GetByIdAsync)} - An error occurred. Payload: {JsonSerializer.Serialize(request)}");
throw;
}
}
/// <summary>
/// Gets furniture variants by a list of IDs.
/// </summary>
[HttpPost("GetByIds")]
[ProducesResponseType(typeof(IEnumerable<FurnitureVariant>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetByIdsAsync([FromBody] GetFurnitureVariantsByIdsRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(GetByIdsAsync)} - Request received. Payload: {JsonSerializer.Serialize(request)}");
if (request?.Ids == null || request.Ids.Count == 0)
return BadRequest("At least one Id is required.");
return await Handle(() => inventoryClient.GetFurnitureVariantsByIdsAsync(TrackingId.ToString(), request, cancellationToken));
}
catch (Exception ex)
{
logger.LogError(ex, $"{nameof(GetByIdsAsync)} - An error occurred. Payload: {JsonSerializer.Serialize(request)}");
throw;
}
}
/// <summary>
/// Creates a new furniture variant.
/// </summary>
[HttpPost("Create")]
[ProducesResponseType(typeof(FurnitureVariant), StatusCodes.Status201Created)]
public async Task<IActionResult> CreateAsync([FromBody] CreateFurnitureVariantRequest newVariant, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(CreateAsync)} - Request received. Payload: {JsonSerializer.Serialize(newVariant)}");
if (newVariant == null) return BadRequest("Invalid furniture object");
if (string.IsNullOrEmpty(newVariant.ModelId)) return BadRequest("Invalid furniture modelId");
if (string.IsNullOrEmpty(newVariant.Name)) return BadRequest("Invalid furniture name");
if (string.IsNullOrEmpty(newVariant.Color)) return BadRequest("Invalid furniture color");
return await Handle(() => inventoryClient.CreateFurnitureVariantAsync(TrackingId.ToString(), newVariant, cancellationToken));
}
catch (Exception ex)
{
logger.LogError(ex, $"{nameof(CreateAsync)} - An error occurred. Payload: {JsonSerializer.Serialize(newVariant)}");
throw;
}
}
/// <summary>
/// Updates a furniture variant.
/// </summary>
[HttpPut("Update")]
[ProducesResponseType(typeof(FurnitureVariant), StatusCodes.Status200OK)]
public async Task<IActionResult> UpdateAsync([FromBody] UpdateFurnitureVariantRequest newVariant, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(UpdateAsync)} - Request received. Payload: {JsonSerializer.Serialize(newVariant)}");
if (newVariant == null) return BadRequest("Invalid furniture object");
if (string.IsNullOrEmpty(newVariant.ModelId)) return BadRequest("Invalid furniture modelId");
if (string.IsNullOrEmpty(newVariant.Name)) return BadRequest("Invalid furniture name");
if (string.IsNullOrEmpty(newVariant.Color)) return BadRequest("Invalid furniture color");
if (string.IsNullOrWhiteSpace(newVariant.Id)) return BadRequest("Id is required.");
return await Handle(() => inventoryClient.UpdateFurnitureVariantAsync(TrackingId.ToString(), newVariant.Id, newVariant, cancellationToken));
}
catch (Exception ex)
{
logger.LogError(ex, $"{nameof(UpdateAsync)} - An error occurred. Payload: {JsonSerializer.Serialize(newVariant)}");
throw;
}
}
/// <summary>
/// Changes the status of a furniture variant.
/// </summary>
[HttpPatch("ChangeStatus")]
[ProducesResponseType(typeof(FurnitureVariant), StatusCodes.Status200OK)]
public async Task<IActionResult> ChangeStatusAsync([FromBody] ChangeFurnitureVariantStatusRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(ChangeStatusAsync)} - Request received. Payload: {JsonSerializer.Serialize(request)}");
if (string.IsNullOrWhiteSpace(request.MongoId)) return BadRequest("Id is required.");
return await Handle(() => inventoryClient.ChangeFurnitureVariantStatusAsync(TrackingId.ToString(), request, cancellationToken));
}
catch (Exception ex)
{
logger.LogError(ex, $"{nameof(ChangeStatusAsync)} - An error occurred. Payload: {JsonSerializer.Serialize(request)}");
throw;
}
}
}
}

View File

@ -0,0 +1,307 @@
using Asp.Versioning;
using Core.Adapters.Lib.Inventory;
using Core.Inventory.External.Clients.Inventory;
using Core.Inventory.External.Clients.Inventory.Requests.Product;
using Lib.Architecture.BuildingBlocks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
namespace Core.Inventory.BFF.API.Controllers
{
/// <summary>
/// Handles all requests for Product operations.
/// </summary>
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
[Consumes("application/json")]
[Produces("application/json")]
[ApiController]
[AllowAnonymous]
public class ProductController(IInventoryServiceClient inventoryServiceClient, ILogger<ProductController> logger) : BaseController(logger)
{
/// <summary>
/// Gets all the Products.
/// </summary>
[HttpGet("GetAll")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetAllProductsService(CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(GetAllProductsService)} - Request received - Payload: ");
return await Handle(() => inventoryServiceClient.GetAllProductsService(new GetAllProductsRequest { }, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(GetAllProductsService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload");
throw;
}
}
/// <summary>
/// Gets all the Products by Product identifiers.
/// </summary>
/// <param name="request">The request containing the list of Product identifiers.</param>
/// <param name="cancellationToken">Cancellation token for the asynchronous operation.</param>
/// <returns>The <see cref="IActionResult"/> representing the result of the service call.</returns>
/// <response code="200">The Products found.</response>
/// <response code="204">No content if no Products are found.</response>
/// <response code="400">Bad request if the Product identifiers are missing or invalid.</response>
/// <response code="401">Unauthorized if the user is not authenticated.</response>
/// <response code="500">Internal server error if an unexpected error occurs.</response>
[HttpPost("GetAllByList")]
[ProducesResponseType(typeof(IEnumerable<ProductAdapter>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetAllProductsByListAsync([FromBody] GetAllProductsByListRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(GetAllProductsByListAsync)} - Request received - Payload: {request}");
if (request == null || request.Products == null || !request.Products.Any())
{
return BadRequest("Product identifiers are required.");
}
return await Handle(() => inventoryServiceClient.GetAllProductsByListService(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError(ex, $"{nameof(GetAllProductsByListAsync)} - An error occurred - {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload: {request}");
return StatusCode(StatusCodes.Status500InternalServerError, "Internal server error");
}
}
/// <summary>
/// Creates a new Product.
/// </summary>
[HttpPost("Create")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> CreateProductService(CreateProductRequest newProduct, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(CreateProductService)} - Request received - Payload: {JsonSerializer.Serialize(newProduct)}");
if (newProduct == null) return BadRequest("Invalid Product object");
if (string.IsNullOrEmpty(newProduct.ProductName)) return BadRequest("Invalid Product name");
return await Handle(() => inventoryServiceClient.CreateProductService(newProduct, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(CreateProductService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(newProduct)}");
throw;
}
}
/// <summary>
/// Gets the Product by identifier.
/// </summary>
[HttpPost("GetById")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetProductByIdService(GetProductRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(GetProductByIdService)} - Request received - Payload: {JsonSerializer.Serialize(request)}");
if (string.IsNullOrEmpty(request.Id)) return BadRequest("Invalid Product identifier");
return await Handle(() => inventoryServiceClient.GetProductByIdService(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(GetProductByIdService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(request)}");
throw;
}
}
/// <summary>
/// Updates a full Product by identifier.
/// </summary>
[HttpPut("Update")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> UpdateProductService(UpdateProductRequest newProduct, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(UpdateProductService)} - Request received - Payload: {JsonSerializer.Serialize(newProduct)}");
if (newProduct == null) return BadRequest("Invalid Product object");
if (string.IsNullOrEmpty(newProduct.ProductName)) return BadRequest("Invalid Product name");
return await Handle(() => inventoryServiceClient.UpdateProductService(newProduct, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(UpdateProductService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(newProduct)}");
throw;
}
}
/// <summary>
/// Changes the status of the Product.
/// </summary>
/// <param name="request">The request containing the product ID and new ProductStatus.</param>
/// <returns>The <see cref="ProductAdapter"/> updated entity.</returns>
/// <response code="200">The Product updates.</response>
/// <response code="204">The Product not found.</response>
/// <response code="400">The Product could not be updated.</response>
/// <response code="401">The Product could not be updated.</response>
/// <response code="412">The Product could not be updated.</response>
/// <response code="422">The Product could not be updated.</response>
/// <response code="500">The service internal error.</response>
[HttpPatch]
[Route("ChangeStatus")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> ChangeProductStatusService([FromBody] ChangeProductStatusRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(ChangeProductStatusService)} - Request received - Payload: {JsonSerializer.Serialize(request)}");
if (string.IsNullOrEmpty(request.Id)) { return BadRequest("Invalid Product identifier"); }
return await Handle(() => inventoryServiceClient.ChangeProductStatusService(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(ChangeProductStatusService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(request)}");
throw;
}
}
/// <summary>
/// Adds a tag to the product.
/// </summary>
[HttpPost]
[Route("AddTag")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> AddTagToProductAsync([FromBody] AddTagToProductRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(AddTagToProductAsync)} - Request received - Payload: {JsonSerializer.Serialize(request)}");
if (string.IsNullOrEmpty(request.ProductId)) { return BadRequest("Invalid product identifier"); }
if (string.IsNullOrEmpty(request.TagId)) { return BadRequest("Invalid tag identifier"); }
return await Handle(() => inventoryServiceClient.AddTagToProductAsync(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(AddTagToProductAsync)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(request)}");
throw;
}
}
/// <summary>
/// Remove a tag from the product.
/// </summary>
[HttpDelete]
[Route("RemoveTag")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> RemoveTagFromProductAsync([FromBody] RemoveTagFromProductRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(RemoveTagFromProductAsync)} - Request received - Payload: {JsonSerializer.Serialize(request)}");
if (string.IsNullOrEmpty(request.ProductId)) { return BadRequest("Invalid product identifier"); }
if (string.IsNullOrEmpty(request.TagId)) { return BadRequest("Invalid tag identifier"); }
return await Handle(() => inventoryServiceClient.RemoveTagFromProductAsync(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(RemoveTagFromProductAsync)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(request)}");
throw;
}
}
/// <summary>
/// Deletes a Product by its identifier.
/// </summary>
/// <param name="request">The request containing the product ID to delete.</param>
/// <param name="cancellationToken">Cancellation token for the asynchronous operation.</param>
/// <returns>The <see cref="IActionResult"/> representing the result of the service call.</returns>
/// <response code="200">The Product deleted successfully.</response>
/// <response code="204">No content if the Product was not found.</response>
/// <response code="400">Bad request if the Product ID is missing or invalid.</response>
/// <response code="401">Unauthorized if the user is not authenticated.</response>
/// <response code="412">Precondition failed if the request does not meet expected conditions.</response>
/// <response code="422">Unprocessable entity if the request cannot be processed.</response>
/// <response code="500">Internal server error if an unexpected error occurs.</response>
[HttpDelete("Delete")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> DeleteProductService([FromBody] DeleteProductRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(DeleteProductService)} - Request received - Payload: {JsonSerializer.Serialize(request)}");
if (string.IsNullOrEmpty(request.Id)) { return BadRequest("Invalid Product identifier"); }
return await Handle(() => inventoryServiceClient.DeleteProductService(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(DeleteProductService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(request)}");
throw;
}
}
}
}

View File

@ -0,0 +1,291 @@
using Asp.Versioning;
using Core.Adapters.Lib;
using Core.Inventory.External.Clients.Inventory;
using Core.Inventory.External.Clients.Inventory.Requests.Tag;
using Core.Inventory.External.Clients.Inventory.Requests.TagType;
using Lib.Architecture.BuildingBlocks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
namespace Core.Inventory.BFF.API.Controllers
{
/// <summary>
/// Handles all requests for Tag authentication.
/// </summary>
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
[Consumes("application/json")]
[Produces("application/json")]
[ApiController]
[AllowAnonymous]
public class TagController(IInventoryServiceClient inventoryServiceClient, ILogger<TagController> logger) : BaseController(logger)
{
/// <summary>
/// Gets all the Tags.
/// </summary>
[HttpGet("GetAll")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetAllTagsService(CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(GetAllTagsService)} - Request received - Payload: ");
return await Handle(() => inventoryServiceClient.GetAllTagsService(new GetAllTagsRequest { }, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(GetAllTagsService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload");
throw;
}
}
/// <summary>
/// Gets all the Tags by Tag identifiers.
/// </summary>
/// <param name="request">The request containing the list of Tag identifiers.</param>
/// <param name="cancellationToken">Cancellation token for the asynchronous operation.</param>
/// <returns>The <see cref="IActionResult"/> representing the result of the service call.</returns>
/// <response code="200">The Tags found.</response>
/// <response code="204">No content if no Tags are found.</response>
/// <response code="400">Bad request if the Tag identifiers are missing or invalid.</response>
/// <response code="401">Unauthorized if the user is not authenticated.</response>
/// <response code="500">Internal server error if an unexpected error occurs.</response>
[HttpPost("GetAllByList")]
[ProducesResponseType(typeof(IEnumerable<TagAdapter>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetAllTagsByListAsync([FromBody] GetAllTagsByListRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(GetAllTagsByListAsync)} - Request received - Payload: {request}");
if (request == null || request.Tags == null || !request.Tags.Any())
{
return BadRequest("Tag identifiers are required.");
}
return await Handle(() => inventoryServiceClient.GetAllTagsByListService(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError(ex, $"{nameof(GetAllTagsByListAsync)} - An error occurred - {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload: {request}");
return StatusCode(StatusCodes.Status500InternalServerError, "Internal server error");
}
}
/// <summary>
/// Creates a new Tag.
/// </summary>
[HttpPost("Create")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> CreateTagService(CreateTagRequest newTag, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(CreateTagService)} - Request received - Payload: {JsonSerializer.Serialize(newTag)}");
if (newTag == null) return BadRequest("Invalid Tag object");
if (string.IsNullOrEmpty(newTag.TagName)) return BadRequest("Invalid Tag name");
return await Handle(() => inventoryServiceClient.CreateTagService(newTag, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(CreateTagService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(newTag)}");
throw;
}
}
/// <summary>
/// Gets the Tag by identifier.
/// </summary>
[HttpPost("GetById")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetTagByIdService(GetTagRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(GetTagByIdService)} - Request received - Payload: {JsonSerializer.Serialize(request)}");
if (string.IsNullOrEmpty(request.Id)) return BadRequest("Invalid Tag identifier");
return await Handle(() => inventoryServiceClient.GetTagByIdService(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(GetTagByIdService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(request)}");
throw;
}
}
/// <summary>
/// Updates a full Tag by identifier.
/// </summary>
[HttpPut("Update")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> UpdateTagService(UpdateTagRequest tag, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(UpdateTagService)} - Request received - Payload: {JsonSerializer.Serialize(tag)}");
if (tag == null) return BadRequest("Invalid Tag object");
if (string.IsNullOrEmpty(tag.TagName)) return BadRequest("Invalid Tag name");
return await Handle(() => inventoryServiceClient.UpdateTagService(tag, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(UpdateTagService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(tag)}");
throw;
}
}
/// <summary>
/// Changes the status of the Tag.
/// </summary>
[HttpPatch]
[Route("ChangeStatus")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> ChangeTagStatusService([FromBody] ChangeTagStatusRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(ChangeTagStatusService)} - Request received - Payload: {JsonSerializer.Serialize(request)}");
if (string.IsNullOrEmpty(request.Id)) { return BadRequest("Invalid Tag identifier"); }
return await Handle(() => inventoryServiceClient.ChangeTagStatusService(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(ChangeTagStatusService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(request)}");
throw;
}
}
/// <summary>
/// Adds a parentTag to the tag.
/// </summary>
[HttpPost]
[Route("AddParentTag")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> AddParentTagAsync([FromBody] AddParentTagToTagRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(AddParentTagAsync)} - Request received - Payload: {JsonSerializer.Serialize(request)}");
if (string.IsNullOrEmpty(request.TagId)) { return BadRequest("Invalid tag identifier"); }
if (string.IsNullOrEmpty(request.ParentTagId)) { return BadRequest("Invalid parentTag identifier"); }
return await Handle(() => inventoryServiceClient.AddParentTagAsync(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(AddParentTagAsync)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(request)}");
throw;
}
}
/// <summary>
/// Remove a parentTag to the tag.
/// </summary>
[HttpDelete]
[Route("RemoveParentTag")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> RemoveParentTagAsync([FromBody] RemoveParentTagFromTag request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(RemoveParentTagAsync)} - Request received - Payload: {JsonSerializer.Serialize(request)}");
if (string.IsNullOrEmpty(request.TagId)) { return BadRequest("Invalid tag identifier"); }
if (string.IsNullOrEmpty(request.ParentTagId)) { return BadRequest("Invalid parentTag identifier"); }
return await Handle(() => inventoryServiceClient.RemoveParentTagAsync(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(RemoveParentTagAsync)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(request)}");
throw;
}
}
/// <summary>
/// Deletes a full Tag by identifier.
/// </summary>
[HttpDelete("Delete")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> DeleteTagService(DeleteTagRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(DeleteTagService)} - Request received - Payload: {JsonSerializer.Serialize(request)}");
if (request == null) return BadRequest("Invalid Tag object");
if (string.IsNullOrEmpty(request.Id)) return BadRequest("Invalid Tag identifier");
return await Handle(() => inventoryServiceClient.DeleteTagService(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(DeleteTagService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(request)}");
throw;
}
}
}
}

View File

@ -0,0 +1,235 @@
using Asp.Versioning;
using Core.Adapters.Lib;
using Core.Inventory.External.Clients.Inventory;
using Core.Inventory.External.Clients.Inventory.Requests.TagOverride;
using Core.Inventory.External.Clients.Inventory.Requests.TagType;
using Lib.Architecture.BuildingBlocks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
namespace Core.Inventory.BFF.API.Controllers
{
/// <summary>
/// Handles all requests for TagOverride authentication.
/// </summary>
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
[Consumes("application/json")]
[Produces("application/json")]
[ApiController]
[AllowAnonymous]
public class TagOverrideController(IInventoryServiceClient inventoryServiceClient, ILogger<TagOverrideController> logger) : BaseController(logger)
{
/// <summary>
/// Gets all the TagOverrides.
/// </summary>
[HttpGet("GetAll")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetAllTagOverridesService(CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(GetAllTagOverridesService)} - Request received - Payload: ");
return await Handle(() => inventoryServiceClient.GetAllTagOverridesService(new GetAllTagOverridesRequest { }, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(GetAllTagOverridesService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload");
throw;
}
}
/// <summary>
/// Gets all the TagOverrides by TagOverride identifiers.
/// </summary>
/// <param name="request">The request containing the list of TagOverride identifiers.</param>
/// <param name="cancellationToken">Cancellation token for the asynchronous operation.</param>
/// <returns>The <see cref="IActionResult"/> representing the result of the service call.</returns>
/// <response code="200">The TagOverrides found.</response>
/// <response code="204">No content if no TagOverrides are found.</response>
/// <response code="400">Bad request if the TagOverride identifiers are missing or invalid.</response>
/// <response code="401">Unauthorized if the user is not authenticated.</response>
/// <response code="500">Internal server error if an unexpected error occurs.</response>
[HttpPost("GetAllByList")]
[ProducesResponseType(typeof(IEnumerable<TagOverrideAdapter>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetAllTagOverridesByListAsync([FromBody] GetAllTagOverridesByListRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(GetAllTagOverridesByListAsync)} - Request received - Payload: {request}");
if (request == null || request.TagOverrides == null || !request.TagOverrides.Any())
{
return BadRequest("TagOverride identifiers are required.");
}
return await Handle(() => inventoryServiceClient.GetAllTagOverridesByListService(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError(ex, $"{nameof(GetAllTagOverridesByListAsync)} - An error occurred - {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload: {request}");
return StatusCode(StatusCodes.Status500InternalServerError, "Internal server error");
}
}
/// <summary>
/// Creates a new TagOverride.
/// </summary>
[HttpPost("Create")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> CreateTagOverrideService(CreateTagOverrideRequest newTagOverride, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(CreateTagOverrideService)} - Request received - Payload: {JsonSerializer.Serialize(newTagOverride)}");
if (newTagOverride == null) return BadRequest("Invalid TagOverride object");
if (string.IsNullOrEmpty(newTagOverride.BaseTagId)) return BadRequest("Invalid TagOverride BaseTagId");
if (string.IsNullOrEmpty(newTagOverride.OverrideTagId)) return BadRequest("Invalid TagOverride OverrideTagId");
return await Handle(() => inventoryServiceClient.CreateTagOverrideService(newTagOverride, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(CreateTagOverrideService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(newTagOverride)}");
throw;
}
}
/// <summary>
/// Gets the TagOverride by identifier.
/// </summary>
[HttpPost("GetById")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetTagOverrideByIdService(GetTagOverrideRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(GetTagOverrideByIdService)} - Request received - Payload: {JsonSerializer.Serialize(request)}");
if (string.IsNullOrEmpty(request.Id)) return BadRequest("Invalid TagOverride identifier");
return await Handle(() => inventoryServiceClient.GetTagOverrideByIdService(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(GetTagOverrideByIdService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(request)}");
throw;
}
}
/// <summary>
/// Updates a full TagOverride by identifier.
/// </summary>
[HttpPut("Update")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> UpdateTagOverrideService(UpdateTagOverrideRequest tagOverride, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(UpdateTagOverrideService)} - Request received - Payload: {JsonSerializer.Serialize(tagOverride)}");
if (tagOverride == null) return BadRequest("Invalid TagOverride object");
if (string.IsNullOrEmpty(tagOverride.BaseTagId)) return BadRequest("Invalid TagOverride BaseTagId");
if (string.IsNullOrEmpty(tagOverride.OverrideTagId)) return BadRequest("Invalid TagOverride OverrideTagId");
return await Handle(() => inventoryServiceClient.UpdateTagOverrideService(tagOverride, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(UpdateTagOverrideService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(tagOverride)}");
throw;
}
}
/// <summary>
/// Changes the status of the TagOverride.
/// </summary>
[HttpPatch]
[Route("ChangeStatus")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> ChangeTagOverrideStatusService([FromBody] ChangeTagOverrideStatusRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(ChangeTagOverrideStatusService)} - Request received - Payload: {JsonSerializer.Serialize(request)}");
if (string.IsNullOrEmpty(request.Id)) { return BadRequest("Invalid TagOverride identifier"); }
return await Handle(() => inventoryServiceClient.ChangeTagOverrideStatusService(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(ChangeTagOverrideStatusService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(request)}");
throw;
}
}
/// <summary>
/// Deletes a full TagOverride by identifier.
/// </summary>
[HttpDelete("Delete")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> DeleteTagOverrideService(DeleteTagOverrideRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(DeleteTagOverrideService)} - Request received - Payload: {JsonSerializer.Serialize(request)}");
if (request == null) return BadRequest("Invalid TagOverride object");
if (string.IsNullOrEmpty(request.Id)) return BadRequest("Invalid TagOverride identifier");
return await Handle(() => inventoryServiceClient.DeleteTagOverrideService(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(DeleteTagOverrideService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(request)}");
throw;
}
}
}
}

View File

@ -0,0 +1,230 @@
using Asp.Versioning;
using Core.Adapters.Lib;
using Core.Inventory.External.Clients.Inventory;
using Core.Inventory.External.Clients.Inventory.Requests.TagType;
using Lib.Architecture.BuildingBlocks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
namespace Core.Inventory.BFF.API.Controllers
{
/// <summary>
/// Handles all requests for TagType authentication.
/// </summary>
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
[Consumes("application/json")]
[Produces("application/json")]
[ApiController]
[AllowAnonymous]
public class TagTypeController(IInventoryServiceClient inventoryServiceClient, ILogger<TagTypeController> logger) : BaseController(logger)
{
/// <summary>
/// Gets all the TagTypes.
/// </summary>
[HttpGet("GetAll")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetAllTagTypesService(CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(GetAllTagTypesService)} - Request received - Payload: ");
return await Handle(() => inventoryServiceClient.GetAllTagTypesService(new GetAllTagTypesRequest { }, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(GetAllTagTypesService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload");
throw;
}
}
/// <summary>
/// Gets all the TagTypes by TagType identifiers.
/// </summary>
/// <param name="request">The request containing the list of TagType identifiers.</param>
/// <param name="cancellationToken">Cancellation token for the asynchronous operation.</param>
/// <returns>The <see cref="IActionResult"/> representing the result of the service call.</returns>
/// <response code="200">The TagTypes found.</response>
/// <response code="204">No content if no TagTypes are found.</response>
/// <response code="400">Bad request if the TagType identifiers are missing or invalid.</response>
/// <response code="401">Unauthorized if the user is not authenticated.</response>
/// <response code="500">Internal server error if an unexpected error occurs.</response>
[HttpPost("GetAllByList")]
[ProducesResponseType(typeof(IEnumerable<TagTypeAdapter>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetAllTagTypesByListAsync([FromBody] GetAllTagTypesByListRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(GetAllTagTypesByListAsync)} - Request received - Payload: {request}");
if (request == null || request.TagTypes == null || !request.TagTypes.Any())
{
return BadRequest("TagType identifiers are required.");
}
return await Handle(() => inventoryServiceClient.GetAllTagTypesByListService(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError(ex, $"{nameof(GetAllTagTypesByListAsync)} - An error occurred - {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload: {request}");
return StatusCode(StatusCodes.Status500InternalServerError, "Internal server error");
}
}
/// <summary>
/// Creates a new TagType.
/// </summary>
[HttpPost("Create")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> CreateTagTypeService(CreateTagTypeRequest newTagType, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(CreateTagTypeService)} - Request received - Payload: {JsonSerializer.Serialize(newTagType)}");
if (newTagType == null) return BadRequest("Invalid TagType object");
if (string.IsNullOrEmpty(newTagType.TypeName)) return BadRequest("Invalid TagType name");
return await Handle(() => inventoryServiceClient.CreateTagTypeService(newTagType, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(CreateTagTypeService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(newTagType)}");
throw;
}
}
/// <summary>
/// Gets the TagType by identifier.
/// </summary>
[HttpPost("GetById")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetTagTypeByIdService(GetTagTypeRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(GetTagTypeByIdService)} - Request received - Payload: {JsonSerializer.Serialize(request)}");
if (string.IsNullOrEmpty(request.Id)) return BadRequest("Invalid TagType identifier");
return await Handle(() => inventoryServiceClient.GetTagTypeByIdService(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(GetTagTypeByIdService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(request)}");
throw;
}
}
/// <summary>
/// Updates a full TagType by identifier.
/// </summary>
[HttpPut("Update")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> UpdateTagTypeService(UpdateTagTypeRequest tagType, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(UpdateTagTypeService)} - Request received - Payload: {JsonSerializer.Serialize(tagType)}");
if (tagType == null) return BadRequest("Invalid TagType object");
if (string.IsNullOrEmpty(tagType.TypeName)) return BadRequest("Invalid TagType name");
return await Handle(() => inventoryServiceClient.UpdateTagTypeService(tagType, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(UpdateTagTypeService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(tagType)}");
throw;
}
}
/// <summary>
/// Changes the status of the TagType.
/// </summary>
[HttpPatch]
[Route("ChangeStatus")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> ChangeTagTypeStatusService([FromBody] ChangeTagTypeStatusRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(ChangeTagTypeStatusService)} - Request received - Payload: {JsonSerializer.Serialize(request)}");
if (string.IsNullOrEmpty(request.Id)) { return BadRequest("Invalid TagType identifier"); }
return await Handle(() => inventoryServiceClient.ChangeTagTypeStatusService(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(ChangeTagTypeStatusService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(request)}");
throw;
}
}
/// <summary>
/// Deletes a full TagType by identifier.
/// </summary>
[HttpDelete("Delete")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(Notification), StatusCodes.Status422UnprocessableEntity)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> DeleteTagTypeService(DeleteTagTypeRequest request, CancellationToken cancellationToken)
{
try
{
logger.LogInformation($"{nameof(DeleteTagTypeService)} - Request received - Payload: {JsonSerializer.Serialize(request)}");
if (request == null) return BadRequest("Invalid TagType object");
if (string.IsNullOrEmpty(request.Id)) return BadRequest("Invalid TagType identifier");
return await Handle(() => inventoryServiceClient.DeleteTagTypeService(request, cancellationToken)).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError($"{nameof(DeleteTagTypeService)} - An Error Occurred- {ex.Message} - {ex.InnerException} - {ex.StackTrace} - with payload {JsonSerializer.Serialize(request)}");
throw;
}
}
}
}

View File

@ -1,33 +0,0 @@
using Microsoft.AspNetCore.Mvc;
namespace Core.Inventory.BFF.API.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}

View File

@ -7,7 +7,15 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" />
<PackageReference Include="Core.Blueprint.Logging" Version="1.0.0" />
<PackageReference Include="OpenTelemetry" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.12.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Core.Inventory.External\Core.Inventory.External.csproj" />
</ItemGroup>
</Project>

View File

@ -1,25 +1,133 @@
using Core.Blueprint.Logging.Configuration;
using Core.Inventory.External;
using Core.Inventory.External.ClientConfiguration;
using Microsoft.AspNetCore.ResponseCompression;
using OpenTelemetry.Logs;
using OpenTelemetry.Resources;
using Swashbuckle.AspNetCore.SwaggerUI;
using System.IO.Compression;
using System.Reflection;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Configuration
.AddUserSecrets(Assembly.GetExecutingAssembly())
.AddEnvironmentVariables();
builder.Services.AddResponseCompression();
builder.Services.AddProblemDetails();
builder.Services.AddLogs(builder);
builder.Services.AddMemoryCache();
builder.Services.AddResponseCaching(configureOptions => { configureOptions.UseCaseSensitivePaths = true; });
builder.Logging.AddOpenTelemetry(options =>
{
options.IncludeScopes = true;
options.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("core.inventory.bff.api")).AddConsoleExporter();
});
builder.Host.ConfigureServices((context, services) =>
{
builder.Services.AddHsts(options =>
{
options.Preload = true;
options.IncludeSubDomains = true;
options.MaxAge = TimeSpan.FromDays(60);
});
builder.Services.AddResponseCaching(configureOptions =>
{
configureOptions.UseCaseSensitivePaths = true;
configureOptions.MaximumBodySize = 2048;
});
builder.Services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = 308;
});
services.AddHttpLogging(http =>
{
http.CombineLogs = true;
});
services.AddAntiforgery();
services.AddCors(options =>
{
options.AddPolicy("AllowAll", policyBuilder =>
policyBuilder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
});
services.AddMvc().AddJsonOptions(options =>
{
options.JsonSerializerOptions.WriteIndented = true;
options.JsonSerializerOptions.MaxDepth = 20;
options.JsonSerializerOptions.NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowNamedFloatingPointLiterals;
});
services.Configure<BrotliCompressionProviderOptions>(options =>
{
options.Level = CompressionLevel.SmallestSize;
});
services.Configure<GzipCompressionProviderOptions>(options =>
{
options.Level = CompressionLevel.SmallestSize;
});
services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
options.Providers.Add<BrotliCompressionProvider>();
options.Providers.Add<GzipCompressionProvider>();
});
services.AddResponseCaching();
services.AddControllers();
services.AddEndpointsApiExplorer();
services.AddSwaggerGen();
services.AddLogging();
services.AddProblemDetails();
services.AddHttpContextAccessor();
services.AddTransient<TrackingMechanismExtension>(); // Register the TrackingIdHandler
services.RegisterExternalLayer(builder.Configuration);
services.AddApiVersioning(options => options.ReportApiVersions = true)
.AddApiExplorer(options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
});
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
//*************************************************************************//
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
app.UseCors(options => options.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin());
app.UseSwagger();
app.UseSwaggerUI(options =>
{
app.UseSwagger();
app.UseSwaggerUI();
}
foreach (var version in app.DescribeApiVersions().Select(version => version.GroupName))
options.SwaggerEndpoint($"/swagger/{version}/swagger.json", version);
options.DisplayRequestDuration();
options.EnableTryItOutByDefault();
options.DocExpansion(DocExpansion.None);
});
app.UseResponseCompression();
app.UseResponseCaching();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.UseHsts();
app.UseAntiforgery();
app.UseLogging(builder.Configuration);
app.Run();

View File

@ -16,7 +16,7 @@
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5101",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
"ASPNETCORE_ENVIRONMENT": "Local"
}
},
"https": {
@ -26,7 +26,7 @@
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7223;http://localhost:5101",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
"ASPNETCORE_ENVIRONMENT": "Local"
}
},
"IIS Express": {
@ -34,7 +34,7 @@
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
"ASPNETCORE_ENVIRONMENT": "Local"
}
}
}

View File

@ -1,13 +0,0 @@
namespace Core.Inventory.BFF.API
{
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
}

View File

@ -0,0 +1,12 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"LocalGateways": {
"InventoryService": "https://localhost:7028"
}
}

View File

@ -5,6 +5,10 @@ VisualStudioVersion = 17.14.36212.18 d17.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Inventory.BFF.API", "Core.Inventory.BFF.API\Core.Inventory.BFF.API.csproj", "{A7C30239-BEB4-4DD5-A5C4-AEB4B5154927}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Application", "Application", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Inventory.External", "Core.Inventory.External\Core.Inventory.External.csproj", "{AC69431D-D222-4376-BCE3-31C7201B1F01}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -15,10 +19,17 @@ Global
{A7C30239-BEB4-4DD5-A5C4-AEB4B5154927}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A7C30239-BEB4-4DD5-A5C4-AEB4B5154927}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A7C30239-BEB4-4DD5-A5C4-AEB4B5154927}.Release|Any CPU.Build.0 = Release|Any CPU
{AC69431D-D222-4376-BCE3-31C7201B1F01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AC69431D-D222-4376-BCE3-31C7201B1F01}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AC69431D-D222-4376-BCE3-31C7201B1F01}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AC69431D-D222-4376-BCE3-31C7201B1F01}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{AC69431D-D222-4376-BCE3-31C7201B1F01} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {97B12EA0-3BE9-4A8D-8918-7152ADB153B1}
EndGlobalSection

View File

@ -0,0 +1,65 @@
using Core.Inventory.External.Clients.Inventory;
using Core.Inventory.External.GatewayConfigurations;
using Lib.Architecture.BuildingBlocks.Helpers.Token;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Refit;
namespace Core.Inventory.External.ClientConfiguration
{
public static class RegisterClientConfiguration
{
public static IServiceCollection RegisterExternalLayer(this IServiceCollection services, IConfiguration configuration)
{
var gatewayConfiguration = new GatewayConfiguration();
var gatewaySettingsConfiguration = new GatewaySettingsConfigurations(configuration);
// Register GatewayConfiguration as a singleton
services.AddSingleton(gatewayConfiguration);
// Register IHttpContextAccessor
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// Register ITokenProvider
services.AddSingleton<ITokenProvider, HttpContextTokenProvider>();
// Register the custom AuthenticatedHttpClientHandler
services.AddTransient(provider =>
{
var tokenProvider = provider.GetRequiredService<ITokenProvider>();
var trackingIdHandler = new TrackingMechanismExtension(provider.GetRequiredService<IHttpContextAccessor>());
var handler = new AuthenticatedHttpClientHandler(tokenProvider)
{
InnerHandler = new HttpClientHandler() // Setting the InnerHandler manually
};
// Attach the TrackingIdHandler as the outermost handler
trackingIdHandler.InnerHandler = handler;
return handler;
});
var inventoryServiceApiUrl = GatewaySettingsConfigurations.GetInventoryServiceAPIEndpoint().Endpoint.Url;
// Register IDashBoardServiceClient with the manually created HttpClient
services.AddScoped(provider =>
{
var handler = provider.GetRequiredService<AuthenticatedHttpClientHandler>();
var handlerTrackingId = new TrackingMechanismExtension(provider.GetRequiredService<IHttpContextAccessor>()); // Using the TrackingIdHandler here
// Chain the handlers
handlerTrackingId.InnerHandler = handler; //chaining
var httpClient = new HttpClient(handlerTrackingId)
{
BaseAddress = new Uri(inventoryServiceApiUrl),
Timeout = TimeSpan.FromMinutes(1)
};
return RestService.For<IInventoryServiceClient>(httpClient);
});
return services;
}
}
}

View File

@ -0,0 +1,171 @@
using Core.Adapters.Lib;
using Core.Adapters.Lib.Inventory;
using Core.Inventory.External.Clients.Inventory.Requests.Base;
using Core.Inventory.External.Clients.Inventory.Requests.Product;
using Core.Inventory.External.Clients.Inventory.Requests.Tag;
using Core.Inventory.External.Clients.Inventory.Requests.TagOverride;
using Core.Inventory.External.Clients.Inventory.Requests.TagType;
using Core.Inventory.External.Clients.Inventory.Requests.Variant;
using Refit;
namespace Core.Inventory.External.Clients.Inventory
{
public interface IInventoryServiceClient
{
#region Furniture Base
[Get("/api/v1/FurnitureBase/GetAll")]
Task<ApiResponse<IEnumerable<FurnitureBase>>> GetAllBaseAsync([Header("TrackingId")] string trackingId, CancellationToken cancellationToken = default);
[Post("/api/v1/FurnitureBase/GetById")]
Task<ApiResponse<FurnitureBase>> GetByIdAsync([Header("TrackingId")] string trackingId, [Body] GetFurnitureBaseByIdRequest request, CancellationToken cancellationToken = default);
[Post("/api/v1/FurnitureBase/Create")]
Task<ApiResponse<FurnitureBase>> CreateAsync([Header("TrackingId")] string trackingId, [Body] CreateFurnitureBaseRequest request, CancellationToken cancellationToken = default);
[Put("/api/v1/FurnitureBase/Update")]
Task<ApiResponse<FurnitureBase>> UpdateFurnitureBaseAsync([Header("TrackingId")] string trackingId, [Body] UpdateFurnitureBaseRequest request, CancellationToken cancellationToken = default);
[Patch("/api/v1/FurnitureBase/ChangeStatus")]
Task<ApiResponse<FurnitureBase>> ChangeFurnitureBaseStatusAsync([Header("TrackingId")] string trackingId, [Body] ChangeFurnitureBaseStatusRequest request, CancellationToken cancellationToken = default);
#endregion
#region Furniture Variant
[Post("/api/v1/FurnitureVariant/GetAllByModelId")]
Task<ApiResponse<IEnumerable<FurnitureVariant>>> GetAllVariantsByModelIdAsync([Header("TrackingId")] string trackingId, [Body] GetAllFurnitureVariantsByModelIdRequest request, CancellationToken cancellationToken = default);
[Post("/api/v1/FurnitureVariant/GetById")]
Task<ApiResponse<FurnitureVariant>> GetFurnitureVariantByIdAsync([Header("TrackingId")] string trackingId, [Body] GetFurnitureVariantByIdRequest request, CancellationToken cancellationToken = default);
[Post("/api/v1/FurnitureVariant/GetByIds")]
Task<ApiResponse<IEnumerable<FurnitureVariant>>> GetFurnitureVariantsByIdsAsync([Header("TrackingId")] string trackingId, [Body] GetFurnitureVariantsByIdsRequest request, CancellationToken cancellationToken = default);
[Post("/api/v1/FurnitureVariant/Create")]
Task<ApiResponse<FurnitureVariant>> CreateFurnitureVariantAsync([Header("TrackingId")] string trackingId, [Body] CreateFurnitureVariantRequest request, CancellationToken cancellationToken = default);
[Put("/api/v1/FurnitureVariant/Update")]
Task<ApiResponse<FurnitureVariant>> UpdateFurnitureVariantAsync([Header("TrackingId")] string trackingId, string id, [Body] UpdateFurnitureVariantRequest entity, CancellationToken cancellationToken = default);
[Patch("/api/v1/FurnitureVariant/ChangeStatus")]
Task<ApiResponse<FurnitureVariant>> ChangeFurnitureVariantStatusAsync([Header("TrackingId")] string trackingId, [Body] ChangeFurnitureVariantStatusRequest request, CancellationToken cancellationToken = default);
[Get("/api/v1/FurnitureVariant/GetAll")]
Task<ApiResponse<IEnumerable<FurnitureVariant>>> GetAllVariantsAsync([Header("TrackingId")] string trackingId, CancellationToken cancellationToken = default);
#endregion
#region TagType
[Post("/api/v1/TagType/Create")]
Task<ApiResponse<TagTypeAdapter>> CreateTagTypeService([Header("TrackingId")][Body] CreateTagTypeRequest request, CancellationToken cancellationToken = default);
[Post("/api/v1/TagType/GetById")]
Task<ApiResponse<TagTypeAdapter>> GetTagTypeByIdService([Header("TrackingId")][Body] GetTagTypeRequest request, CancellationToken cancellationToken = default);
[Get("/api/v1/TagType/GetAll")]
Task<ApiResponse<IEnumerable<TagTypeAdapter>>> GetAllTagTypesService([Header("TrackingId")][Body] GetAllTagTypesRequest request, CancellationToken cancellationToken = default);
[Post("/api/v1/TagType/GetTagTypeList")]
Task<ApiResponse<IEnumerable<TagTypeAdapter>>> GetAllTagTypesByListService([Header("TrackingId")][Body] GetAllTagTypesByListRequest request, CancellationToken cancellationToken = default);
[Put("/api/v1/TagType/Update")]
Task<ApiResponse<TagTypeAdapter>> UpdateTagTypeService([Header("TrackingId")][Body] UpdateTagTypeRequest request, CancellationToken cancellationToken = default);
[Patch("/api/v1/TagType/ChangeStatus")]
Task<ApiResponse<TagTypeAdapter>> ChangeTagTypeStatusService([Header("TrackingId")][Body] ChangeTagTypeStatusRequest request, CancellationToken cancellationToken = default);
[Delete("/api/v1/TagType/Delete")]
Task<ApiResponse<TagTypeAdapter>> DeleteTagTypeService([Header("TrackingId")][Body] DeleteTagTypeRequest request, CancellationToken cancellationToken = default);
#endregion
#region Tag
[Post("/api/v1/Tag/Create")]
Task<ApiResponse<TagAdapter>> CreateTagService([Header("TrackingId")][Body] CreateTagRequest request, CancellationToken cancellationToken = default);
[Post("/api/v1/Tag/GetById")]
Task<ApiResponse<TagAdapter>> GetTagByIdService([Header("TrackingId")][Body] GetTagRequest request, CancellationToken cancellationToken = default);
[Get("/api/v1/Tag/GetAll")]
Task<ApiResponse<IEnumerable<TagAdapter>>> GetAllTagsService([Header("TrackingId")][Body] GetAllTagsRequest request, CancellationToken cancellationToken = default);
[Post("/api/v1/Tag/GetTagList")]
Task<ApiResponse<IEnumerable<TagAdapter>>> GetAllTagsByListService([Header("TrackingId")][Body] GetAllTagsByListRequest request, CancellationToken cancellationToken = default);
[Put("/api/v1/Tag/Update")]
Task<ApiResponse<TagAdapter>> UpdateTagService([Header("TrackingId")][Body] UpdateTagRequest request, CancellationToken cancellationToken = default);
[Patch("/api/v1/Tag/ChangeStatus")]
Task<ApiResponse<TagAdapter>> ChangeTagStatusService([Header("TrackingId")][Body] ChangeTagStatusRequest request, CancellationToken cancellationToken = default);
[Post("/api/v1/Tag/AddParentTag")]
Task<ApiResponse<TagAdapter>> AddParentTagAsync([Header("TrackingId")][Body] AddParentTagToTagRequest request, CancellationToken cancellationToken = default);
[Delete("/api/v1/Tag/RemoveParentTag")]
Task<ApiResponse<TagAdapter>> RemoveParentTagAsync([Header("TrackingId")][Body] RemoveParentTagFromTag request, CancellationToken cancellationToken = default);
[Delete("/api/v1/Tag/Delete")]
Task<ApiResponse<TagAdapter>> DeleteTagService([Header("TrackingId")][Body] DeleteTagRequest request, CancellationToken cancellationToken = default);
#endregion
#region TagOverride
[Post("/api/v1/TagOverride/Create")]
Task<ApiResponse<TagOverrideAdapter>> CreateTagOverrideService([Header("TrackingId")][Body] CreateTagOverrideRequest request, CancellationToken cancellationToken = default);
[Post("/api/v1/TagOverride/GetById")]
Task<ApiResponse<TagOverrideAdapter>> GetTagOverrideByIdService([Header("TrackingId")][Body] GetTagOverrideRequest request, CancellationToken cancellationToken = default);
[Get("/api/v1/TagOverride/GetAll")]
Task<ApiResponse<IEnumerable<TagOverrideAdapter>>> GetAllTagOverridesService([Header("TrackingId")][Body] GetAllTagOverridesRequest request, CancellationToken cancellationToken = default);
[Post("/api/v1/TagOverride/GetTagOverrideList")]
Task<ApiResponse<IEnumerable<TagOverrideAdapter>>> GetAllTagOverridesByListService([Header("TrackingId")][Body] GetAllTagOverridesByListRequest request, CancellationToken cancellationToken = default);
[Put("/api/v1/TagOverride/Update")]
Task<ApiResponse<TagOverrideAdapter>> UpdateTagOverrideService([Header("TrackingId")][Body] UpdateTagOverrideRequest request, CancellationToken cancellationToken = default);
[Patch("/api/v1/TagOverride/ChangeStatus")]
Task<ApiResponse<TagOverrideAdapter>> ChangeTagOverrideStatusService([Header("TrackingId")][Body] ChangeTagOverrideStatusRequest request, CancellationToken cancellationToken = default);
[Delete("/api/v1/TagOverride/Delete")]
Task<ApiResponse<TagOverrideAdapter>> DeleteTagOverrideService([Header("TrackingId")][Body] DeleteTagOverrideRequest request, CancellationToken cancellationToken = default);
#endregion
#region Product
[Post("/api/v1/Product/Create")]
Task<ApiResponse<ProductAdapter>> CreateProductService([Header("TrackingId")][Body] CreateProductRequest request, CancellationToken cancellationToken = default);
[Post("/api/v1/Product/GetById")]
Task<ApiResponse<ProductAdapter>> GetProductByIdService([Header("TrackingId")][Body] GetProductRequest request, CancellationToken cancellationToken = default);
[Get("/api/v1/Product/GetAll")]
Task<ApiResponse<IEnumerable<ProductAdapter>>> GetAllProductsService([Header("TrackingId")][Body] GetAllProductsRequest request, CancellationToken cancellationToken = default);
[Post("/api/v1/Product/GetProductList")]
Task<ApiResponse<IEnumerable<ProductAdapter>>> GetAllProductsByListService([Header("TrackingId")][Body] GetAllProductsByListRequest request, CancellationToken cancellationToken = default);
[Put("/api/v1/Product/Update")]
Task<ApiResponse<ProductAdapter>> UpdateProductService([Header("TrackingId")][Body] UpdateProductRequest request, CancellationToken cancellationToken = default);
[Patch("/api/v1/Product/ChangeStatus")]
Task<ApiResponse<ProductAdapter>> ChangeProductStatusService([Header("TrackingId")][Body] ChangeProductStatusRequest request, CancellationToken cancellationToken = default);
[Post("/api/v1/Product/AddTag")]
Task<ApiResponse<ProductAdapter>> AddTagToProductAsync([Header("TrackingId")][Body] AddTagToProductRequest request, CancellationToken cancellationToken = default);
[Delete("/api/v1/Product/RemoveTag")]
Task<ApiResponse<ProductAdapter>> RemoveTagFromProductAsync([Header("TrackingId")][Body] RemoveTagFromProductRequest request, CancellationToken cancellationToken = default);
[Delete("/api/v1/Product/Delete")]
Task<ApiResponse<ProductAdapter>> DeleteProductService([Header("TrackingId")][Body] DeleteProductRequest request, CancellationToken cancellationToken = default);
#endregion
}
}

View File

@ -0,0 +1,10 @@
using Core.Blueprint.Mongo;
namespace Core.Inventory.External.Clients.Inventory.Requests.Base
{
public class ChangeFurnitureBaseStatusRequest
{
public string MongoId { get; set; } = default!;
public StatusEnum Status { get; set; }
}
}

View File

@ -0,0 +1,16 @@
using Core.Inventory.External.Clients.Inventory.Requests.Common;
namespace Core.Inventory.External.Clients.Inventory.Requests.Base
{
public class CreateFurnitureBaseRequest
{
public string ModelName { get; set; } = default!;
public string Material { get; set; } = default!;
public string Condition { get; set; } = default!;
public string? BaseDescription { get; set; }
public string? Representation { get; set; }
public string? MaintenanceNotes { get; set; }
public DimensionsRequest Dimensions { get; set; } = new();
public List<string>? VariantIds { get; set; }
}
}

View File

@ -0,0 +1,6 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Base
{
public class GetAllFurnitureBaseRequest
{
}
}

View File

@ -0,0 +1,7 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Base
{
public class GetFurnitureBaseByIdRequest
{
public string MongoId { get; set; } = default!;
}
}

View File

@ -0,0 +1,18 @@
using Core.Inventory.External.Clients.Inventory.Requests.Common;
namespace Core.Inventory.External.Clients.Inventory.Requests.Base
{
public class UpdateFurnitureBaseRequest
{
public string _Id { get; set; } = default!;
public string Id { get; set; } = default!;
public string ModelName { get; set; } = default!;
public string Material { get; set; } = default!;
public string Condition { get; set; } = default!;
public string? BaseDescription { get; set; }
public string? Representation { get; set; }
public string? MaintenanceNotes { get; set; }
public DimensionsRequest Dimensions { get; set; } = new();
public List<string>? VariantIds { get; set; }
}
}

View File

@ -0,0 +1,9 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Common
{
public class DimensionsRequest
{
public decimal Width { get; set; }
public decimal Height { get; set; }
public decimal Depth { get; set; }
}
}

View File

@ -0,0 +1,8 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Product
{
public class AddTagToProductRequest
{
public string ProductId { get; set; } = null!;
public string TagId { get; set; } = null!;
}
}

View File

@ -0,0 +1,10 @@
using Core.Adapters.Lib.Inventory;
namespace Core.Inventory.External.Clients.Inventory.Requests.Product
{
public class ChangeProductStatusRequest
{
public string Id { get; set; } = null!;
public ProductStatus NewStatus { get; set; }
}
}

View File

@ -0,0 +1,11 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Product
{
public class CreateProductRequest
{
public string TenantId { get; set; } = null!;
public string ProductName { get; set; } = null!;
public string Description { get; set; } = null!;
public string ProductStatus { get; set; } = null!;
public List<string> TagIds { get; set; } = new List<string>();
}
}

View File

@ -0,0 +1,14 @@
using Lib.Architecture.BuildingBlocks;
namespace Core.Inventory.External.Clients.Inventory.Requests.Product
{
public class DeleteProductRequest : Notificator, ICommand
{
public string Id { get; set; } = null!;
public bool Validate()
{
return Id != null;
}
}
}

View File

@ -0,0 +1,7 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Product
{
public class GetAllProductsByListRequest
{
public string[] Products { get; set; } = null!;
}
}

View File

@ -0,0 +1,6 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Product
{
public class GetAllProductsRequest
{
}
}

View File

@ -0,0 +1,7 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Product
{
public class GetProductRequest
{
public string Id { get; set; }
}
}

View File

@ -0,0 +1,8 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Product
{
public class RemoveTagFromProductRequest
{
public string ProductId { get; set; } = null!;
public string TagId { get; set; } = null!;
}
}

View File

@ -0,0 +1,14 @@
using Core.Adapters.Lib.Inventory;
namespace Core.Inventory.External.Clients.Inventory.Requests.Product
{
public class UpdateProductRequest
{
public string Id { get; set; } = null!;
public string TenantId { get; set; } = null!;
public string ProductName { get; set; } = null!;
public string Description { get; set; } = null!;
public string ProductStatus { get; set; } = null!;
public List<string> TagIds { get; set; } = new List<string>();
}
}

View File

@ -0,0 +1,8 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Tag
{
public class AddParentTagToTagRequest
{
public string TagId { get; set; }
public string ParentTagId { get; set; }
}
}

View File

@ -0,0 +1,10 @@
using Core.Blueprint.Mongo;
namespace Core.Inventory.External.Clients.Inventory.Requests.Tag
{
public class ChangeTagStatusRequest
{
public string Id { get; set; }
public StatusEnum Status { get; set; }
}
}

View File

@ -0,0 +1,13 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Tag
{
public class CreateTagRequest
{
public string TenantId { get; set; } = null!;
public string TagName { get; set; } = null!;
public string TypeId { get; set; } = null!;
public string[] ParentTagId { get; set; } = null!;
public string Slug { get; set; } = null!;
public int DisplayOrder { get; set; }
public string Icon { get; set; } = null!;
}
}

View File

@ -0,0 +1,14 @@
using Lib.Architecture.BuildingBlocks;
namespace Core.Inventory.External.Clients.Inventory.Requests.Tag
{
public class DeleteTagRequest : Notificator, ICommand
{
public string Id { get; set; } = null!;
public bool Validate()
{
return Id != null;
}
}
}

View File

@ -0,0 +1,7 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Tag
{
public class GetAllTagsByListRequest
{
public string[] Tags { get; set; }
}
}

View File

@ -0,0 +1,6 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Tag
{
public class GetAllTagsRequest
{
}
}

View File

@ -0,0 +1,7 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Tag
{
public class GetTagRequest
{
public string Id { get; set; }
}
}

View File

@ -0,0 +1,8 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Tag
{
public class RemoveParentTagFromTag
{
public string TagId { get; set; }
public string ParentTagId { get; set; }
}
}

View File

@ -0,0 +1,17 @@
using Core.Blueprint.Mongo;
namespace Core.Inventory.External.Clients.Inventory.Requests.Tag
{
public class UpdateTagRequest
{
public string Id { get; set; } = null!;
public string TenantId { get; set; } = null!;
public string TagName { get; set; } = null!;
public string TypeId { get; set; } = null!;
public string[] ParentTagId { get; set; } = null!;
public string Slug { get; set; } = null!;
public int DisplayOrder { get; set; }
public string Icon { get; set; } = null!;
public StatusEnum Status { get; set; }
}
}

View File

@ -0,0 +1,10 @@
using Core.Blueprint.Mongo;
namespace Core.Inventory.External.Clients.Inventory.Requests.TagOverride
{
public class ChangeTagOverrideStatusRequest
{
public string Id { get; set; }
public StatusEnum Status { get; set; }
}
}

View File

@ -0,0 +1,9 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.TagOverride
{
public class CreateTagOverrideRequest
{
public string TenantId { get; set; } = null!;
public string BaseTagId { get; set; } = null!;
public string OverrideTagId { get; set; } = null!;
}
}

View File

@ -0,0 +1,14 @@
using Lib.Architecture.BuildingBlocks;
namespace Core.Inventory.External.Clients.Inventory.Requests.TagOverride
{
public class DeleteTagOverrideRequest : Notificator, ICommand
{
public string Id { get; set; } = null!;
public bool Validate()
{
return Id != null;
}
}
}

View File

@ -0,0 +1,7 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.TagOverride
{
public class GetAllTagOverridesByListRequest
{
public string[] TagOverrides { get; set; }
}
}

View File

@ -0,0 +1,6 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.TagOverride
{
public class GetAllTagOverridesRequest
{
}
}

View File

@ -0,0 +1,7 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.TagOverride
{
public class GetTagOverrideRequest
{
public string Id { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using Core.Blueprint.Mongo;
namespace Core.Inventory.External.Clients.Inventory.Requests.TagOverride
{
public class UpdateTagOverrideRequest
{
public string Id { get; set; } = null!;
public string TenantId { get; set; } = null!;
public string BaseTagId { get; set; } = null!;
public string OverrideTagId { get; set; } = null!;
public StatusEnum Status { get; set; }
}
}

View File

@ -0,0 +1,10 @@
using Core.Blueprint.Mongo;
namespace Core.Inventory.External.Clients.Inventory.Requests.TagType
{
public class ChangeTagTypeStatusRequest
{
public string Id { get; set; }
public StatusEnum Status { get; set; }
}
}

View File

@ -0,0 +1,10 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.TagType
{
public class CreateTagTypeRequest
{
public string TenantId { get; set; } = null!;
public string TypeName { get; set; } = null!;
public int Level { get; set; }
public string ParentTypeId { get; set; } = null!;
}
}

View File

@ -0,0 +1,14 @@
using Lib.Architecture.BuildingBlocks;
namespace Core.Inventory.External.Clients.Inventory.Requests.TagType
{
public class DeleteTagTypeRequest : Notificator, ICommand
{
public string Id { get; set; } = null!;
public bool Validate()
{
return Id != null;
}
}
}

View File

@ -0,0 +1,7 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.TagType
{
public class GetAllTagTypesByListRequest
{
public string[] TagTypes { get; set; }
}
}

View File

@ -0,0 +1,6 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.TagType
{
public class GetAllTagTypesRequest
{
}
}

View File

@ -0,0 +1,7 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.TagType
{
public class GetTagTypeRequest
{
public string Id { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using Core.Blueprint.Mongo;
namespace Core.Inventory.External.Clients.Inventory.Requests.TagType
{
public class UpdateTagTypeRequest
{
public string Id { get; set; } = null!;
public string TenantId { get; set; } = null!;
public string TypeName { get; set; } = null!;
public int Level { get; set; }
public string ParentTypeId { get; set; } = null!;
public StatusEnum Status { get; set; }
}
}

View File

@ -0,0 +1,10 @@
using Core.Blueprint.Mongo;
namespace Core.Inventory.External.Clients.Inventory.Requests.Variant
{
public class ChangeFurnitureVariantStatusRequest
{
public string MongoId { get; set; } = default!;
public StatusEnum Status { get; set; }
}
}

View File

@ -0,0 +1,19 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Variant
{
public class CreateFurnitureVariantRequest
{
public string ModelId { get; set; } = default!;
public string Name { get; set; } = default!;
public string Color { get; set; } = default!;
public string? Line { get; set; }
public decimal Price { get; set; }
public string Currency { get; set; } = "USD";
public int Stock { get; set; }
public string CategoryId { get; set; } = string.Empty;
public string ProviderId { get; set; } = string.Empty;
public Dictionary<string, string> Attributes { get; set; } = [];
}
}

View File

@ -0,0 +1,6 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Variant
{
public class GetAllFurnitureVariantRequest
{
}
}

View File

@ -0,0 +1,7 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Variant
{
public class GetAllFurnitureVariantsByModelIdRequest
{
public string ModelId { get; set; } = default!;
}
}

View File

@ -0,0 +1,7 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Variant
{
public class GetFurnitureVariantByIdRequest
{
public string MongoId { get; set; } = default!;
}
}

View File

@ -0,0 +1,7 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Variant
{
public class GetFurnitureVariantsByIdsRequest
{
public List<string> Ids { get; set; } = [];
}
}

View File

@ -0,0 +1,21 @@
namespace Core.Inventory.External.Clients.Inventory.Requests.Variant
{
public class UpdateFurnitureVariantRequest
{
public string _Id { get; set; } = default!;
public string Id { get; set; } = default!;
public string ModelId { get; set; } = default!;
public string Name { get; set; } = default!;
public string Color { get; set; } = default!;
public string? Line { get; set; }
public int Stock { get; set; }
public decimal Price { get; set; }
public string Currency { get; set; } = "USD";
public string CategoryId { get; set; } = string.Empty;
public string ProviderId { get; set; } = string.Empty;
public Dictionary<string, string> Attributes { get; set; } = new();
}
}

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Core.Adapters.Lib" Version="1.0.0" />
<PackageReference Include="Lib.Architecture.BuildingBlocks" Version="1.0.0" />
<PackageReference Include="Refit" Version="8.0.0" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,19 @@
using Core.Blueprint.External;
namespace Core.Inventory.External.GatewayConfigurations
{
public record GatewayConfiguration
{
public GatewayConfiguration()
{
InventoryService = new InventoryServiceAPI();
}
public InventoryServiceAPI InventoryService { get; set; }
}
public record InventoryServiceAPI
{
public string Channel { get; set; }
public BaseEndpoint Endpoint { get; set; }
}
}

View File

@ -0,0 +1,48 @@
using Core.Blueprint.External;
using Microsoft.Extensions.Configuration;
namespace Core.Inventory.External.GatewayConfigurations
{
public class GatewaySettingsConfigurations
{
private static GatewayConfiguration GatewayConfigurations { get; set; } = new GatewayConfiguration();
private readonly IConfiguration _configuration;
public GatewaySettingsConfigurations(IConfiguration configuration)
{
_configuration = configuration;
SetDashboardServiceAPIEndpoint();
}
public static InventoryServiceAPI GetInventoryServiceAPIEndpoint()
{
return GatewayConfigurations.InventoryService;
}
private GatewayConfiguration SetDashboardServiceAPIEndpoint()
{
IConfigurationSection source;
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? string.Empty;
if (environment == "Local")
source = _configuration.GetSection("LocalGateways");
else
source = _configuration.GetSection("Gateways");
var endpoint = source["InventoryService"] ?? string.Empty;
if (string.IsNullOrEmpty(endpoint)) throw new Exception("Inventory Service endpoint is empty or null");
GatewayConfigurations.InventoryService = new InventoryServiceAPI()
{
Endpoint = new BaseEndpoint()
{
Uri = new Uri(endpoint),
Url = endpoint,
Token = string.Empty,
APIName = "Inventory Service"
}
};
return GatewayConfigurations;
}
}
}

View File

@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Http;
namespace Core.Inventory.External
{
public sealed class TrackingMechanismExtension(IHttpContextAccessor httpContextAccessor) : DelegatingHandler
{
private readonly IHttpContextAccessor _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (_httpContextAccessor.HttpContext != null)
{
request.Headers.Add("TrackingId", Guid.NewGuid().ToString());
}
return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
}
}
}

38
Dockerfile Normal file
View File

@ -0,0 +1,38 @@
# ===== Build stage =====
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
# Usar tu feed (BaGet) + nuget.org
COPY nuget.config ./
# Copiar SOLO los .csproj primero (mejor caché)
COPY Core.Inventory.BFF.API/Core.Inventory.BFF.API.csproj Core.Inventory.BFF.API/
COPY Core.Inventory.External/Core.Inventory.External.csproj Core.Inventory.External/
# Restore con tu nuget.config
RUN dotnet restore Core.Inventory.BFF.API/Core.Inventory.BFF.API.csproj --configfile ./nuget.config
# Copiar el resto del código
COPY . .
# Publicar artefactos
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish Core.Inventory.BFF.API/Core.Inventory.BFF.API.csproj \
-c $BUILD_CONFIGURATION -o /app/out /p:UseAppHost=false
# ===== Runtime stage =====
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
WORKDIR /app
COPY --from=build /app/out .
# Config base
ENV ASPNETCORE_URLS=http://+:8080 \
ASPNETCORE_ENVIRONMENT=Production
EXPOSE 8080
# (Opcional) Healthcheck si tienes endpoint /health
# HEALTHCHECK --interval=30s --timeout=5s --retries=5 \
# CMD wget -qO- http://localhost:8080/health || exit 1
ENTRYPOINT ["dotnet", "Core.Inventory.BFF.API.dll"]

9
nuget.config Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<!-- Tu BaGet primero -->
<add key="BaGet" value="https://nuget.dream-views.com/v3/index.json" protocolVersion="3" />
<!-- NuGet oficial como fallback (si quieres) -->
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
</packageSources>
</configuration>