using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using RadicadeServer.DB; using RadicadeServer.Extensions; using System.Text.Json; namespace RadicadeServer.Clubs; [Route("clubs/subscription")] [Route("clubs/subscriptions")] [Route("api/clubs/v1/subscription")] [Route("api/clubs/v2/subscription")] [Route("api/clubs/v1/subscriptions")] [Route("api/clubs/v2/subscriptions")] public class ClubSubscriptionAPI(RecDBContext db) : Controller { private static readonly string[] TargetIdKeys = { "playerId", "PlayerId", "accountId", "AccountId", "creatorAccountId", "CreatorAccountId", "subscriptionId", "SubscriptionId", "id", "Id", "targetPlayerId", "TargetPlayerId" }; [HttpGet("mine/member")] [HttpGet("my/member")] public IActionResult GetMyMemberships() => Ok(Array.Empty()); [HttpGet("my/subscriptions")] public async Task GetMySubscriptions() { var userId = User.GetUserId(); if (userId == null) return Ok(Array.Empty()); return Ok(await PlayerSubscriptions.SubscriptionIdsAsync(db, userId.Value)); } [HttpGet("my/subscribers")] public async Task GetMySubscribers() { var userId = User.GetUserId(); if (userId == null) return Ok(Array.Empty()); return Ok(await PlayerSubscriptions.SubscriberIdsAsync(db, userId.Value)); } [HttpGet("details/{accountId:long}")] public async Task GetAccountSubscriptionDetails(long accountId) => Ok(new { clubId = PlayerSubscriptions.PersonalClubId(accountId), accountId, subscriberCount = await PlayerSubscriptions.SubscriberCountAsync(db, accountId) }); [HttpGet("details/{subscription}")] public IActionResult GetNamedSubscriptionDetails(string subscription) => Ok(new { }); [HttpGet("subscriberCount/{accountId:long}")] public async Task GetSubscriberCount(long accountId) => Ok(await PlayerSubscriptions.SubscriberCountAsync(db, accountId)); [HttpGet("top/creators")] public async Task GetTopCreators() => Ok(await PlayerSubscriptions.TopCreatorsAsync(db, 100)); [HttpGet("top/creators/count")] public async Task GetTopCreatorCount() => Ok((await PlayerSubscriptions.TopCreatorsAsync(db, int.MaxValue)).Count); [HttpPost("{playerId:long}"), Authorize] public async Task Subscribe(long playerId) { var userId = User.GetUserId(); if (userId == null) return Unauthorized(); if (playerId > 0) await PlayerSubscriptions.SubscribeAsync(db, userId.Value, playerId); return Ok(new { value = PlayerSubscriptions.PersonalClubId(playerId), success = true, errorId = (object?)null, error = (object?)null }); } [HttpPost(""), Authorize] public async Task SubscribeBare() { var userId = User.GetUserId(); if (userId == null) return Unauthorized(); var playerId = await ReadTargetPlayerIdAsync(); if (playerId > 0) await PlayerSubscriptions.SubscribeAsync(db, userId.Value, playerId); return Ok(new { value = PlayerSubscriptions.PersonalClubId(playerId), success = true, errorId = (object?)null, error = (object?)null }); } [HttpDelete("{playerId:long}"), Authorize] [HttpPost("{playerId:long}/unsubscribe"), Authorize] public async Task Unsubscribe(long playerId) { var userId = User.GetUserId(); if (userId == null) return Unauthorized(); if (playerId > 0) await PlayerSubscriptions.UnsubscribeAsync(db, userId.Value, playerId); return Ok(new { success = true, errorId = (object?)null, error = (object?)null }); } [HttpDelete(""), Authorize] public async Task UnsubscribeBare() { var userId = User.GetUserId(); if (userId == null) return Unauthorized(); var playerId = await ReadTargetPlayerIdAsync(); if (playerId > 0) await PlayerSubscriptions.UnsubscribeAsync(db, userId.Value, playerId); return Ok(new { success = true, errorId = (object?)null, error = (object?)null }); } private async Task ReadTargetPlayerIdAsync() { foreach (var key in TargetIdKeys) { var value = Request.Query[key].FirstOrDefault(); if (long.TryParse(value, out var fromQuery) && fromQuery > 0) return fromQuery; } if (Request.HasFormContentType) { var form = await Request.ReadFormAsync(); foreach (var key in TargetIdKeys) { var value = form[key].FirstOrDefault(); if (long.TryParse(value, out var fromForm) && fromForm > 0) return fromForm; } return 0; } if (Request.ContentLength is not > 0) return 0; try { Request.EnableBuffering(); using var reader = new StreamReader(Request.Body, leaveOpen: true); var body = await reader.ReadToEndAsync(); if (Request.Body.CanSeek) Request.Body.Position = 0; if (string.IsNullOrWhiteSpace(body)) return 0; var trimmed = body.Trim(); if (trimmed.StartsWith("{")) { using var document = JsonDocument.Parse(trimmed); if (document.RootElement.ValueKind == JsonValueKind.Object) { foreach (var property in document.RootElement.EnumerateObject()) { if (!TargetIdKeys.Any(key => key.Equals(property.Name, StringComparison.OrdinalIgnoreCase))) continue; if (long.TryParse(property.Value.ToString(), out var fromBody) && fromBody > 0) return fromBody; } } } else if (long.TryParse(trimmed, out var fromRaw) && fromRaw > 0) { return fromRaw; } } catch { } return 0; } }