249 lines
10 KiB
C#
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()
|
|
})
|
|
};
|
|
}
|
|
}
|