Zeeshaun 9a7d6544ef
All checks were successful
Deploy Promiscuity Auth API / deploy (push) Successful in 46s
Deploy Promiscuity Character API / deploy (push) Successful in 46s
Deploy Promiscuity Locations API / deploy (push) Successful in 46s
k8s smoke test / test (push) Successful in 7s
Adding inventory microservice
2026-03-15 10:21:49 -05:00

249 lines
10 KiB
C#

using InventoryApi.Models;
using InventoryApi.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
namespace InventoryApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class InventoryController : ControllerBase
{
private readonly InventoryStore _inventory;
public InventoryController(InventoryStore inventory)
{
_inventory = inventory;
}
[HttpGet("by-owner/{ownerType}/{ownerId}")]
[Authorize(Roles = "USER,SUPER")]
public async Task<IActionResult> GetByOwner(string ownerType, string ownerId)
{
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (string.IsNullOrWhiteSpace(userId))
return Unauthorized();
var access = await _inventory.ResolveOwnerAsync(ownerType, ownerId, userId, User.IsInRole("SUPER"));
if (!access.IsSupported)
return BadRequest("Unsupported ownerType");
if (!access.Exists)
return NotFound();
if (!access.IsAuthorized)
return Forbid();
var items = await _inventory.GetByOwnerAsync(access.OwnerType, access.OwnerId);
return Ok(new InventoryOwnerResponse
{
OwnerType = access.OwnerType,
OwnerId = access.OwnerId,
Items = items.Select(InventoryItemResponse.FromModel).ToList()
});
}
[HttpPost("by-owner/{ownerType}/{ownerId}/grant")]
[Authorize(Roles = "USER,SUPER")]
public async Task<IActionResult> Grant(string ownerType, string ownerId, [FromBody] GrantInventoryItemRequest req)
{
if (string.IsNullOrWhiteSpace(req.ItemKey))
return BadRequest("itemKey required");
if (req.Quantity <= 0)
return BadRequest("quantity must be greater than 0");
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (string.IsNullOrWhiteSpace(userId))
return Unauthorized();
var access = await _inventory.ResolveOwnerAsync(ownerType, ownerId, userId, User.IsInRole("SUPER"));
if (!access.IsSupported)
return BadRequest("Unsupported ownerType");
if (!access.Exists)
return NotFound();
if (!access.IsAuthorized)
return Forbid();
var items = await _inventory.GrantAsync(access, req);
return Ok(new InventoryOwnerResponse
{
OwnerType = access.OwnerType,
OwnerId = access.OwnerId,
Items = items.Select(InventoryItemResponse.FromModel).ToList()
});
}
[HttpPost("by-owner/{ownerType}/{ownerId}/move")]
[Authorize(Roles = "USER,SUPER")]
public async Task<IActionResult> Move(string ownerType, string ownerId, [FromBody] MoveInventoryItemRequest req)
{
if (string.IsNullOrWhiteSpace(req.ItemId))
return BadRequest("itemId required");
if (req.ToSlot < 0)
return BadRequest("toSlot must be >= 0");
if (req.Quantity is <= 0)
return BadRequest("quantity must be greater than 0");
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (string.IsNullOrWhiteSpace(userId))
return Unauthorized();
var access = await _inventory.ResolveOwnerAsync(ownerType, ownerId, userId, User.IsInRole("SUPER"));
if (!access.IsSupported)
return BadRequest("Unsupported ownerType");
if (!access.Exists)
return NotFound();
if (!access.IsAuthorized)
return Forbid();
var result = await _inventory.MoveAsync(access, req);
return result.Status switch
{
InventoryMutationStatus.ItemNotFound => NotFound(),
InventoryMutationStatus.Invalid => BadRequest("Invalid move"),
InventoryMutationStatus.Conflict => Conflict("Target slot is not available"),
_ => Ok(new InventoryOwnerResponse
{
OwnerType = access.OwnerType,
OwnerId = access.OwnerId,
Items = result.Items.Select(InventoryItemResponse.FromModel).ToList()
})
};
}
[HttpPost("transfer")]
[Authorize(Roles = "USER,SUPER")]
public async Task<IActionResult> Transfer([FromBody] TransferInventoryItemRequest req)
{
if (string.IsNullOrWhiteSpace(req.ItemId))
return BadRequest("itemId required");
if (string.IsNullOrWhiteSpace(req.FromOwnerType) || string.IsNullOrWhiteSpace(req.FromOwnerId))
return BadRequest("from owner required");
if (string.IsNullOrWhiteSpace(req.ToOwnerType) || string.IsNullOrWhiteSpace(req.ToOwnerId))
return BadRequest("to owner required");
if (req.ToSlot is < 0)
return BadRequest("toSlot must be >= 0");
if (req.Quantity is <= 0)
return BadRequest("quantity must be greater than 0");
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (string.IsNullOrWhiteSpace(userId))
return Unauthorized();
var fromAccess = await _inventory.ResolveOwnerAsync(req.FromOwnerType, req.FromOwnerId, userId, User.IsInRole("SUPER"));
if (!fromAccess.IsSupported)
return BadRequest("Unsupported fromOwnerType");
if (!fromAccess.Exists)
return NotFound("Source owner not found");
if (!fromAccess.IsAuthorized)
return Forbid();
var toAccess = await _inventory.ResolveOwnerAsync(req.ToOwnerType, req.ToOwnerId, userId, User.IsInRole("SUPER"));
if (!toAccess.IsSupported)
return BadRequest("Unsupported toOwnerType");
if (!toAccess.Exists)
return NotFound("Target owner not found");
if (!toAccess.IsAuthorized)
return Forbid();
var result = await _inventory.TransferAsync(fromAccess, toAccess, req);
return result.Status switch
{
InventoryMutationStatus.ItemNotFound => NotFound(),
InventoryMutationStatus.Invalid => BadRequest("Invalid transfer"),
InventoryMutationStatus.Conflict => Conflict("Target slot is not available"),
_ => Ok(new TransferInventoryResponse
{
MovedItemId = req.ItemId,
FromOwnerType = fromAccess.OwnerType,
FromOwnerId = fromAccess.OwnerId,
ToOwnerType = toAccess.OwnerType,
ToOwnerId = toAccess.OwnerId,
FromItems = result.Items.Select(InventoryItemResponse.FromModel).Where(x => x.OwnerType == fromAccess.OwnerType && x.OwnerId == fromAccess.OwnerId).ToList(),
ToItems = result.Items.Select(InventoryItemResponse.FromModel).Where(x => x.OwnerType == toAccess.OwnerType && x.OwnerId == toAccess.OwnerId).ToList()
})
};
}
[HttpPost("items/{itemId}/consume")]
[Authorize(Roles = "USER,SUPER")]
public async Task<IActionResult> Consume(string itemId, [FromBody] ConsumeInventoryItemRequest req)
{
if (req.Quantity <= 0)
return BadRequest("quantity must be greater than 0");
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (string.IsNullOrWhiteSpace(userId))
return Unauthorized();
var result = await _inventory.ConsumeAsync(itemId, req.Quantity, userId, User.IsInRole("SUPER"));
return result.Status switch
{
InventoryMutationStatus.ItemNotFound => NotFound(),
InventoryMutationStatus.Invalid => BadRequest("Invalid consume request"),
InventoryMutationStatus.Conflict => Conflict(),
_ => Ok(new InventoryOwnerResponse
{
OwnerType = result.OwnerType,
OwnerId = result.OwnerId,
Items = result.Items.Select(InventoryItemResponse.FromModel).ToList()
})
};
}
[HttpPost("items/{itemId}/equip")]
[Authorize(Roles = "USER,SUPER")]
public async Task<IActionResult> Equip(string itemId, [FromBody] EquipInventoryItemRequest req)
{
if (string.IsNullOrWhiteSpace(req.OwnerId))
return BadRequest("ownerId required");
if (string.IsNullOrWhiteSpace(req.EquipmentSlot))
return BadRequest("equipmentSlot required");
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (string.IsNullOrWhiteSpace(userId))
return Unauthorized();
var result = await _inventory.EquipAsync(itemId, req.OwnerId, req.EquipmentSlot, userId, User.IsInRole("SUPER"));
return result.Status switch
{
InventoryMutationStatus.ItemNotFound => NotFound(),
InventoryMutationStatus.Invalid => BadRequest("Invalid equip request"),
InventoryMutationStatus.Conflict => Conflict("Equipment slot is not available"),
_ => Ok(new InventoryOwnerResponse
{
OwnerType = result.OwnerType,
OwnerId = result.OwnerId,
Items = result.Items.Select(InventoryItemResponse.FromModel).ToList()
})
};
}
[HttpPost("items/{itemId}/unequip")]
[Authorize(Roles = "USER,SUPER")]
public async Task<IActionResult> Unequip(string itemId, [FromBody] UnequipInventoryItemRequest req)
{
if (string.IsNullOrWhiteSpace(req.OwnerId))
return BadRequest("ownerId required");
if (req.PreferredSlot is < 0)
return BadRequest("preferredSlot must be >= 0");
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (string.IsNullOrWhiteSpace(userId))
return Unauthorized();
var result = await _inventory.UnequipAsync(itemId, req.OwnerId, req.PreferredSlot, userId, User.IsInRole("SUPER"));
return result.Status switch
{
InventoryMutationStatus.ItemNotFound => NotFound(),
InventoryMutationStatus.Invalid => BadRequest("Invalid unequip request"),
InventoryMutationStatus.Conflict => Conflict("Inventory slot is not available"),
_ => Ok(new InventoryOwnerResponse
{
OwnerType = result.OwnerType,
OwnerId = result.OwnerId,
Items = result.Items.Select(InventoryItemResponse.FromModel).ToList()
})
};
}
}