using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using RadicadeServer.API.Rooms; using RadicadeServer.DB; using RadicadeServer.Extensions; using RadicadeServer.RecNet.Config; using RadicadeServer.RecNet.Rooms; namespace RadicadeServer.API.Rooms.Keys.V1 { [Route("api/roomkeys/v1")] [Route("econ/api/roomkeys/v1")] public class RoomKeysAPI : Controller { private const int DefaultMaxKeysPerRoom = 500; RecDBContext db; public RoomKeysAPI(RecDBContext context) { this.db = context; } [HttpGet("room")] public IActionResult GetRoomKeysForRoom(long? roomId) { if (roomId is not > 0) return Ok(Array.Empty()); return Ok( db.RoomKeys.Where(roomKey => roomKey.RoomId == roomId.Value).ToList() ); } [HttpGet("mine")] public async Task GetOwnedRoomkeys([FromQuery] long? roomId) { var userId = User.GetUserId(); if (roomId == null || userId == null) return Ok(Array.Empty()); var ownedIds = (await db.Unlocks.AsNoTracking() .FirstOrDefaultAsync(unlocks => unlocks.AccountId == userId.Value))?.RoomKeys .FromJson>() ?? new List(); var keys = await db.RoomKeys.AsNoTracking() .Where(key => key.RoomId == roomId.Value && ownedIds.Contains(key.RoomKeyId)) .ToListAsync(); return Ok(keys); } [HttpGet("purchased/{roomKeyId:long}")] public async Task IsRoomKeyPurchased(long roomKeyId) { var userId = User.GetUserId(); if (userId == null || roomKeyId <= 0) return Ok(false); var roomKey = await db.RoomKeys.AsNoTracking() .FirstOrDefaultAsync(key => key.RoomKeyId == roomKeyId); if (roomKey == null) return Ok(false); var unlocks = await db.Unlocks.AsNoTracking() .FirstOrDefaultAsync(row => row.AccountId == userId.Value); var ownedIds = unlocks?.RoomKeys.FromJson>() ?? new List(); return Ok(ownedIds.Contains(roomKeyId)); } [HttpPost("create")] [HttpPost("create/{roomId}")] public async Task CreateRoomKey() { var body = await RoomEconomyPayload.ReadBodyAsync(Request); var roomId = await RoomEconomyPayload.RoomIdAsync(db, Request, body, "roomId", "roomKeyRoomId") ?? ReadRoomIdFromReferrer(); if (roomId is not > 0) return BadRequest(new { Message = "roomId is required." }); var key = new RoomKey { RoomId = roomId.Value, Name = RoomEconomyPayload.String(body, "name", "keyName") ?? "Room Key", Description = RoomEconomyPayload.String(body, "description") ?? string.Empty, Price = (int)(RoomEconomyPayload.Long(body, "price", "tokenPrice", "cost") ?? 0), ReplicationId = RoomEconomyPayload.String(body, "replicationId") ?? Guid.NewGuid().ToString() }; var maxKeys = await MaxKeysPerRoomAsync(); var existing = await db.RoomKeys.CountAsync(existing => existing.RoomId == roomId.Value); if (existing >= maxKeys) { return BadRequest(new { Message = $"A room can have at most {maxKeys} keys." }); } await db.RoomKeys.AddAsync(key); await db.SaveChangesAsync(); return Ok(key); } private long? ReadRoomIdFromReferrer() { var referer = Request.Headers.Referer.FirstOrDefault(); if (!Uri.TryCreate(referer, UriKind.Absolute, out var uri)) return null; var parts = uri.AbsolutePath.Split('/', StringSplitOptions.RemoveEmptyEntries); for (var index = parts.Length - 1; index >= 0; index--) if (long.TryParse(parts[index], out var roomId) && roomId > 0) return roomId; return null; } private string Describe(System.Text.Json.JsonElement? body) { var raw = RoomEconomyPayload.RawBody(Request); if (raw.Length == 0 && body == null) return "(empty)"; if (raw.Length == 0) raw = body?.ToString() ?? ""; return raw.Length <= 1000 ? raw : raw[..1000] + "..."; } private async Task MaxKeysPerRoomAsync() { var config = await db.Config.FirstOrDefaultAsync(); var limit = config?.RoomKeyConfig?.FromJson()?.MaxKeysPerRoom ?? 0; return limit > 0 ? limit : DefaultMaxKeysPerRoom; } } }