166 lines
5.8 KiB
C#
166 lines
5.8 KiB
C#
using LocationsApi.Models;
|
|
using LocationsApi.Services;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using MongoDB.Driver;
|
|
using System.Net.Http.Headers;
|
|
using System.Security.Claims;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
|
|
namespace LocationsApi.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("api/[controller]")]
|
|
public class LocationsController : ControllerBase
|
|
{
|
|
private readonly LocationStore _locations;
|
|
private readonly IHttpClientFactory _httpClientFactory;
|
|
private readonly IConfiguration _configuration;
|
|
|
|
public LocationsController(LocationStore locations, IHttpClientFactory httpClientFactory, IConfiguration configuration)
|
|
{
|
|
_locations = locations;
|
|
_httpClientFactory = httpClientFactory;
|
|
_configuration = configuration;
|
|
}
|
|
|
|
[HttpPost]
|
|
[Authorize(Roles = "SUPER")]
|
|
public async Task<IActionResult> Create([FromBody] CreateLocationRequest req)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(req.Name))
|
|
return BadRequest("Name required");
|
|
|
|
if (req.Coord is null)
|
|
return BadRequest("Coord required");
|
|
|
|
var location = new Location
|
|
{
|
|
Name = req.Name.Trim(),
|
|
Coord = req.Coord,
|
|
CreatedUtc = DateTime.UtcNow
|
|
};
|
|
|
|
try
|
|
{
|
|
await _locations.CreateAsync(location);
|
|
}
|
|
catch (MongoWriteException ex) when (ex.WriteError.Category == ServerErrorCategory.DuplicateKey)
|
|
{
|
|
return Conflict("Coord must be unique");
|
|
}
|
|
catch (MongoWriteException ex) when (ex.WriteError.Code == 121)
|
|
{
|
|
return BadRequest("Location document failed validation");
|
|
}
|
|
|
|
return Ok(location);
|
|
}
|
|
|
|
[HttpGet]
|
|
[Authorize(Roles = "SUPER")]
|
|
public async Task<IActionResult> ListMine()
|
|
{
|
|
var locations = await _locations.GetAllAsync();
|
|
return Ok(locations);
|
|
}
|
|
|
|
[HttpDelete("{id}")]
|
|
[Authorize(Roles = "SUPER")]
|
|
public async Task<IActionResult> Delete(string id)
|
|
{
|
|
var deleted = await _locations.DeleteAsync(id);
|
|
if (!deleted)
|
|
return NotFound();
|
|
|
|
return Ok("Deleted");
|
|
}
|
|
|
|
[HttpPut("{id}")]
|
|
[Authorize(Roles = "SUPER")]
|
|
public async Task<IActionResult> Update(string id, [FromBody] UpdateLocationRequest req)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(req.Name))
|
|
return BadRequest("Name required");
|
|
|
|
if (req.Coord is not null)
|
|
return BadRequest("Coord cannot be updated");
|
|
|
|
var updated = await _locations.UpdateNameAsync(id, req.Name.Trim());
|
|
if (!updated)
|
|
return NotFound();
|
|
|
|
return Ok("Updated");
|
|
}
|
|
|
|
[HttpPost("{id}/interact")]
|
|
[Authorize(Roles = "USER,SUPER")]
|
|
public async Task<IActionResult> Interact(string id, [FromBody] InteractLocationObjectRequest req)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(req.CharacterId))
|
|
return BadRequest("characterId required");
|
|
if (string.IsNullOrWhiteSpace(req.ObjectId))
|
|
return BadRequest("objectId required");
|
|
|
|
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
|
if (string.IsNullOrWhiteSpace(userId))
|
|
return Unauthorized();
|
|
|
|
var allowAnyOwner = User.IsInRole("SUPER");
|
|
var interact = await _locations.InteractWithObjectAsync(id, req.CharacterId, req.ObjectId, userId, allowAnyOwner);
|
|
if (interact.Status == InteractStatus.LocationNotFound)
|
|
return NotFound("Location not found");
|
|
if (interact.Status == InteractStatus.CharacterNotFound)
|
|
return NotFound("Character not found");
|
|
if (interact.Status == InteractStatus.Forbidden)
|
|
return Forbid();
|
|
if (interact.Status == InteractStatus.Invalid)
|
|
return BadRequest("Character is not at the target location");
|
|
if (interact.Status == InteractStatus.ObjectNotFound)
|
|
return NotFound("Location object not found");
|
|
if (interact.Status == InteractStatus.UnsupportedObjectType)
|
|
return BadRequest("Location object type is not supported");
|
|
if (interact.Status == InteractStatus.ObjectConsumed)
|
|
return Conflict("Location object is consumed");
|
|
|
|
var inventoryBaseUrl = (_configuration["Services:InventoryApiBaseUrl"] ?? "http://localhost:5003").TrimEnd('/');
|
|
var token = Request.Headers.Authorization.ToString();
|
|
var grantBody = JsonSerializer.Serialize(new
|
|
{
|
|
itemKey = interact.ItemKey,
|
|
quantity = interact.QuantityGranted
|
|
});
|
|
|
|
var client = _httpClientFactory.CreateClient();
|
|
using var request = new HttpRequestMessage(
|
|
HttpMethod.Post,
|
|
$"{inventoryBaseUrl}/api/inventory/by-owner/character/{req.CharacterId}/grant");
|
|
request.Content = new StringContent(grantBody, Encoding.UTF8, "application/json");
|
|
if (!string.IsNullOrWhiteSpace(token))
|
|
request.Headers.Authorization = AuthenticationHeaderValue.Parse(token);
|
|
|
|
using var response = await client.SendAsync(request);
|
|
var responseBody = await response.Content.ReadAsStringAsync();
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
if (interact.PreviousObject is not null)
|
|
await _locations.RestoreObjectInteractionAsync(id, interact.PreviousObject);
|
|
return StatusCode((int)response.StatusCode, responseBody);
|
|
}
|
|
|
|
return Ok(new InteractLocationObjectResponse
|
|
{
|
|
LocationId = id,
|
|
CharacterId = req.CharacterId,
|
|
ObjectId = interact.ObjectId,
|
|
ObjectType = interact.ObjectType,
|
|
ItemKey = interact.ItemKey,
|
|
QuantityGranted = interact.QuantityGranted,
|
|
RemainingQuantity = interact.RemainingQuantity,
|
|
Consumed = interact.Consumed,
|
|
InventoryResponseJson = responseBody
|
|
});
|
|
}
|
|
}
|