using LocationsApi.Models; using LocationsApi.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using MongoDB.Driver; namespace LocationsApi.Controllers; [ApiController] [Route("api/[controller]")] public class LocationsController : ControllerBase { private readonly LocationStore _locations; private readonly IConfiguration _cfg; public LocationsController(LocationStore locations, IConfiguration cfg) { _locations = locations; _cfg = cfg; } [HttpPost] [Authorize(Roles = "SUPER")] public async Task 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, CharacterIds = new List(), 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 ListMine() { var locations = await _locations.GetAllAsync(); return Ok(locations); } [HttpDelete("{id}")] [Authorize(Roles = "SUPER")] public async Task Delete(string id) { var deleted = await _locations.DeleteAsync(id); if (!deleted) return NotFound(); return Ok("Deleted"); } [HttpPut("{id}")] [Authorize(Roles = "SUPER")] public async Task 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("presence")] [AllowAnonymous] public async Task UpdatePresence([FromBody] UpdateLocationPresenceRequest req) { var internalKey = _cfg["Internal:Key"]; if (!string.IsNullOrWhiteSpace(internalKey)) { if (!Request.Headers.TryGetValue("X-Internal-Key", out var provided) || provided != internalKey) return Unauthorized(); } if (string.IsNullOrWhiteSpace(req.CharacterId)) return BadRequest("CharacterId required"); if (req.Coord is null) return BadRequest("Coord required"); var updated = await _locations.UpdatePresenceAsync(req.CharacterId.Trim(), req.Coord); if (!updated) return NotFound("Location not found"); return Ok("Updated"); } }