[backend/masto-client] Refactor mastodon entity names to prevent class name conflicts

This commit is contained in:
Laura Hausmann 2024-02-17 00:20:52 +01:00
parent 5bd92d14ac
commit 7fcf9a5179
No known key found for this signature in database
GPG key ID: D044E84C5BE01605
27 changed files with 194 additions and 206 deletions

View file

@ -13,7 +13,6 @@ using Microsoft.EntityFrameworkCore;
using Iceshrimp.Backend.Controllers.Mastodon.Renderers; using Iceshrimp.Backend.Controllers.Mastodon.Renderers;
using Iceshrimp.Backend.Core.Services; using Iceshrimp.Backend.Core.Services;
using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Cors;
using Notification = Iceshrimp.Backend.Core.Database.Tables.Notification;
namespace Iceshrimp.Backend.Controllers.Mastodon; namespace Iceshrimp.Backend.Controllers.Mastodon;
@ -33,7 +32,7 @@ public class AccountController(
) : Controller { ) : Controller {
[HttpGet("verify_credentials")] [HttpGet("verify_credentials")]
[Authorize("read:accounts")] [Authorize("read:accounts")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Account))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(AccountEntity))]
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))]
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))]
public async Task<IActionResult> VerifyUserCredentials() { public async Task<IActionResult> VerifyUserCredentials() {
@ -43,7 +42,7 @@ public class AccountController(
} }
[HttpGet("{id}")] [HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Account))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(AccountEntity))]
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))]
public async Task<IActionResult> GetUser(string id) { public async Task<IActionResult> GetUser(string id) {
var user = await db.Users.IncludeCommonProperties().FirstOrDefaultAsync(p => p.Id == id) var user = await db.Users.IncludeCommonProperties().FirstOrDefaultAsync(p => p.Id == id)
@ -54,7 +53,7 @@ public class AccountController(
[HttpPost("{id}/follow")] [HttpPost("{id}/follow")]
[Authorize("write:follows")] [Authorize("write:follows")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Relationship))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(RelationshipEntity))]
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))]
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))]
//TODO: [FromHybrid] request (bool reblogs, bool notify, bool languages) //TODO: [FromHybrid] request (bool reblogs, bool notify, bool languages)
@ -129,7 +128,7 @@ public class AccountController(
followee.PrecomputedIsFollowedBy = true; followee.PrecomputedIsFollowedBy = true;
} }
var res = new Relationship { var res = new RelationshipEntity {
Id = followee.Id, Id = followee.Id,
Following = followee.PrecomputedIsFollowedBy ?? false, Following = followee.PrecomputedIsFollowedBy ?? false,
FollowedBy = followee.PrecomputedIsFollowing ?? false, FollowedBy = followee.PrecomputedIsFollowing ?? false,
@ -151,7 +150,7 @@ public class AccountController(
[HttpPost("{id}/unfollow")] [HttpPost("{id}/unfollow")]
[Authorize("write:follows")] [Authorize("write:follows")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Relationship))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(RelationshipEntity))]
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))]
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))]
public async Task<IActionResult> UnfollowUser(string id) { public async Task<IActionResult> UnfollowUser(string id) {
@ -195,7 +194,7 @@ public class AccountController(
p.Notifiee == followee && p.Notifier == user)) p.Notifiee == followee && p.Notifier == user))
.ExecuteDeleteAsync(); .ExecuteDeleteAsync();
var res = new Relationship { var res = new RelationshipEntity {
Id = followee.Id, Id = followee.Id,
Following = followee.PrecomputedIsFollowedBy ?? false, Following = followee.PrecomputedIsFollowedBy ?? false,
FollowedBy = followee.PrecomputedIsFollowing ?? false, FollowedBy = followee.PrecomputedIsFollowing ?? false,
@ -217,7 +216,7 @@ public class AccountController(
[HttpGet("relationships")] [HttpGet("relationships")]
[Authorize("read:follows")] [Authorize("read:follows")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Relationship[]))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(RelationshipEntity[]))]
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))]
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))]
public async Task<IActionResult> GetRelationships([FromQuery(Name = "id")] List<string> ids) { public async Task<IActionResult> GetRelationships([FromQuery(Name = "id")] List<string> ids) {
@ -228,7 +227,7 @@ public class AccountController(
.PrecomputeRelationshipData(user) .PrecomputeRelationshipData(user)
.ToListAsync(); .ToListAsync();
var res = users.Select(u => new Relationship { var res = users.Select(u => new RelationshipEntity {
Id = u.Id, Id = u.Id,
Following = u.PrecomputedIsFollowedBy ?? false, Following = u.PrecomputedIsFollowedBy ?? false,
FollowedBy = u.PrecomputedIsFollowing ?? false, FollowedBy = u.PrecomputedIsFollowing ?? false,
@ -253,7 +252,7 @@ public class AccountController(
[Authorize("read:statuses")] [Authorize("read:statuses")]
[LinkPagination(20, 40)] [LinkPagination(20, 40)]
[Produces("application/json")] [Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<Status>))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<StatusEntity>))]
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))]
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))]
public async Task<IActionResult> GetUserStatuses(string id, AccountSchemas.AccountStatusesRequest request, public async Task<IActionResult> GetUserStatuses(string id, AccountSchemas.AccountStatusesRequest request,
@ -276,7 +275,7 @@ public class AccountController(
[HttpGet("{id}/followers")] [HttpGet("{id}/followers")]
[Authenticate("read:accounts")] [Authenticate("read:accounts")]
[LinkPagination(40, 80)] [LinkPagination(40, 80)]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<Account>))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<AccountEntity>))]
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))]
public async Task<IActionResult> GetUserFollowers(string id, PaginationQuery query) { public async Task<IActionResult> GetUserFollowers(string id, PaginationQuery query) {
var user = HttpContext.GetUser(); var user = HttpContext.GetUser();
@ -286,10 +285,10 @@ public class AccountController(
if (user == null || user.Id != account.Id) { if (user == null || user.Id != account.Id) {
if (account.UserProfile?.FFVisibility == UserProfile.UserProfileFFVisibility.Private) if (account.UserProfile?.FFVisibility == UserProfile.UserProfileFFVisibility.Private)
return Ok((List<Account>) []); return Ok((List<AccountEntity>) []);
if (account.UserProfile?.FFVisibility == UserProfile.UserProfileFFVisibility.Followers) if (account.UserProfile?.FFVisibility == UserProfile.UserProfileFFVisibility.Followers)
if (user == null || !await db.Users.AnyAsync(p => p == account && p.Followers.Contains(user))) if (user == null || !await db.Users.AnyAsync(p => p == account && p.Followers.Contains(user)))
return Ok((List<Account>) []); return Ok((List<AccountEntity>) []);
} }
var res = await db.Users var res = await db.Users
@ -305,7 +304,7 @@ public class AccountController(
[HttpGet("{id}/following")] [HttpGet("{id}/following")]
[Authenticate("read:accounts")] [Authenticate("read:accounts")]
[LinkPagination(40, 80)] [LinkPagination(40, 80)]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<Account>))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<AccountEntity>))]
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))]
public async Task<IActionResult> GetUserFollowing(string id, PaginationQuery query) { public async Task<IActionResult> GetUserFollowing(string id, PaginationQuery query) {
var user = HttpContext.GetUser(); var user = HttpContext.GetUser();
@ -315,10 +314,10 @@ public class AccountController(
if (user == null || user.Id != account.Id) { if (user == null || user.Id != account.Id) {
if (account.UserProfile?.FFVisibility == UserProfile.UserProfileFFVisibility.Private) if (account.UserProfile?.FFVisibility == UserProfile.UserProfileFFVisibility.Private)
return Ok((List<Account>) []); return Ok((List<AccountEntity>) []);
if (account.UserProfile?.FFVisibility == UserProfile.UserProfileFFVisibility.Followers) if (account.UserProfile?.FFVisibility == UserProfile.UserProfileFFVisibility.Followers)
if (user == null || !await db.Users.AnyAsync(p => p == account && p.Followers.Contains(user))) if (user == null || !await db.Users.AnyAsync(p => p == account && p.Followers.Contains(user)))
return Ok((List<Account>) []); return Ok((List<AccountEntity>) []);
} }
var res = await db.Users var res = await db.Users
@ -334,7 +333,7 @@ public class AccountController(
[HttpGet("/api/v1/follow_requests")] [HttpGet("/api/v1/follow_requests")]
[Authorize("read:follows")] [Authorize("read:follows")]
[LinkPagination(40, 80)] [LinkPagination(40, 80)]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<Account>))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<AccountEntity>))]
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))]
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))]
public async Task<IActionResult> GetFollowRequests(PaginationQuery query) { public async Task<IActionResult> GetFollowRequests(PaginationQuery query) {
@ -351,7 +350,7 @@ public class AccountController(
[HttpPost("/api/v1/follow_requests/{id}/authorize")] [HttpPost("/api/v1/follow_requests/{id}/authorize")]
[Authorize("write:follows")] [Authorize("write:follows")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Relationship))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(RelationshipEntity))]
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))]
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))]
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))]
@ -402,7 +401,7 @@ public class AccountController(
var relationship = await db.Users.Where(p => id == p.Id) var relationship = await db.Users.Where(p => id == p.Id)
.IncludeCommonProperties() .IncludeCommonProperties()
.PrecomputeRelationshipData(user) .PrecomputeRelationshipData(user)
.Select(u => new Relationship { .Select(u => new RelationshipEntity {
Id = u.Id, Id = u.Id,
Following = u.PrecomputedIsFollowedBy ?? false, Following = u.PrecomputedIsFollowedBy ?? false,
FollowedBy = u.PrecomputedIsFollowing ?? false, FollowedBy = u.PrecomputedIsFollowing ?? false,
@ -428,7 +427,7 @@ public class AccountController(
[HttpPost("/api/v1/follow_requests/{id}/reject")] [HttpPost("/api/v1/follow_requests/{id}/reject")]
[Authorize("write:follows")] [Authorize("write:follows")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Relationship))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(RelationshipEntity))]
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))]
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))]
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))]
@ -462,7 +461,7 @@ public class AccountController(
var relationship = await db.Users.Where(p => id == p.Id) var relationship = await db.Users.Where(p => id == p.Id)
.IncludeCommonProperties() .IncludeCommonProperties()
.PrecomputeRelationshipData(user) .PrecomputeRelationshipData(user)
.Select(u => new Relationship { .Select(u => new RelationshipEntity {
Id = u.Id, Id = u.Id,
Following = u.PrecomputedIsFollowedBy ?? false, Following = u.PrecomputedIsFollowedBy ?? false,
FollowedBy = u.PrecomputedIsFollowing ?? false, FollowedBy = u.PrecomputedIsFollowing ?? false,

View file

@ -1,4 +1,5 @@
using Iceshrimp.Backend.Controllers.Mastodon.Attributes; using Iceshrimp.Backend.Controllers.Mastodon.Attributes;
using Iceshrimp.Backend.Controllers.Mastodon.Schemas;
using Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities; using Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
using Iceshrimp.Backend.Core.Configuration; using Iceshrimp.Backend.Core.Configuration;
using Iceshrimp.Backend.Core.Database; using Iceshrimp.Backend.Core.Database;
@ -23,7 +24,7 @@ public class InstanceController(DatabaseContext db) : Controller {
var instanceCount = await db.Instances.LongCountAsync(); var instanceCount = await db.Instances.LongCountAsync();
//TODO: admin contact //TODO: admin contact
var res = new InstanceInfo(config.Value) { var res = new InstanceInfoResponse(config.Value) {
Stats = new InstanceStats(userCount, noteCount, instanceCount) Stats = new InstanceStats(userCount, noteCount, instanceCount)
}; };

View file

@ -15,7 +15,7 @@ namespace Iceshrimp.Backend.Controllers.Mastodon;
[EnableCors("mastodon")] [EnableCors("mastodon")]
[EnableRateLimiting("sliding")] [EnableRateLimiting("sliding")]
[Produces("application/json")] [Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Attachment))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(AttachmentEntity))]
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))]
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))]
public class MediaController(DriveService driveSvc) : Controller { public class MediaController(DriveService driveSvc) : Controller {
@ -31,9 +31,9 @@ public class MediaController(DriveService driveSvc) : Controller {
MimeType = request.File.ContentType, MimeType = request.File.ContentType,
}; };
var file = await driveSvc.StoreFile(request.File.OpenReadStream(), user, rq); var file = await driveSvc.StoreFile(request.File.OpenReadStream(), user, rq);
var res = new Attachment { var res = new AttachmentEntity {
Id = file.Id, Id = file.Id,
Type = Attachment.GetType(file.Type), Type = AttachmentEntity.GetType(file.Type),
Url = file.Url, Url = file.Url,
Blurhash = file.Blurhash, Blurhash = file.Blurhash,
Description = file.Comment, Description = file.Comment,

View file

@ -24,7 +24,7 @@ public class NotificationController(DatabaseContext db, NotificationRenderer not
[Authorize("read:notifications")] [Authorize("read:notifications")]
[LinkPagination(40, 80)] [LinkPagination(40, 80)]
[Produces("application/json")] [Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List<Notification>))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List<NotificationEntity>))]
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))]
public async Task<IActionResult> GetNotifications(PaginationQuery query) { public async Task<IActionResult> GetNotifications(PaginationQuery query) {
var user = HttpContext.GetUserOrFail(); var user = HttpContext.GetUserOrFail();

View file

@ -15,9 +15,9 @@ public class NoteRenderer(
MfmConverter mfmConverter, MfmConverter mfmConverter,
DatabaseContext db DatabaseContext db
) { ) {
public async Task<Status> RenderAsync( public async Task<StatusEntity> RenderAsync(
Note note, User? user, List<Account>? accounts = null, List<Mention>? mentions = null, Note note, User? user, List<AccountEntity>? accounts = null, List<MentionEntity>? mentions = null,
List<Attachment>? attachments = null, Dictionary<string, int>? likeCounts = null, List<AttachmentEntity>? attachments = null, Dictionary<string, int>? likeCounts = null,
List<string>? likedNotes = null, int recurse = 2 List<string>? likedNotes = null, int recurse = 2
) { ) {
var uri = note.Uri ?? note.GetPublicUri(config.Value); var uri = note.Uri ?? note.GetPublicUri(config.Value);
@ -32,7 +32,7 @@ public class NoteRenderer(
if (mentions == null) { if (mentions == null) {
mentions = await db.Users.IncludeCommonProperties() mentions = await db.Users.IncludeCommonProperties()
.Where(p => note.Mentions.Contains(p.Id)) .Where(p => note.Mentions.Contains(p.Id))
.Select(u => new Mention(u, config.Value.WebDomain)) .Select(u => new MentionEntity(u, config.Value.WebDomain))
.ToListAsync(); .ToListAsync();
} }
else { else {
@ -41,7 +41,7 @@ public class NoteRenderer(
if (attachments == null) { if (attachments == null) {
attachments = await db.DriveFiles.Where(p => note.FileIds.Contains(p.Id)) attachments = await db.DriveFiles.Where(p => note.FileIds.Contains(p.Id))
.Select(f => new Attachment { .Select(f => new AttachmentEntity {
Id = f.Id, Id = f.Id,
Url = f.WebpublicUrl ?? f.Url, Url = f.WebpublicUrl ?? f.Url,
Blurhash = f.Blurhash, Blurhash = f.Blurhash,
@ -49,7 +49,7 @@ public class NoteRenderer(
Description = f.Comment, Description = f.Comment,
Metadata = null, Metadata = null,
RemoteUrl = f.Uri, RemoteUrl = f.Uri,
Type = Attachment.GetType(f.Type) Type = AttachmentEntity.GetType(f.Type)
}) })
.ToListAsync(); .ToListAsync();
} }
@ -70,7 +70,7 @@ public class NoteRenderer(
var account = accounts?.FirstOrDefault(p => p.Id == note.UserId) ?? await userRenderer.RenderAsync(note.User); var account = accounts?.FirstOrDefault(p => p.Id == note.UserId) ?? await userRenderer.RenderAsync(note.User);
var res = new Status { var res = new StatusEntity {
Id = note.Id, Id = note.Id,
Uri = uri, Uri = uri,
Url = note.Url ?? uri, Url = note.Url ?? uri,
@ -91,7 +91,7 @@ public class NoteRenderer(
IsMuted = null, //FIXME IsMuted = null, //FIXME
IsSensitive = note.Cw != null, IsSensitive = note.Cw != null,
ContentWarning = note.Cw ?? "", ContentWarning = note.Cw ?? "",
Visibility = Status.EncodeVisibility(note.Visibility), Visibility = StatusEntity.EncodeVisibility(note.Visibility),
Content = content, Content = content,
Text = text, Text = text,
Mentions = mentions, Mentions = mentions,
@ -102,18 +102,18 @@ public class NoteRenderer(
return res; return res;
} }
private async Task<List<Mention>> GetMentions(IEnumerable<Note> notes) { private async Task<List<MentionEntity>> GetMentions(IEnumerable<Note> notes) {
var ids = notes.SelectMany(n => n.Mentions).Distinct(); var ids = notes.SelectMany(n => n.Mentions).Distinct();
return await db.Users.IncludeCommonProperties() return await db.Users.IncludeCommonProperties()
.Where(p => ids.Contains(p.Id)) .Where(p => ids.Contains(p.Id))
.Select(u => new Mention(u, config.Value.WebDomain)) .Select(u => new MentionEntity(u, config.Value.WebDomain))
.ToListAsync(); .ToListAsync();
} }
private async Task<List<Attachment>> GetAttachments(IEnumerable<Note> notes) { private async Task<List<AttachmentEntity>> GetAttachments(IEnumerable<Note> notes) {
var ids = notes.SelectMany(n => n.FileIds).Distinct(); var ids = notes.SelectMany(n => n.FileIds).Distinct();
return await db.DriveFiles.Where(p => ids.Contains(p.Id)) return await db.DriveFiles.Where(p => ids.Contains(p.Id))
.Select(f => new Attachment { .Select(f => new AttachmentEntity {
Id = f.Id, Id = f.Id,
Url = f.Url, Url = f.Url,
Blurhash = f.Blurhash, Blurhash = f.Blurhash,
@ -121,12 +121,12 @@ public class NoteRenderer(
Description = f.Comment, Description = f.Comment,
Metadata = null, Metadata = null,
RemoteUrl = f.Uri, RemoteUrl = f.Uri,
Type = Attachment.GetType(f.Type) Type = AttachmentEntity.GetType(f.Type)
}) })
.ToListAsync(); .ToListAsync();
} }
internal async Task<List<Account>> GetAccounts(IEnumerable<User> users) { internal async Task<List<AccountEntity>> GetAccounts(IEnumerable<User> users) {
return (await userRenderer.RenderManyAsync(users.DistinctBy(p => p.Id))).ToList(); return (await userRenderer.RenderManyAsync(users.DistinctBy(p => p.Id))).ToList();
} }
@ -142,8 +142,8 @@ public class NoteRenderer(
.ToListAsync(); .ToListAsync();
} }
public async Task<IEnumerable<Status>> RenderManyAsync( public async Task<IEnumerable<StatusEntity>> RenderManyAsync(
IEnumerable<Note> notes, User? user, List<Account>? accounts = null IEnumerable<Note> notes, User? user, List<AccountEntity>? accounts = null
) { ) {
var noteList = notes.ToList(); var noteList = notes.ToList();
accounts ??= await GetAccounts(noteList.Select(p => p.User)); accounts ??= await GetAccounts(noteList.Select(p => p.User));

View file

@ -2,14 +2,12 @@ using Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
using Iceshrimp.Backend.Core.Database.Tables; using Iceshrimp.Backend.Core.Database.Tables;
using Iceshrimp.Backend.Core.Extensions; using Iceshrimp.Backend.Core.Extensions;
using Iceshrimp.Backend.Core.Middleware; using Iceshrimp.Backend.Core.Middleware;
using Notification = Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities.Notification;
using DbNotification = Iceshrimp.Backend.Core.Database.Tables.Notification;
namespace Iceshrimp.Backend.Controllers.Mastodon.Renderers; namespace Iceshrimp.Backend.Controllers.Mastodon.Renderers;
public class NotificationRenderer(NoteRenderer noteRenderer, UserRenderer userRenderer) { public class NotificationRenderer(NoteRenderer noteRenderer, UserRenderer userRenderer) {
public async Task<Notification> RenderAsync( public async Task<NotificationEntity> RenderAsync(
DbNotification notification, User? user, List<Account>? accounts = null, IEnumerable<Status>? statuses = null Notification notification, User? user, List<AccountEntity>? accounts = null, IEnumerable<StatusEntity>? statuses = null
) { ) {
var dbNotifier = notification.Notifier ?? throw new GracefulException("Notification has no notifier"); var dbNotifier = notification.Notifier ?? throw new GracefulException("Notification has no notifier");
@ -23,9 +21,9 @@ public class NotificationRenderer(NoteRenderer noteRenderer, UserRenderer userRe
//TODO: specially handle quotes //TODO: specially handle quotes
var res = new Notification { var res = new NotificationEntity {
Id = notification.Id, Id = notification.Id,
Type = Notification.EncodeType(notification.Type), Type = NotificationEntity.EncodeType(notification.Type),
Note = note, Note = note,
Notifier = notifier, Notifier = notifier,
CreatedAt = notification.CreatedAt.ToStringMastodon() CreatedAt = notification.CreatedAt.ToStringMastodon()
@ -34,8 +32,8 @@ public class NotificationRenderer(NoteRenderer noteRenderer, UserRenderer userRe
return res; return res;
} }
public async Task<IEnumerable<Notification>> RenderManyAsync( public async Task<IEnumerable<NotificationEntity>> RenderManyAsync(
IEnumerable<DbNotification> notifications, User? user IEnumerable<Notification> notifications, User? user
) { ) {
var notificationList = notifications.ToList(); var notificationList = notifications.ToList();

View file

@ -10,12 +10,12 @@ namespace Iceshrimp.Backend.Controllers.Mastodon.Renderers;
public class UserRenderer(IOptions<Config.InstanceSection> config, MfmConverter mfmConverter) { public class UserRenderer(IOptions<Config.InstanceSection> config, MfmConverter mfmConverter) {
private readonly string _transparent = $"https://{config.Value.WebDomain}/assets/transparent.png"; private readonly string _transparent = $"https://{config.Value.WebDomain}/assets/transparent.png";
public async Task<Account> RenderAsync(User user, UserProfile? profile) { public async Task<AccountEntity> RenderAsync(User user, UserProfile? profile) {
var acct = user.Username; var acct = user.Username;
if (user.Host != null) if (user.Host != null)
acct += $"@{user.Host}"; acct += $"@{user.Host}";
var res = new Account { var res = new AccountEntity {
Id = user.Id, Id = user.Id,
DisplayName = user.DisplayName ?? user.Username, DisplayName = user.DisplayName ?? user.Username,
AvatarUrl = user.AvatarUrl ?? user.GetIdenticonUrl(config.Value), AvatarUrl = user.AvatarUrl ?? user.GetIdenticonUrl(config.Value),
@ -41,11 +41,11 @@ public class UserRenderer(IOptions<Config.InstanceSection> config, MfmConverter
return res; return res;
} }
public async Task<Account> RenderAsync(User user) { public async Task<AccountEntity> RenderAsync(User user) {
return await RenderAsync(user, user.UserProfile); return await RenderAsync(user, user.UserProfile);
} }
public async Task<IEnumerable<Account>> RenderManyAsync(IEnumerable<User> users) { public async Task<IEnumerable<AccountEntity>> RenderManyAsync(IEnumerable<User> users) {
return await users.Select(RenderAsync).AwaitAllAsync(); return await users.Select(RenderAsync).AwaitAllAsync();
} }
} }

View file

@ -1,36 +0,0 @@
using Iceshrimp.Backend.Core.Database;
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
public class Account : IEntity {
[J("username")] public required string Username { get; set; }
[J("acct")] public required string Acct { get; set; }
[J("fqn")] public required string FullyQualifiedName { get; set; }
[J("display_name")] public required string DisplayName { get; set; }
[J("locked")] public required bool IsLocked { get; set; }
[J("created_at")] public required string CreatedAt { get; set; }
[J("followers_count")] public required long FollowersCount { get; set; }
[J("following_count")] public required long FollowingCount { get; set; }
[J("statuses_count")] public required long StatusesCount { get; set; }
[J("note")] public required string Note { get; set; }
[J("url")] public required string Url { get; set; }
[J("avatar")] public required string AvatarUrl { get; set; }
[J("avatar_static")] public required string AvatarStaticUrl { get; set; }
[J("header")] public required string HeaderUrl { get; set; }
[J("header_static")] public required string HeaderStaticUrl { get; set; }
[J("moved")] public required Account? MovedToAccount { get; set; }
[J("bot")] public required bool IsBot { get; set; }
[J("discoverable")] public required bool IsDiscoverable { get; set; }
[J("fields")] public required Field[] Fields { get; set; }
[J("source")] public object? Source => null; //FIXME
[J("emojis")] public object[] Emoji => []; //FIXME
[J("id")] public required string Id { get; set; }
}
public class Field {
[J("name")] public required string Name { get; set; }
[J("value")] public required string Value { get; set; }
[J("verified_at")] public string? VerifiedAt { get; set; }
}

View file

@ -0,0 +1,36 @@
using Iceshrimp.Backend.Core.Database;
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
public class AccountEntity : IEntity {
[J("username")] public required string Username { get; set; }
[J("acct")] public required string Acct { get; set; }
[J("fqn")] public required string FullyQualifiedName { get; set; }
[J("display_name")] public required string DisplayName { get; set; }
[J("locked")] public required bool IsLocked { get; set; }
[J("created_at")] public required string CreatedAt { get; set; }
[J("followers_count")] public required long FollowersCount { get; set; }
[J("following_count")] public required long FollowingCount { get; set; }
[J("statuses_count")] public required long StatusesCount { get; set; }
[J("note")] public required string Note { get; set; }
[J("url")] public required string Url { get; set; }
[J("avatar")] public required string AvatarUrl { get; set; }
[J("avatar_static")] public required string AvatarStaticUrl { get; set; }
[J("header")] public required string HeaderUrl { get; set; }
[J("header_static")] public required string HeaderStaticUrl { get; set; }
[J("moved")] public required AccountEntity? MovedToAccount { get; set; }
[J("bot")] public required bool IsBot { get; set; }
[J("discoverable")] public required bool IsDiscoverable { get; set; }
[J("fields")] public required Field[] Fields { get; set; }
[J("source")] public object? Source => null; //FIXME
[J("emojis")] public object[] Emoji => []; //FIXME
[J("id")] public required string Id { get; set; }
}
public class Field {
[J("name")] public required string Name { get; set; }
[J("value")] public required string Value { get; set; }
[J("verified_at")] public string? VerifiedAt { get; set; }
}

View file

@ -2,7 +2,7 @@ using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities; namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
public class Attachment { public class AttachmentEntity {
[J("id")] public required string Id { get; set; } [J("id")] public required string Id { get; set; }
[J("url")] public required string Url { get; set; } [J("url")] public required string Url { get; set; }
[J("remote_url")] public string? RemoteUrl { get; set; } [J("remote_url")] public string? RemoteUrl { get; set; }

View file

@ -5,7 +5,7 @@ using JI = System.Text.Json.Serialization.JsonIgnoreAttribute;
namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities; namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
public class Mention() { public class MentionEntity() {
[J("id")] public required string Id { get; set; } [J("id")] public required string Id { get; set; }
[J("username")] public required string Username { get; set; } [J("username")] public required string Username { get; set; }
[J("acct")] public required string Acct { get; set; } [J("acct")] public required string Acct { get; set; }
@ -16,7 +16,7 @@ public class Mention() {
[JI] public required string? Host; [JI] public required string? Host;
[SetsRequiredMembers] [SetsRequiredMembers]
public Mention(User u, string webDomain) : this() { public MentionEntity(User u, string webDomain) : this() {
Id = u.Id; Id = u.Id;
Username = u.Username; Username = u.Username;
Host = u.Host; Host = u.Host;

View file

@ -5,12 +5,12 @@ using static Iceshrimp.Backend.Core.Database.Tables.Notification;
namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities; namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
public class Notification : IEntity { public class NotificationEntity : IEntity {
[J("id")] public required string Id { get; set; } [J("id")] public required string Id { get; set; }
[J("created_at")] public required string CreatedAt { get; set; } [J("created_at")] public required string CreatedAt { get; set; }
[J("type")] public required string Type { get; set; } [J("type")] public required string Type { get; set; }
[J("account")] public required Account Notifier { get; set; } [J("account")] public required AccountEntity Notifier { get; set; }
[J("status")] public required Status? Note { get; set; } [J("status")] public required StatusEntity? Note { get; set; }
//TODO: [J("reaction")] public required Reaction? Reaction { get; set; } //TODO: [J("reaction")] public required Reaction? Reaction { get; set; }

View file

@ -5,7 +5,7 @@ using JI = System.Text.Json.Serialization.JsonIgnoreAttribute;
namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities; namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
public class Relationship : IEntity { public class RelationshipEntity : IEntity {
[J("following")] public required bool Following { get; set; } [J("following")] public required bool Following { get; set; }
[J("followed_by")] public required bool FollowedBy { get; set; } [J("followed_by")] public required bool FollowedBy { get; set; }
[J("blocking")] public required bool Blocking { get; set; } [J("blocking")] public required bool Blocking { get; set; }

View file

@ -1,77 +0,0 @@
using System.Text.Json.Serialization;
using Iceshrimp.Backend.Core.Database;
using Iceshrimp.Backend.Core.Database.Tables;
using Iceshrimp.Backend.Core.Middleware;
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
using JI = System.Text.Json.Serialization.JsonIgnoreAttribute;
namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
public class Status : IEntity {
[J("text")] [JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
public required string? Text;
[J("uri")] public required string Uri { get; set; }
[J("url")] public required string Url { get; set; }
[J("account")] public required Account Account { get; set; }
[J("in_reply_to_id")] public required string? ReplyId { get; set; }
[J("in_reply_to_account_id")] public required string? ReplyUserId { get; set; }
[J("reblog")] public required Status? Renote { get; set; }
[J("quote")] public required Status? Quote { get; set; }
[J("content_type")] public required string ContentType { get; set; }
[J("created_at")] public required string CreatedAt { get; set; }
[J("edited_at")] public required string? EditedAt { get; set; }
[J("replies_count")] public required long RepliesCount { get; set; }
[J("reblogs_count")] public required long RenoteCount { get; set; }
[J("favourites_count")] public required long FavoriteCount { get; set; }
[J("reblogged")] public required bool? IsRenoted { get; set; }
[J("favourited")] public required bool? IsFavorited { get; set; }
[J("bookmarked")] public required bool? IsBookmarked { get; set; }
[J("muted")] public required bool? IsMuted { get; set; }
[J("sensitive")] public required bool IsSensitive { get; set; }
[J("spoiler_text")] public required string ContentWarning { get; set; }
[J("visibility")] public required string Visibility { get; set; }
[J("content")]
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
public required string? Content { get; set; }
[J("pinned")]
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
public required bool? IsPinned { get; set; }
[J("mentions")] public required List<Mention> Mentions { get; set; }
[J("media_attachments")] public required List<Attachment> Attachments { get; set; }
[J("emojis")] public object[] Emojis => []; //FIXME
[J("tags")] public object[] Tags => []; //FIXME
[J("reactions")] public object[] Reactions => []; //FIXME
[J("filtered")] public object[] Filtered => []; //FIXME
[J("card")] public object? Card => null; //FIXME
[J("poll")] public object? Poll => null; //FIXME
[J("application")] public object? Application => null; //FIXME
[J("language")] public string? Language => null; //FIXME
[J("id")] public required string Id { get; set; }
public static string EncodeVisibility(Note.NoteVisibility visibility) {
return visibility switch {
Note.NoteVisibility.Public => "public",
Note.NoteVisibility.Home => "unlisted",
Note.NoteVisibility.Followers => "private",
Note.NoteVisibility.Specified => "direct",
_ => throw new GracefulException($"Unknown visibility: {visibility}")
};
}
public static Note.NoteVisibility DecodeVisibility(string visibility) {
return visibility switch {
"public" => Note.NoteVisibility.Public,
"unlisted" => Note.NoteVisibility.Home,
"private" => Note.NoteVisibility.Followers,
"direct" => Note.NoteVisibility.Specified,
_ => throw GracefulException.BadRequest($"Unknown visibility: {visibility}")
};
}
}

View file

@ -1,8 +0,0 @@
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
public class StatusContext {
[J("ancestors")] public required List<Status> Ancestors { get; set; }
[J("descendants")] public required List<Status> Descendants { get; set; }
}

View file

@ -0,0 +1,82 @@
using System.Text.Json.Serialization;
using Iceshrimp.Backend.Core.Database;
using Iceshrimp.Backend.Core.Database.Tables;
using Iceshrimp.Backend.Core.Middleware;
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
using JI = System.Text.Json.Serialization.JsonIgnoreAttribute;
namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
public class StatusEntity : IEntity {
[J("text")] [JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
public required string? Text;
[J("uri")] public required string Uri { get; set; }
[J("url")] public required string Url { get; set; }
[J("account")] public required AccountEntity Account { get; set; }
[J("in_reply_to_id")] public required string? ReplyId { get; set; }
[J("in_reply_to_account_id")] public required string? ReplyUserId { get; set; }
[J("reblog")] public required StatusEntity? Renote { get; set; }
[J("quote")] public required StatusEntity? Quote { get; set; }
[J("content_type")] public required string ContentType { get; set; }
[J("created_at")] public required string CreatedAt { get; set; }
[J("edited_at")] public required string? EditedAt { get; set; }
[J("replies_count")] public required long RepliesCount { get; set; }
[J("reblogs_count")] public required long RenoteCount { get; set; }
[J("favourites_count")] public required long FavoriteCount { get; set; }
[J("reblogged")] public required bool? IsRenoted { get; set; }
[J("favourited")] public required bool? IsFavorited { get; set; }
[J("bookmarked")] public required bool? IsBookmarked { get; set; }
[J("muted")] public required bool? IsMuted { get; set; }
[J("sensitive")] public required bool IsSensitive { get; set; }
[J("spoiler_text")] public required string ContentWarning { get; set; }
[J("visibility")] public required string Visibility { get; set; }
[J("content")]
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
public required string? Content { get; set; }
[J("pinned")]
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
public required bool? IsPinned { get; set; }
[J("mentions")] public required List<MentionEntity> Mentions { get; set; }
[J("media_attachments")] public required List<AttachmentEntity> Attachments { get; set; }
[J("emojis")] public object[] Emojis => []; //FIXME
[J("tags")] public object[] Tags => []; //FIXME
[J("reactions")] public object[] Reactions => []; //FIXME
[J("filtered")] public object[] Filtered => []; //FIXME
[J("card")] public object? Card => null; //FIXME
[J("poll")] public object? Poll => null; //FIXME
[J("application")] public object? Application => null; //FIXME
[J("language")] public string? Language => null; //FIXME
[J("id")] public required string Id { get; set; }
public static string EncodeVisibility(Note.NoteVisibility visibility) {
return visibility switch {
Note.NoteVisibility.Public => "public",
Note.NoteVisibility.Home => "unlisted",
Note.NoteVisibility.Followers => "private",
Note.NoteVisibility.Specified => "direct",
_ => throw new GracefulException($"Unknown visibility: {visibility}")
};
}
public static Note.NoteVisibility DecodeVisibility(string visibility) {
return visibility switch {
"public" => Note.NoteVisibility.Public,
"unlisted" => Note.NoteVisibility.Home,
"private" => Note.NoteVisibility.Followers,
"direct" => Note.NoteVisibility.Specified,
_ => throw GracefulException.BadRequest($"Unknown visibility: {visibility}")
};
}
}
public class StatusContext {
[J("ancestors")] public required List<StatusEntity> Ancestors { get; set; }
[J("descendants")] public required List<StatusEntity> Descendants { get; set; }
}

View file

@ -1,9 +1,9 @@
using Iceshrimp.Backend.Core.Configuration; using Iceshrimp.Backend.Core.Configuration;
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute; using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities; namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas;
public class InstanceInfo(Config config) { public class InstanceInfoResponse(Config config) {
[J("version")] public string Version => $"4.2.1 (compatible; Iceshrimp.NET/{config.Instance.Version}"; [J("version")] public string Version => $"4.2.1 (compatible; Iceshrimp.NET/{config.Instance.Version}";
[J("max_toot_chars")] public int MaxNoteChars => config.Instance.CharacterLimit; [J("max_toot_chars")] public int MaxNoteChars => config.Instance.CharacterLimit;

View file

@ -17,8 +17,8 @@ public abstract class SearchSchemas {
} }
public class SearchResponse { public class SearchResponse {
[J("accounts")] public required List<Account> Accounts { get; set; } [J("accounts")] public required List<AccountEntity> Accounts { get; set; }
[J("statuses")] public required List<Status> Statuses { get; set; } [J("statuses")] public required List<StatusEntity> Statuses { get; set; }
[J("hashtags")] public List<object> Hashtags => []; //TODO: implement this [J("hashtags")] public List<object> Hashtags => []; //TODO: implement this
} }
} }

View file

@ -49,7 +49,7 @@ public class SearchController(
[SuppressMessage("ReSharper", "EntityFramework.UnsupportedServerSideFunctionCall", [SuppressMessage("ReSharper", "EntityFramework.UnsupportedServerSideFunctionCall",
Justification = "Inspection doesn't know about the Projectable attribute")] Justification = "Inspection doesn't know about the Projectable attribute")]
private async Task<List<Account>> SearchUsersAsync(SearchSchemas.SearchRequest search, PaginationQuery pagination) { private async Task<List<AccountEntity>> SearchUsersAsync(SearchSchemas.SearchRequest search, PaginationQuery pagination) {
var user = HttpContext.GetUserOrFail(); var user = HttpContext.GetUserOrFail();
if (search.Resolve) { if (search.Resolve) {
@ -105,7 +105,7 @@ public class SearchController(
[SuppressMessage("ReSharper", "EntityFramework.UnsupportedServerSideFunctionCall", [SuppressMessage("ReSharper", "EntityFramework.UnsupportedServerSideFunctionCall",
Justification = "Inspection doesn't know about the Projectable attribute")] Justification = "Inspection doesn't know about the Projectable attribute")]
private async Task<List<Status>> SearchNotesAsync(SearchSchemas.SearchRequest search, PaginationQuery pagination) { private async Task<List<StatusEntity>> SearchNotesAsync(SearchSchemas.SearchRequest search, PaginationQuery pagination) {
var user = HttpContext.GetUserOrFail(); var user = HttpContext.GetUserOrFail();
if (search.Resolve && (search.Query!.StartsWith("https://") || search.Query.StartsWith("http://"))) { if (search.Resolve && (search.Query!.StartsWith("https://") || search.Query.StartsWith("http://"))) {

View file

@ -29,7 +29,7 @@ public class StatusController(
[HttpGet("{id}")] [HttpGet("{id}")]
[Authenticate("read:statuses")] [Authenticate("read:statuses")]
[Produces("application/json")] [Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Status))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(StatusEntity))]
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))]
public async Task<IActionResult> GetNote(string id) { public async Task<IActionResult> GetNote(string id) {
var user = HttpContext.GetUser(); var user = HttpContext.GetUser();
@ -47,7 +47,7 @@ public class StatusController(
[HttpGet("{id}/context")] [HttpGet("{id}/context")]
[Authenticate("read:statuses")] [Authenticate("read:statuses")]
[Produces("application/json")] [Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Status))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(StatusEntity))]
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))]
public async Task<IActionResult> GetStatusContext(string id) { public async Task<IActionResult> GetStatusContext(string id) {
var user = HttpContext.GetUser(); var user = HttpContext.GetUser();
@ -81,7 +81,7 @@ public class StatusController(
[HttpPost("{id}/favourite")] [HttpPost("{id}/favourite")]
[Authorize("write:favourites")] [Authorize("write:favourites")]
[Produces("application/json")] [Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Status))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(StatusEntity))]
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))]
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))]
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))]
@ -100,7 +100,7 @@ public class StatusController(
[HttpPost("{id}/unfavourite")] [HttpPost("{id}/unfavourite")]
[Authorize("write:favourites")] [Authorize("write:favourites")]
[Produces("application/json")] [Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Status))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(StatusEntity))]
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))]
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))]
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))]
@ -119,7 +119,7 @@ public class StatusController(
[HttpPost] [HttpPost]
[Authorize("write:statuses")] [Authorize("write:statuses")]
[Produces("application/json")] [Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Status))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(StatusEntity))]
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(MastodonErrorResponse))] [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(MastodonErrorResponse))]
public async Task<IActionResult> PostNote([FromHybrid] StatusSchemas.PostStatusRequest request) { public async Task<IActionResult> PostNote([FromHybrid] StatusSchemas.PostStatusRequest request) {
var user = HttpContext.GetUserOrFail(); var user = HttpContext.GetUserOrFail();
@ -151,7 +151,7 @@ public class StatusController(
if (request.Poll != null) if (request.Poll != null)
throw GracefulException.BadRequest("Polls haven't been implemented yet"); throw GracefulException.BadRequest("Polls haven't been implemented yet");
var visibility = Status.DecodeVisibility(request.Visibility); var visibility = StatusEntity.DecodeVisibility(request.Visibility);
var reply = request.ReplyId != null var reply = request.ReplyId != null
? await db.Notes.Where(p => p.Id == request.ReplyId).EnsureVisibleFor(user).FirstOrDefaultAsync() ?? ? await db.Notes.Where(p => p.Id == request.ReplyId).EnsureVisibleFor(user).FirstOrDefaultAsync() ??
throw GracefulException.BadRequest("Reply target is nonexistent or inaccessible") throw GracefulException.BadRequest("Reply target is nonexistent or inaccessible")

View file

@ -27,7 +27,7 @@ public class TimelineController(DatabaseContext db, NoteRenderer noteRenderer, I
[Authorize("read:statuses")] [Authorize("read:statuses")]
[HttpGet("home")] [HttpGet("home")]
[Produces("application/json")] [Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<Status>))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<StatusEntity>))]
public async Task<IActionResult> GetHomeTimeline(PaginationQuery query) { public async Task<IActionResult> GetHomeTimeline(PaginationQuery query) {
var user = HttpContext.GetUserOrFail(); var user = HttpContext.GetUserOrFail();
var heuristic = await QueryableExtensions.GetHeuristic(user, db, cache); var heuristic = await QueryableExtensions.GetHeuristic(user, db, cache);
@ -49,7 +49,7 @@ public class TimelineController(DatabaseContext db, NoteRenderer noteRenderer, I
[Authorize("read:statuses")] [Authorize("read:statuses")]
[HttpGet("public")] [HttpGet("public")]
[Produces("application/json")] [Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<Status>))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<StatusEntity>))]
public async Task<IActionResult> GetPublicTimeline(PaginationQuery query) { public async Task<IActionResult> GetPublicTimeline(PaginationQuery query) {
var user = HttpContext.GetUserOrFail(); var user = HttpContext.GetUserOrFail();

View file

@ -9,7 +9,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Notification = Iceshrimp.Backend.Core.Database.Tables.Notification;
#nullable disable #nullable disable

View file

@ -9,7 +9,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Notification = Iceshrimp.Backend.Core.Database.Tables.Notification;
#nullable disable #nullable disable

View file

@ -9,7 +9,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Notification = Iceshrimp.Backend.Core.Database.Tables.Notification;
#nullable disable #nullable disable

View file

@ -9,7 +9,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Notification = Iceshrimp.Backend.Core.Database.Tables.Notification;
#nullable disable #nullable disable

View file

@ -8,7 +8,6 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Notification = Iceshrimp.Backend.Core.Database.Tables.Notification;
#nullable disable #nullable disable

View file

@ -10,8 +10,6 @@ using Iceshrimp.Backend.Core.Middleware;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Distributed;
using MastoNotification = Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities.Notification;
using Notification = Iceshrimp.Backend.Core.Database.Tables.Notification;
namespace Iceshrimp.Backend.Core.Extensions; namespace Iceshrimp.Backend.Core.Extensions;
@ -218,7 +216,7 @@ public static class QueryableExtensions {
return list.Select(EnforceRenoteReplyVisibility); return list.Select(EnforceRenoteReplyVisibility);
} }
public static async Task<List<Status>> RenderAllForMastodonAsync( public static async Task<List<StatusEntity>> RenderAllForMastodonAsync(
this IQueryable<Note> notes, NoteRenderer renderer, User? user this IQueryable<Note> notes, NoteRenderer renderer, User? user
) { ) {
var list = (await notes.ToListAsync()) var list = (await notes.ToListAsync())
@ -226,13 +224,13 @@ public static class QueryableExtensions {
return (await renderer.RenderManyAsync(list, user)).ToList(); return (await renderer.RenderManyAsync(list, user)).ToList();
} }
public static async Task<List<Account>> RenderAllForMastodonAsync( public static async Task<List<AccountEntity>> RenderAllForMastodonAsync(
this IQueryable<User> users, UserRenderer renderer) { this IQueryable<User> users, UserRenderer renderer) {
var list = await users.ToListAsync(); var list = await users.ToListAsync();
return (await renderer.RenderManyAsync(list)).ToList(); return (await renderer.RenderManyAsync(list)).ToList();
} }
public static async Task<List<MastoNotification>> RenderAllForMastodonAsync( public static async Task<List<NotificationEntity>> RenderAllForMastodonAsync(
this IQueryable<Notification> notifications, NotificationRenderer renderer, User? user) { this IQueryable<Notification> notifications, NotificationRenderer renderer, User? user) {
var list = await notifications.ToListAsync(); var list = await notifications.ToListAsync();
return (await renderer.RenderManyAsync(list, user)).ToList(); return (await renderer.RenderManyAsync(list, user)).ToList();