mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-26 15:38:45 -07:00
feat: Enhance API endpoints with pagination and new subscription details for players
This commit is contained in:
@@ -112,12 +112,19 @@ public class CustomAvatarItemsController(
|
||||
|
||||
[HttpGet("me")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> Me()
|
||||
public async Task<IActionResult> Me([FromQuery] int skip = 0, [FromQuery] int take = 100)
|
||||
{
|
||||
var pid = this.RequireCurrentPlayerId();
|
||||
var created = await db.CustomAvatarItems
|
||||
skip = Math.Max(0, skip);
|
||||
take = Math.Clamp(take, 1, 100);
|
||||
|
||||
var createdQuery = db.CustomAvatarItems
|
||||
.Where(i => i.CreatorPlayerId == pid)
|
||||
.OrderByDescending(i => i.UpdatedAt)
|
||||
.OrderByDescending(i => i.UpdatedAt);
|
||||
var total = await createdQuery.CountAsync();
|
||||
var created = await createdQuery
|
||||
.Skip(skip)
|
||||
.Take(take)
|
||||
.ToListAsync();
|
||||
var ownedIds = await db.CustomAvatarItemOwnership
|
||||
.Where(o => o.PlayerId == pid)
|
||||
@@ -132,6 +139,8 @@ public class CustomAvatarItemsController(
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
Results = created.Select(ToWire),
|
||||
TotalResults = total,
|
||||
Created = created.Select(ToWire),
|
||||
Owned = owned.Select(ToWire),
|
||||
});
|
||||
@@ -139,15 +148,26 @@ public class CustomAvatarItemsController(
|
||||
|
||||
[HttpGet("owned")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> Owned()
|
||||
public async Task<IActionResult> Owned([FromQuery] int skip = 0, [FromQuery] int take = 100)
|
||||
{
|
||||
var pid = this.RequireCurrentPlayerId();
|
||||
var rows = await db.CustomAvatarItemOwnership
|
||||
skip = Math.Max(0, skip);
|
||||
take = Math.Clamp(take, 1, 100);
|
||||
|
||||
var query = db.CustomAvatarItemOwnership
|
||||
.Where(o => o.PlayerId == pid)
|
||||
.Join(db.CustomAvatarItems, o => o.CustomAvatarItemId, i => i.Id, (o, i) => i)
|
||||
.OrderByDescending(i => i.UpdatedAt)
|
||||
.OrderByDescending(i => i.UpdatedAt);
|
||||
var total = await query.CountAsync();
|
||||
var rows = await query
|
||||
.Skip(skip)
|
||||
.Take(take)
|
||||
.ToListAsync();
|
||||
return Ok(rows.Select(ToWire));
|
||||
return Ok(new
|
||||
{
|
||||
Results = rows.Select(ToWire),
|
||||
TotalResults = total,
|
||||
});
|
||||
}
|
||||
|
||||
[HttpGet("isCreationAllowedForAccount")]
|
||||
|
||||
@@ -1,31 +1,14 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using DorkNet.Server.Auth;
|
||||
using DorkNet.Server.Data;
|
||||
using DorkNet.Server.Data.Entities;
|
||||
|
||||
namespace DorkNet.Server.Controllers.API.GameSight;
|
||||
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class GameSightController(DorkNetDbContext db) : ControllerBase
|
||||
[AllowAnonymous]
|
||||
public class GameSightController : ControllerBase
|
||||
{
|
||||
[HttpPost("api/gamesight/event")]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> Event([FromBody] object? body)
|
||||
{
|
||||
var playerId = this.CurrentPlayerId();
|
||||
if (playerId is null)
|
||||
return Ok(new { Success = true });
|
||||
|
||||
db.ObjectiveProgress.Add(new ObjectiveProgressEntity
|
||||
{
|
||||
PlayerId = playerId.Value,
|
||||
Key = $"gamesight:{Guid.NewGuid():N}",
|
||||
IsCompleted = true,
|
||||
ClearedAt = DateTime.UtcNow,
|
||||
});
|
||||
await db.SaveChangesAsync();
|
||||
return Ok(new { Success = true });
|
||||
}
|
||||
[HttpPost("/api/gamesight/event")]
|
||||
[HttpPost("/data/event")]
|
||||
[HttpPost("/data/heartbeat")]
|
||||
public IActionResult Event() => Ok(new { Success = true });
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ public class PlayerStateController(
|
||||
// values from PlayerEntity.Level / .XP. Default 1/0 when the
|
||||
// account hasn't been seen yet (synthetic ids passed in queries).
|
||||
[HttpGet("api/players/v1/progression/{accountId:long}")]
|
||||
[HttpGet("api/players/v2/progression/{accountId:long}")]
|
||||
public async Task<ActionResult<Progression>> GetProgression(long accountId)
|
||||
{
|
||||
var p = await db.Players
|
||||
@@ -51,12 +52,25 @@ public class PlayerStateController(
|
||||
}
|
||||
|
||||
[HttpPost("api/players/v1/progression/bulk")]
|
||||
[HttpPost("api/players/v2/progression/bulk")]
|
||||
[Consumes("application/x-www-form-urlencoded", "multipart/form-data")]
|
||||
public async Task<ActionResult<List<Progression>>> GetProgressionBulk(
|
||||
[FromForm(Name = "Ids")] string? ids)
|
||||
{
|
||||
var idList = ParseIds(ids).Select(i => (long)i).ToList();
|
||||
if (idList.Count == 0) return Ok(new List<Progression>());
|
||||
return Ok(await BuildProgressionBulkAsync(idList));
|
||||
}
|
||||
|
||||
[HttpGet("api/players/v2/progression/bulk")]
|
||||
public async Task<ActionResult<List<Progression>>> GetProgressionBulkV2Get()
|
||||
{
|
||||
var idList = ParseQueryIds().ToList();
|
||||
return Ok(await BuildProgressionBulkAsync(idList));
|
||||
}
|
||||
|
||||
private async Task<List<Progression>> BuildProgressionBulkAsync(IReadOnlyCollection<long> idList)
|
||||
{
|
||||
if (idList.Count == 0) return new List<Progression>();
|
||||
var rows = await db.Players
|
||||
.Where(p => idList.Contains(p.Id))
|
||||
.Select(p => new Progression
|
||||
@@ -72,26 +86,40 @@ public class PlayerStateController(
|
||||
rows.AddRange(idList
|
||||
.Where(id => !found.Contains((int)id))
|
||||
.Select(id => new Progression { PlayerId = (int)id }));
|
||||
return Ok(rows);
|
||||
return rows;
|
||||
}
|
||||
|
||||
// RecNet.Reputations.GetReputationById — aggregates CheerEntity
|
||||
// by category. Each Cheer* count is the sum of distinct cheers
|
||||
// received from other players in that category.
|
||||
[HttpGet("api/playerReputation/v1/{accountId:long}")]
|
||||
[HttpGet("api/playerReputation/v2/{accountId:long}")]
|
||||
public async Task<ActionResult<Reputation>> GetReputation(long accountId) =>
|
||||
Ok(await BuildReputationAsync(accountId));
|
||||
|
||||
[HttpPost("api/playerReputation/v1/bulk")]
|
||||
[HttpPost("api/playerReputation/v2/bulk")]
|
||||
[Consumes("application/x-www-form-urlencoded", "multipart/form-data")]
|
||||
public async Task<ActionResult<List<Reputation>>> GetReputationBulk(
|
||||
[FromForm(Name = "Ids")] string? ids)
|
||||
{
|
||||
var idList = ParseIds(ids).Select(i => (long)i).ToList();
|
||||
return Ok(await BuildReputationBulkAsync(idList));
|
||||
}
|
||||
|
||||
[HttpGet("api/playerReputation/v2/bulk")]
|
||||
public async Task<ActionResult<List<Reputation>>> GetReputationBulkV2Get()
|
||||
{
|
||||
var idList = ParseQueryIds().ToList();
|
||||
return Ok(await BuildReputationBulkAsync(idList));
|
||||
}
|
||||
|
||||
private async Task<List<Reputation>> BuildReputationBulkAsync(IReadOnlyCollection<long> idList)
|
||||
{
|
||||
var result = new List<Reputation>(idList.Count);
|
||||
foreach (var id in idList)
|
||||
result.Add(await BuildReputationAsync(id));
|
||||
return Ok(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>POST api/playerReputation/v1/cheer/{playerId} — cheer
|
||||
@@ -216,6 +244,23 @@ public class PlayerStateController(
|
||||
.Select(s => int.TryParse(s, out var v) ? v : 0)
|
||||
.Where(v => v != 0);
|
||||
|
||||
private IEnumerable<long> ParseQueryIds()
|
||||
{
|
||||
foreach (var (key, values) in Request.Query)
|
||||
{
|
||||
if (long.TryParse(key, out var keyId) && keyId > 0)
|
||||
yield return keyId;
|
||||
foreach (var value in values)
|
||||
{
|
||||
if (long.TryParse(value, out var valueId) && valueId > 0)
|
||||
yield return valueId;
|
||||
foreach (var part in value.ToString().Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
|
||||
if (long.TryParse(part, out var partId) && partId > 0)
|
||||
yield return partId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RecNet.PlayerReporting.GetModerationBlockDetails
|
||||
// IMPORTANT: returns a single object, not an array. Defaults indicate
|
||||
// "user is not currently blocked / kicked".
|
||||
|
||||
@@ -187,17 +187,31 @@ public class RoomsController(
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// `Rooms.GetById(roomId)` — same shape as ByName.
|
||||
/// `Rooms.GetById(roomId)` — same flat shape as ByName.
|
||||
/// </summary>
|
||||
[HttpGet("api/rooms/v2/{roomId:long}")]
|
||||
[HttpGet("api/rooms/v3/{roomId:long}")]
|
||||
[HttpGet("rooms/{roomId:long}")]
|
||||
public async Task<IActionResult> ById(long roomId)
|
||||
{
|
||||
var r = await rooms.GetByIdAsync(roomId);
|
||||
return Ok(RoomService.ToWireRoom(r ?? Synthetic($"Room_{roomId}", roomId)));
|
||||
}
|
||||
|
||||
[HttpGet("rooms/{roomId:long}")]
|
||||
public async Task<IActionResult> RoomServerById(long roomId)
|
||||
{
|
||||
var room = await rooms.GetByIdAsync(roomId) ?? Synthetic($"Room_{roomId}", roomId);
|
||||
var sceneRows = await db.RoomScenes
|
||||
.Where(s => s.RoomId == room.Id)
|
||||
.OrderBy(s => s.OrderIndex)
|
||||
.ToListAsync();
|
||||
var roles = await db.RoomRoles
|
||||
.Where(r => r.RoomId == room.Id)
|
||||
.ToListAsync();
|
||||
|
||||
return Ok(BuildRoomServerDetails(room, sceneRows, roles: roles));
|
||||
}
|
||||
|
||||
// ── RoomDetails (the boot-critical one) ─────────────────────────────
|
||||
//
|
||||
// /v4/details/{roomId} is hit *during* the matchmaking goto flow.
|
||||
|
||||
Reference in New Issue
Block a user