[backend/api] Fixup basic endpoints
This commit is contained in:
parent
0b98c4226a
commit
a7b47b59b8
5 changed files with 72 additions and 39 deletions
|
@ -1,12 +0,0 @@
|
|||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Backend.Core.Database.Tables;
|
||||
|
||||
namespace Iceshrimp.Backend.Controllers.Renderers;
|
||||
|
||||
public class TimelineRenderer
|
||||
{
|
||||
public static TimelineResponse Render(IEnumerable<Note> notes, int limit)
|
||||
{
|
||||
return new TimelineResponse { Notes = NoteRenderer.RenderMany(notes), Limit = limit };
|
||||
}
|
||||
}
|
10
Iceshrimp.Backend/Controllers/Schemas/PaginationQuery.cs
Normal file
10
Iceshrimp.Backend/Controllers/Schemas/PaginationQuery.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Iceshrimp.Backend.Controllers.Schemas;
|
||||
|
||||
public class PaginationQuery
|
||||
{
|
||||
[FromQuery(Name = "max_id")] public string? MaxId { get; set; }
|
||||
[FromQuery(Name = "min_id")] public string? MinId { get; set; }
|
||||
[FromQuery(Name = "limit")] public int? Limit { get; set; }
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
|
||||
|
||||
namespace Iceshrimp.Backend.Controllers.Schemas;
|
||||
|
||||
public class TimelineResponse
|
||||
{
|
||||
[J("notes")] public required IEnumerable<NoteResponse> Notes { get; set; }
|
||||
[J("limit")] public required int Limit { get; set; }
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
using Iceshrimp.Backend.Controllers.Attributes;
|
||||
using Iceshrimp.Backend.Controllers.Renderers;
|
||||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Backend.Core.Database;
|
||||
using Iceshrimp.Backend.Core.Database.Tables;
|
||||
using Iceshrimp.Backend.Core.Extensions;
|
||||
using Iceshrimp.Backend.Core.Middleware;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.RateLimiting;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
@ -10,7 +11,6 @@ using Microsoft.EntityFrameworkCore;
|
|||
namespace Iceshrimp.Backend.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("User")]
|
||||
[Produces("application/json")]
|
||||
[EnableRateLimiting("sliding")]
|
||||
[Route("/api/iceshrimp/v1/user/{id}")]
|
||||
|
@ -21,28 +21,32 @@ public class UserController(DatabaseContext db) : Controller
|
|||
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ErrorResponse))]
|
||||
public async Task<IActionResult> GetUser(string id)
|
||||
{
|
||||
var user = await db.Users.FirstOrDefaultAsync(p => p.Id == id);
|
||||
if (user == null) return NotFound();
|
||||
return Ok(user);
|
||||
var user = await db.Users.IncludeCommonProperties()
|
||||
.FirstOrDefaultAsync(p => p.Id == id) ??
|
||||
throw GracefulException.NotFound("User not found");
|
||||
|
||||
return Ok(UserRenderer.RenderOne(user));
|
||||
}
|
||||
|
||||
[HttpGet("notes")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(TimelineResponse))]
|
||||
[Authenticate]
|
||||
[LinkPagination(20, 80)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<NoteResponse>))]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ErrorResponse))]
|
||||
public async Task<IActionResult> GetUserNotes(string id)
|
||||
public async Task<IActionResult> GetUserNotes(string id, PaginationQuery pq)
|
||||
{
|
||||
var user = await db.Users.FirstOrDefaultAsync(p => p.Id == id);
|
||||
if (user == null) return NotFound();
|
||||
var localUser = HttpContext.GetUser();
|
||||
var user = await db.Users.FirstOrDefaultAsync(p => p.Id == id) ??
|
||||
throw GracefulException.NotFound("User not found");
|
||||
|
||||
var limit = 10;
|
||||
var notes = db.Notes
|
||||
.Include(p => p.User)
|
||||
.Where(p => p.UserId == id)
|
||||
.HasVisibility(Note.NoteVisibility.Public)
|
||||
.OrderByDescending(p => p.Id)
|
||||
.Take(limit)
|
||||
.ToList();
|
||||
var notes = await db.Notes
|
||||
.IncludeCommonProperties()
|
||||
.Where(p => p.User == user)
|
||||
.EnsureVisibleFor(localUser)
|
||||
.PrecomputeVisibilities(localUser)
|
||||
.Paginate(pq, ControllerContext)
|
||||
.ToListAsync();
|
||||
|
||||
return Ok(TimelineRenderer.Render(notes, limit));
|
||||
return Ok(NoteRenderer.RenderMany(notes.EnforceRenoteReplyVisibility()));
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ using Iceshrimp.Backend.Controllers.Attributes;
|
|||
using Iceshrimp.Backend.Controllers.Mastodon.Renderers;
|
||||
using Iceshrimp.Backend.Controllers.Mastodon.Schemas;
|
||||
using Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
|
||||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Backend.Core.Database;
|
||||
using Iceshrimp.Backend.Core.Database.Tables;
|
||||
using Iceshrimp.Backend.Core.Middleware;
|
||||
|
@ -48,6 +49,45 @@ public static class QueryableExtensions
|
|||
return query.Take(Math.Min(pq.Limit ?? defaultLimit, maxLimit));
|
||||
}
|
||||
|
||||
public static IQueryable<T> Paginate<T>(
|
||||
this IQueryable<T> query,
|
||||
PaginationQuery pq,
|
||||
int defaultLimit,
|
||||
int maxLimit
|
||||
) where T : IEntity
|
||||
{
|
||||
if (pq.Limit is < 1)
|
||||
throw GracefulException.BadRequest("Limit cannot be less than 1");
|
||||
|
||||
query = pq switch
|
||||
{
|
||||
{ MinId: not null, MaxId: not null } => query
|
||||
.Where(p => p.Id.IsGreaterThan(pq.MinId) &&
|
||||
p.Id.IsLessThan(pq.MaxId))
|
||||
.OrderBy(p => p.Id),
|
||||
{ MinId: not null } => query.Where(p => p.Id.IsGreaterThan(pq.MinId)).OrderBy(p => p.Id),
|
||||
{ MaxId: not null } => query.Where(p => p.Id.IsLessThan(pq.MaxId)).OrderByDescending(p => p.Id),
|
||||
_ => query.OrderByDescending(p => p.Id)
|
||||
};
|
||||
|
||||
return query.Take(Math.Min(pq.Limit ?? defaultLimit, maxLimit));
|
||||
}
|
||||
|
||||
public static IQueryable<T> Paginate<T>(
|
||||
this IQueryable<T> query,
|
||||
MastodonPaginationQuery pq,
|
||||
ControllerContext context
|
||||
) where T : IEntity
|
||||
{
|
||||
var filter = context.ActionDescriptor.FilterDescriptors.Select(p => p.Filter)
|
||||
.OfType<LinkPaginationAttribute>()
|
||||
.FirstOrDefault();
|
||||
if (filter == null)
|
||||
throw new GracefulException("Route doesn't have a LinkPaginationAttribute");
|
||||
|
||||
return Paginate(query, pq, filter.DefaultLimit, filter.MaxLimit);
|
||||
}
|
||||
|
||||
public static IQueryable<T> Paginate<T>(
|
||||
this IQueryable<T> query,
|
||||
PaginationQuery pq,
|
||||
|
|
Loading…
Add table
Reference in a new issue