diff --git a/Iceshrimp.Backend/Controllers/Federation/NodeInfoController.cs b/Iceshrimp.Backend/Controllers/Federation/NodeInfoController.cs index 5f12e035..edbbc110 100644 --- a/Iceshrimp.Backend/Controllers/Federation/NodeInfoController.cs +++ b/Iceshrimp.Backend/Controllers/Federation/NodeInfoController.cs @@ -55,7 +55,9 @@ public class NodeInfoController(IOptions config, Databas //FIXME Implement members Users = new NodeInfoResponse.NodeInfoUsers { - Total = totalUsers, ActiveMonth = activeMonth, ActiveHalfYear = activeHalfYear + Total = totalUsers, + ActiveMonth = activeMonth, + ActiveHalfYear = activeHalfYear }, LocalComments = 0, LocalPosts = localPosts diff --git a/Iceshrimp.Backend/Controllers/Federation/Schemas/HostMetaXmlResponse.cs b/Iceshrimp.Backend/Controllers/Federation/Schemas/HostMetaXmlResponse.cs index be44ca49..652e4b29 100644 --- a/Iceshrimp.Backend/Controllers/Federation/Schemas/HostMetaXmlResponse.cs +++ b/Iceshrimp.Backend/Controllers/Federation/Schemas/HostMetaXmlResponse.cs @@ -6,19 +6,19 @@ namespace Iceshrimp.Backend.Controllers.Federation.Schemas; [XmlRoot("XRD", Namespace = "http://docs.oasis-open.org/ns/xri/xrd-1.0", IsNullable = false)] public class HostMetaXmlResponse() { + [XmlElement("Link")] public required HostMetaXmlResponseLink Link; + [SetsRequiredMembers] public HostMetaXmlResponse(string webDomain) : this() => Link = new HostMetaXmlResponseLink(webDomain); - - [XmlElement("Link")] public required HostMetaXmlResponseLink Link; } public class HostMetaXmlResponseLink() { + [XmlAttribute("rel")] public string Rel = "lrdd"; + [XmlAttribute("template")] public required string Template; + [XmlAttribute("type")] public string Type = "application/xrd+xml"; + [SetsRequiredMembers] public HostMetaXmlResponseLink(string webDomain) : this() => Template = $"https://{webDomain}/.well-known/webfinger?resource={{uri}}"; - - [XmlAttribute("rel")] public string Rel = "lrdd"; - [XmlAttribute("type")] public string Type = "application/xrd+xml"; - [XmlAttribute("template")] public required string Template; } \ No newline at end of file diff --git a/Iceshrimp.Backend/Controllers/Federation/WellKnownController.cs b/Iceshrimp.Backend/Controllers/Federation/WellKnownController.cs index 1b215247..181672b5 100644 --- a/Iceshrimp.Backend/Controllers/Federation/WellKnownController.cs +++ b/Iceshrimp.Backend/Controllers/Federation/WellKnownController.cs @@ -59,7 +59,9 @@ public class WellKnownController(IOptions config, Databa [ new WebFingerLink { - Rel = "self", Type = "application/activity+json", Href = user.GetPublicUri(config.Value) + Rel = "self", + Type = "application/activity+json", + Href = user.GetPublicUri(config.Value) }, new WebFingerLink { diff --git a/Iceshrimp.Backend/Controllers/Mastodon/AccountController.cs b/Iceshrimp.Backend/Controllers/Mastodon/AccountController.cs index d0e941c0..24e942a4 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/AccountController.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/AccountController.cs @@ -76,7 +76,12 @@ public class AccountController( if (request.Fields?.Where(p => p is { Name: not null, Value: not null }).ToList() is { Count: > 0 } fields) { user.UserProfile.Fields = - fields.Select(p => new UserProfile.Field { Name = p.Name!, Value = p.Value!, IsVerified = false }) + fields.Select(p => new UserProfile.Field + { + Name = p.Name!, + Value = p.Value!, + IsVerified = false + }) .ToArray(); } @@ -87,7 +92,9 @@ public class AccountController( { var rq = new DriveFileCreationRequest { - Filename = request.Avatar.FileName, IsSensitive = false, MimeType = request.Avatar.ContentType + Filename = request.Avatar.FileName, + IsSensitive = false, + MimeType = request.Avatar.ContentType }; var avatar = await driveSvc.StoreFile(request.Avatar.OpenReadStream(), user, rq); user.Avatar = avatar; @@ -99,7 +106,9 @@ public class AccountController( { var rq = new DriveFileCreationRequest { - Filename = request.Banner.FileName, IsSensitive = false, MimeType = request.Banner.ContentType + Filename = request.Banner.FileName, + IsSensitive = false, + MimeType = request.Banner.ContentType }; var banner = await driveSvc.StoreFile(request.Banner.OpenReadStream(), user, rq); user.Banner = banner; @@ -248,7 +257,7 @@ public class AccountController( return Ok(res); } - + [HttpPost("{id}/unmute")] [Authorize("write:mutes")] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(RelationshipEntity))] @@ -271,7 +280,7 @@ public class AccountController( return Ok(res); } - + [HttpPost("{id}/block")] [Authorize("write:blocks")] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(RelationshipEntity))] @@ -282,11 +291,11 @@ public class AccountController( throw GracefulException.BadRequest("You cannot block yourself"); var blockee = await db.Users - .Where(p => p.Id == id) - .IncludeCommonProperties() - .PrecomputeRelationshipData(user) - .FirstOrDefaultAsync() ?? - throw GracefulException.RecordNotFound(); + .Where(p => p.Id == id) + .IncludeCommonProperties() + .PrecomputeRelationshipData(user) + .FirstOrDefaultAsync() ?? + throw GracefulException.RecordNotFound(); await userSvc.BlockUserAsync(user, blockee); @@ -294,7 +303,7 @@ public class AccountController( return Ok(res); } - + [HttpPost("{id}/unblock")] [Authorize("write:blocks")] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(RelationshipEntity))] @@ -305,11 +314,11 @@ public class AccountController( throw GracefulException.BadRequest("You cannot unblock yourself"); var blockee = await db.Users - .Where(p => p.Id == id) - .IncludeCommonProperties() - .PrecomputeRelationshipData(user) - .FirstOrDefaultAsync() ?? - throw GracefulException.RecordNotFound(); + .Where(p => p.Id == id) + .IncludeCommonProperties() + .PrecomputeRelationshipData(user) + .FirstOrDefaultAsync() ?? + throw GracefulException.RecordNotFound(); await userSvc.UnblockUserAsync(user, blockee); diff --git a/Iceshrimp.Backend/Controllers/Mastodon/ConversationsController.cs b/Iceshrimp.Backend/Controllers/Mastodon/ConversationsController.cs index e41ce73a..0865b083 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/ConversationsController.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/ConversationsController.cs @@ -145,9 +145,9 @@ public class ConversationsController( private class Conversation { - public required string Id { get; init; } public required Note LastNote; - public required List Users; public required bool Unread; + public required List Users; + public required string Id { get; init; } } } \ No newline at end of file diff --git a/Iceshrimp.Backend/Controllers/Mastodon/InstanceController.cs b/Iceshrimp.Backend/Controllers/Mastodon/InstanceController.cs index 428b6570..bb916247 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/InstanceController.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/InstanceController.cs @@ -71,7 +71,7 @@ public class InstanceController(DatabaseContext db) : ControllerBase return Ok(res); } - + [HttpGet("/api/v1/instance/translation_languages")] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Dictionary>))] public IActionResult GetTranslationLanguages() diff --git a/Iceshrimp.Backend/Controllers/Mastodon/ListController.cs b/Iceshrimp.Backend/Controllers/Mastodon/ListController.cs index 487698cd..d320f5b9 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/ListController.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/ListController.cs @@ -34,7 +34,12 @@ public class ListController(DatabaseContext db, UserRenderer userRenderer) : Con var res = await db.UserLists .Where(p => p.User == user) - .Select(p => new ListEntity { Id = p.Id, Title = p.Name, Exclusive = p.HideFromHomeTl }) + .Select(p => new ListEntity + { + Id = p.Id, + Title = p.Name, + Exclusive = p.HideFromHomeTl + }) .ToListAsync(); return Ok(res); @@ -50,7 +55,12 @@ public class ListController(DatabaseContext db, UserRenderer userRenderer) : Con var res = await db.UserLists .Where(p => p.User == user && p.Id == id) - .Select(p => new ListEntity { Id = p.Id, Title = p.Name, Exclusive = p.HideFromHomeTl }) + .Select(p => new ListEntity + { + Id = p.Id, + Title = p.Name, + Exclusive = p.HideFromHomeTl + }) .FirstOrDefaultAsync() ?? throw GracefulException.RecordNotFound(); @@ -79,7 +89,12 @@ public class ListController(DatabaseContext db, UserRenderer userRenderer) : Con await db.AddAsync(list); await db.SaveChangesAsync(); - var res = new ListEntity { Id = list.Id, Title = list.Name, Exclusive = list.HideFromHomeTl }; + var res = new ListEntity + { + Id = list.Id, + Title = list.Name, + Exclusive = list.HideFromHomeTl + }; return Ok(res); } @@ -105,7 +120,12 @@ public class ListController(DatabaseContext db, UserRenderer userRenderer) : Con db.Update(list); await db.SaveChangesAsync(); - var res = new ListEntity { Id = list.Id, Title = list.Name, Exclusive = list.HideFromHomeTl }; + var res = new ListEntity + { + Id = list.Id, + Title = list.Name, + Exclusive = list.HideFromHomeTl + }; return Ok(res); } diff --git a/Iceshrimp.Backend/Controllers/Mastodon/PushController.cs b/Iceshrimp.Backend/Controllers/Mastodon/PushController.cs index 9f1e1dc7..fc5dc6c1 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/PushController.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/PushController.cs @@ -165,7 +165,7 @@ public class PushController(DatabaseContext db, MetaService meta) : ControllerBa Status = sub.Types.Contains("status"), Update = sub.Types.Contains("update"), FollowRequest = sub.Types.Contains("follow_request") - }, + } }; } } \ No newline at end of file diff --git a/Iceshrimp.Backend/Controllers/Mastodon/Renderers/NoteRenderer.cs b/Iceshrimp.Backend/Controllers/Mastodon/Renderers/NoteRenderer.cs index 478d63e9..294b4533 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/Renderers/NoteRenderer.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/Renderers/NoteRenderer.cs @@ -273,15 +273,15 @@ public class NoteRenderer( public class NoteRendererDto { public List? Accounts; - public List? Mentions; public List? Attachments; - public List? Polls; - public List? LikedNotes; public List? BookmarkedNotes; - public List? PinnedNotes; - public List? Renotes; public List? Emoji; + public List? LikedNotes; + public List? Mentions; + public List? PinnedNotes; + public List? Polls; public List? Reactions; + public List? Renotes; public bool Source; } diff --git a/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/AnnouncementEntity.cs b/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/AnnouncementEntity.cs index 6dabd7a6..356882cc 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/AnnouncementEntity.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/AnnouncementEntity.cs @@ -4,6 +4,10 @@ namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities; public class AnnouncementEntity { + [J("reactions")] public List Reactions = []; //FIXME + + [J("statuses")] public List Statuses = []; //FIXME + [J("tags")] public List Tags = []; //FIXME [J("id")] public required string Id { get; set; } [J("content")] public required string Content { get; set; } [J("published_at")] public required string PublishedAt { get; set; } @@ -12,10 +16,6 @@ public class AnnouncementEntity [J("mentions")] public required List Mentions { get; set; } [J("emojis")] public required List Emoji { get; set; } - [J("statuses")] public List Statuses = []; //FIXME - [J("reactions")] public List Reactions = []; //FIXME - [J("tags")] public List Tags = []; //FIXME - [J("published")] public bool Published => true; [J("all_day")] public bool AllDay => false; } \ No newline at end of file diff --git a/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/ConversationEntity.cs b/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/ConversationEntity.cs index 235c8b7e..45ef8c07 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/ConversationEntity.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/ConversationEntity.cs @@ -5,8 +5,8 @@ namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities; public class ConversationEntity : IEntity { - [J("id")] public required string Id { get; set; } [J("unread")] public required bool Unread { get; set; } [J("accounts")] public required List Accounts { get; set; } [J("last_status")] public required StatusEntity LastStatus { get; set; } + [J("id")] public required string Id { get; set; } } \ No newline at end of file diff --git a/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/PollEntity.cs b/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/PollEntity.cs index 91d73f0e..2fda0b6a 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/PollEntity.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/PollEntity.cs @@ -5,7 +5,6 @@ namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities; public class PollEntity : IEntity { - [J("id")] public required string Id { get; set; } [J("expires_at")] public required string? ExpiresAt { get; set; } [J("expired")] public required bool Expired { get; set; } [J("multiple")] public required bool Multiple { get; set; } @@ -16,6 +15,7 @@ public class PollEntity : IEntity [J("options")] public required List Options { get; set; } [J("emojis")] public List Emoji => []; //TODO + [J("id")] public required string Id { get; set; } } public class PollOptionEntity diff --git a/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/StatusEntity.cs b/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/StatusEntity.cs index e77f7ba0..dba267f2 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/StatusEntity.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/StatusEntity.cs @@ -9,7 +9,6 @@ namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities; public class StatusEntity : IEntity { - [J("id")] public required string Id { get; set; } [J("content")] public required string? Content { get; set; } [J("uri")] public required string Uri { get; set; } [J("url")] public required string Url { get; set; } @@ -52,7 +51,8 @@ public class StatusEntity : IEntity [J("card")] public object? Card => null; //FIXME [J("application")] public object? Application => null; //FIXME - [J("language")] public string? Language => null; //FIXME + [J("language")] public string? Language => null; //FIXME + [J("id")] public required string Id { get; set; } public static string EncodeVisibility(Note.NoteVisibility visibility) { diff --git a/Iceshrimp.Backend/Controllers/Mastodon/Schemas/StatusSchemas.cs b/Iceshrimp.Backend/Controllers/Mastodon/Schemas/StatusSchemas.cs index 33f31659..18850913 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/Schemas/StatusSchemas.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/Schemas/StatusSchemas.cs @@ -82,7 +82,7 @@ public abstract class StatusSchemas [B(Name = "media_ids")] [J("media_ids")] public List? MediaIds { get; set; } - + [B(Name = "media_attributes")] [J("media_attributes")] public List? MediaAttributes { get; set; } diff --git a/Iceshrimp.Backend/Controllers/Mastodon/SearchController.cs b/Iceshrimp.Backend/Controllers/Mastodon/SearchController.cs index 8563ff9e..385fdf5b 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/SearchController.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/SearchController.cs @@ -209,7 +209,7 @@ public class SearchController( { Name = p.Name, Url = $"https://{config.Value.WebDomain}/tags/{p.Name}", - Following = false, //TODO + Following = false //TODO }) .ToListAsync(); } diff --git a/Iceshrimp.Backend/Controllers/Mastodon/StatusController.cs b/Iceshrimp.Backend/Controllers/Mastodon/StatusController.cs index 69ca5286..9ad86dd2 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/StatusController.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/StatusController.cs @@ -324,7 +324,7 @@ public class StatusController( { Choices = request.Poll.Options, Multiple = request.Poll.Multiple, - ExpiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(request.Poll.ExpiresIn), + ExpiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(request.Poll.ExpiresIn) } : null; @@ -465,7 +465,12 @@ public class StatusController( { var user = HttpContext.GetUserOrFail(); var res = await db.Notes.Where(p => p.Id == id && p.User == user) - .Select(p => new StatusSource { Id = p.Id, ContentWarning = p.Cw ?? "", Text = p.Text ?? "" }) + .Select(p => new StatusSource + { + Id = p.Id, + ContentWarning = p.Cw ?? "", + Text = p.Text ?? "" + }) .FirstOrDefaultAsync() ?? throw GracefulException.RecordNotFound(); diff --git a/Iceshrimp.Backend/Controllers/Mastodon/Streaming/Channels/PublicChannel.cs b/Iceshrimp.Backend/Controllers/Mastodon/Streaming/Channels/PublicChannel.cs index 187c113a..05ad8b22 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/Streaming/Channels/PublicChannel.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/Streaming/Channels/PublicChannel.cs @@ -12,12 +12,12 @@ public class PublicChannel( bool onlyMedia ) : IChannel { + public readonly ILogger Logger = + connection.ScopeFactory.CreateScope().ServiceProvider.GetRequiredService>(); + public string Name => name; public List Scopes => ["read:statuses"]; public bool IsSubscribed { get; private set; } - - public readonly ILogger Logger = - connection.ScopeFactory.CreateScope().ServiceProvider.GetRequiredService>(); public Task Subscribe(StreamingRequestMessage _) { @@ -65,7 +65,9 @@ public class PublicChannel( var rendered = await renderer.RenderAsync(note, connection.Token.User); var message = new StreamingUpdateMessage { - Stream = [Name], Event = "update", Payload = JsonSerializer.Serialize(rendered) + Stream = [Name], + Event = "update", + Payload = JsonSerializer.Serialize(rendered) }; await connection.SendMessageAsync(JsonSerializer.Serialize(message)); } @@ -85,7 +87,9 @@ public class PublicChannel( var rendered = await renderer.RenderAsync(note, connection.Token.User); var message = new StreamingUpdateMessage { - Stream = [Name], Event = "status.update", Payload = JsonSerializer.Serialize(rendered) + Stream = [Name], + Event = "status.update", + Payload = JsonSerializer.Serialize(rendered) }; await connection.SendMessageAsync(JsonSerializer.Serialize(message)); } @@ -100,7 +104,12 @@ public class PublicChannel( try { if (!IsApplicable(note)) return; - var message = new StreamingUpdateMessage { Stream = [Name], Event = "delete", Payload = note.Id }; + var message = new StreamingUpdateMessage + { + Stream = [Name], + Event = "delete", + Payload = note.Id + }; await connection.SendMessageAsync(JsonSerializer.Serialize(message)); } catch (Exception e) diff --git a/Iceshrimp.Backend/Controllers/Mastodon/Streaming/Channels/UserChannel.cs b/Iceshrimp.Backend/Controllers/Mastodon/Streaming/Channels/UserChannel.cs index beabe48c..1173dd82 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/Streaming/Channels/UserChannel.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/Streaming/Channels/UserChannel.cs @@ -10,14 +10,14 @@ namespace Iceshrimp.Backend.Controllers.Mastodon.Streaming.Channels; public class UserChannel(WebSocketConnection connection, bool notificationsOnly) : IChannel { + public readonly ILogger Logger = + connection.ScopeFactory.CreateScope().ServiceProvider.GetRequiredService>(); + private List _followedUsers = []; public string Name => notificationsOnly ? "user:notification" : "user"; public List Scopes => ["read:statuses", "read:notifications"]; public bool IsSubscribed { get; private set; } - public readonly ILogger Logger = - connection.ScopeFactory.CreateScope().ServiceProvider.GetRequiredService>(); - public async Task Subscribe(StreamingRequestMessage _) { if (IsSubscribed) return; @@ -74,7 +74,9 @@ public class UserChannel(WebSocketConnection connection, bool notificationsOnly) var rendered = await renderer.RenderAsync(note, connection.Token.User); var message = new StreamingUpdateMessage { - Stream = [Name], Event = "update", Payload = JsonSerializer.Serialize(rendered) + Stream = [Name], + Event = "update", + Payload = JsonSerializer.Serialize(rendered) }; await connection.SendMessageAsync(JsonSerializer.Serialize(message)); } @@ -94,7 +96,9 @@ public class UserChannel(WebSocketConnection connection, bool notificationsOnly) var rendered = await renderer.RenderAsync(note, connection.Token.User); var message = new StreamingUpdateMessage { - Stream = [Name], Event = "status.update", Payload = JsonSerializer.Serialize(rendered) + Stream = [Name], + Event = "status.update", + Payload = JsonSerializer.Serialize(rendered) }; await connection.SendMessageAsync(JsonSerializer.Serialize(message)); } @@ -109,7 +113,12 @@ public class UserChannel(WebSocketConnection connection, bool notificationsOnly) try { if (!IsApplicable(note)) return; - var message = new StreamingUpdateMessage { Stream = [Name], Event = "delete", Payload = note.Id }; + var message = new StreamingUpdateMessage + { + Stream = [Name], + Event = "delete", + Payload = note.Id + }; await connection.SendMessageAsync(JsonSerializer.Serialize(message)); } catch (Exception e) @@ -139,7 +148,9 @@ public class UserChannel(WebSocketConnection connection, bool notificationsOnly) var message = new StreamingUpdateMessage { - Stream = [Name], Event = "notification", Payload = JsonSerializer.Serialize(rendered) + Stream = [Name], + Event = "notification", + Payload = JsonSerializer.Serialize(rendered) }; await connection.SendMessageAsync(JsonSerializer.Serialize(message)); } diff --git a/Iceshrimp.Backend/Controllers/NotificationController.cs b/Iceshrimp.Backend/Controllers/NotificationController.cs index 0902424d..3a8464b4 100644 --- a/Iceshrimp.Backend/Controllers/NotificationController.cs +++ b/Iceshrimp.Backend/Controllers/NotificationController.cs @@ -3,10 +3,8 @@ 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 Iceshrimp.Backend.Core.Services; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.RateLimiting; using Microsoft.EntityFrameworkCore; @@ -14,7 +12,8 @@ using Microsoft.EntityFrameworkCore; namespace Iceshrimp.Backend.Controllers; [ApiController] -[Authenticate, Authorize] +[Authenticate] +[Authorize] [EnableRateLimiting("sliding")] [Route("/api/iceshrimp/v1/notification")] [Produces(MediaTypeNames.Application.Json)] @@ -67,7 +66,7 @@ public class NotificationController(DatabaseContext db, NotificationRenderer not return Ok(new object()); } - + [HttpDelete("{id}")] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(object))] [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ErrorResponse))] diff --git a/Iceshrimp.Backend/Controllers/Renderers/NoteRenderer.cs b/Iceshrimp.Backend/Controllers/Renderers/NoteRenderer.cs index 97b1f3c9..ca0abbbd 100644 --- a/Iceshrimp.Backend/Controllers/Renderers/NoteRenderer.cs +++ b/Iceshrimp.Backend/Controllers/Renderers/NoteRenderer.cs @@ -73,7 +73,7 @@ public class NoteRenderer(UserRenderer userRenderer, DatabaseContext db, EmojiSe i.Reaction == p.First().Reaction && i.User == user), Name = p.First().Reaction, - Url = null, + Url = null }) .ToListAsync(); @@ -102,8 +102,8 @@ public class NoteRenderer(UserRenderer userRenderer, DatabaseContext db, EmojiSe public class NoteRendererDto { - public List? Users; public List? Attachments; public List? Reactions; + public List? Users; } } \ No newline at end of file diff --git a/Iceshrimp.Backend/Controllers/Renderers/NotificationRenderer.cs b/Iceshrimp.Backend/Controllers/Renderers/NotificationRenderer.cs index 26268b3e..3a0d798f 100644 --- a/Iceshrimp.Backend/Controllers/Renderers/NotificationRenderer.cs +++ b/Iceshrimp.Backend/Controllers/Renderers/NotificationRenderer.cs @@ -1,9 +1,6 @@ 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.Services; -using Microsoft.EntityFrameworkCore; namespace Iceshrimp.Backend.Controllers.Renderers; @@ -81,7 +78,7 @@ public class NotificationRenderer( public class NotificationRendererDto { - public List? Users; public List? Notes; + public List? Users; } } \ No newline at end of file diff --git a/Iceshrimp.Backend/Controllers/Renderers/UserProfileRenderer.cs b/Iceshrimp.Backend/Controllers/Renderers/UserProfileRenderer.cs index ccba41dd..7d0d8e53 100644 --- a/Iceshrimp.Backend/Controllers/Renderers/UserProfileRenderer.cs +++ b/Iceshrimp.Backend/Controllers/Renderers/UserProfileRenderer.cs @@ -36,7 +36,7 @@ public class UserProfileRenderer(DatabaseContext db) Fields = user.UserProfile?.Fields, Location = user.UserProfile?.Location, Followers = followers, - Following = following, + Following = following }; } diff --git a/Iceshrimp.Backend/Controllers/Schemas/NotificationResponse.cs b/Iceshrimp.Backend/Controllers/Schemas/NotificationResponse.cs index f3380f25..c60f06cf 100644 --- a/Iceshrimp.Backend/Controllers/Schemas/NotificationResponse.cs +++ b/Iceshrimp.Backend/Controllers/Schemas/NotificationResponse.cs @@ -1,5 +1,4 @@ using J = System.Text.Json.Serialization.JsonPropertyNameAttribute; -using JI = System.Text.Json.Serialization.JsonIgnoreAttribute; namespace Iceshrimp.Backend.Controllers.Schemas; diff --git a/Iceshrimp.Backend/Controllers/UserController.cs b/Iceshrimp.Backend/Controllers/UserController.cs index 641ad8dc..aa576357 100644 --- a/Iceshrimp.Backend/Controllers/UserController.cs +++ b/Iceshrimp.Backend/Controllers/UserController.cs @@ -34,7 +34,7 @@ public class UserController( return Ok(await userRenderer.RenderOne(await userResolver.GetUpdatedUser(user))); } - + [HttpGet("profile")] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(UserProfileResponse))] [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ErrorResponse))] diff --git a/Iceshrimp.Backend/Core/Database/DatabaseContext.cs b/Iceshrimp.Backend/Core/Database/DatabaseContext.cs index 77f15af8..2b3fc322 100644 --- a/Iceshrimp.Backend/Core/Database/DatabaseContext.cs +++ b/Iceshrimp.Backend/Core/Database/DatabaseContext.cs @@ -84,8 +84,8 @@ public class DatabaseContext(DbContextOptions options) public virtual DbSet Webhooks { get; init; } = null!; public virtual DbSet AllowedInstances { get; init; } = null!; public virtual DbSet BlockedInstances { get; init; } = null!; - public virtual DbSet DataProtectionKeys { get; init; } = null!; public virtual DbSet MetaStore { get; init; } = null!; + public virtual DbSet DataProtectionKeys { get; init; } = null!; public static NpgsqlDataSource GetDataSource(Config.DatabaseSection? config) { diff --git a/Iceshrimp.Backend/Core/Database/Tables/Announcement.cs b/Iceshrimp.Backend/Core/Database/Tables/Announcement.cs index c89c6049..56f50239 100644 --- a/Iceshrimp.Backend/Core/Database/Tables/Announcement.cs +++ b/Iceshrimp.Backend/Core/Database/Tables/Announcement.cs @@ -42,7 +42,7 @@ public class Announcement public virtual ICollection AnnouncementReads { get; set; } = new List(); [NotMapped] [Projectable] public virtual IEnumerable ReadBy => AnnouncementReads.Select(p => p.User); - + [Projectable] public bool IsReadBy(User user) => ReadBy.Contains(user); } \ No newline at end of file diff --git a/Iceshrimp.Backend/Core/Database/Tables/DriveFile.cs b/Iceshrimp.Backend/Core/Database/Tables/DriveFile.cs index 76837def..54067548 100644 --- a/Iceshrimp.Backend/Core/Database/Tables/DriveFile.cs +++ b/Iceshrimp.Backend/Core/Database/Tables/DriveFile.cs @@ -184,14 +184,14 @@ public class DriveFile : IEntity [InverseProperty(nameof(Tables.User.Banner))] public virtual User? UserBanner { get; set; } + [NotMapped] public string PublicUrl => WebpublicUrl ?? Url; + [NotMapped] public string PublicThumbnailUrl => ThumbnailUrl ?? WebpublicUrl ?? Url; + [Key] [Column("id")] [StringLength(32)] public string Id { get; set; } = null!; - [NotMapped] public string PublicUrl => WebpublicUrl ?? Url; - [NotMapped] public string PublicThumbnailUrl => ThumbnailUrl ?? WebpublicUrl ?? Url; - public class FileProperties { [J("width")] public int? Width { get; set; } diff --git a/Iceshrimp.Backend/Core/Database/Tables/Hashtag.cs b/Iceshrimp.Backend/Core/Database/Tables/Hashtag.cs index e882e621..409de988 100644 --- a/Iceshrimp.Backend/Core/Database/Tables/Hashtag.cs +++ b/Iceshrimp.Backend/Core/Database/Tables/Hashtag.cs @@ -8,10 +8,10 @@ namespace Iceshrimp.Backend.Core.Database.Tables; [Index("Name", IsUnique = true)] public class Hashtag : IEntity { + [Column("name")] [StringLength(128)] public string Name { get; set; } = null!; + [Key] [Column("id")] [StringLength(32)] public string Id { get; set; } = null!; - - [Column("name")] [StringLength(128)] public string Name { get; set; } = null!; } \ No newline at end of file diff --git a/Iceshrimp.Backend/Core/Database/Tables/Marker.cs b/Iceshrimp.Backend/Core/Database/Tables/Marker.cs index 9818c0aa..aba5d739 100644 --- a/Iceshrimp.Backend/Core/Database/Tables/Marker.cs +++ b/Iceshrimp.Backend/Core/Database/Tables/Marker.cs @@ -11,13 +11,16 @@ namespace Iceshrimp.Backend.Core.Database.Tables; [PrimaryKey("UserId", "Type")] public class Marker { - [Column("userId")] - [StringLength(32)] - public string UserId { get; set; } = null!; + [PgName("marker_type_enum")] + public enum MarkerType + { + [PgName("home")] Home, + [PgName("notifications")] Notifications + } - [Column("type")] - [StringLength(32)] - public MarkerType Type { get; set; } + [Column("userId")] [StringLength(32)] public string UserId { get; set; } = null!; + + [Column("type")] [StringLength(32)] public MarkerType Type { get; set; } [Column("position")] [StringLength(32)] @@ -30,11 +33,4 @@ public class Marker [ForeignKey("UserId")] [InverseProperty(nameof(Tables.User.Markers))] public virtual User User { get; set; } = null!; - - [PgName("marker_type_enum")] - public enum MarkerType - { - [PgName("home")] Home, - [PgName("notifications")] Notifications - } } \ No newline at end of file diff --git a/Iceshrimp.Backend/Core/Database/Tables/Note.cs b/Iceshrimp.Backend/Core/Database/Tables/Note.cs index 26155808..64150894 100644 --- a/Iceshrimp.Backend/Core/Database/Tables/Note.cs +++ b/Iceshrimp.Backend/Core/Database/Tables/Note.cs @@ -241,9 +241,6 @@ public class Note : IEntity public string RawAttachments => InternalRawAttachments(Id); - public static string InternalRawAttachments(string id) - => throw new NotSupportedException(); - [NotMapped] [Projectable] public bool IsPureRenote => (RenoteId != null || Renote != null) && !IsQuote; [NotMapped] @@ -265,6 +262,9 @@ public class Note : IEntity [StringLength(32)] public string Id { get; set; } = null!; + public static string InternalRawAttachments(string id) + => throw new NotSupportedException(); + [Projectable] public bool TextContainsCaseInsensitive(string str) => Text != null && EF.Functions.ILike(Text, "%" + EfHelpers.EscapeLikeQuery(str) + "%", @"\"); diff --git a/Iceshrimp.Backend/Core/Database/Tables/Notification.cs b/Iceshrimp.Backend/Core/Database/Tables/Notification.cs index 72fdd411..db0dea5d 100644 --- a/Iceshrimp.Backend/Core/Database/Tables/Notification.cs +++ b/Iceshrimp.Backend/Core/Database/Tables/Notification.cs @@ -117,14 +117,14 @@ public class Notification : IEntity [InverseProperty(nameof(Tables.UserGroupInvitation.Notifications))] public virtual UserGroupInvitation? UserGroupInvitation { get; set; } + [Column("masto_id")] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public long MastoId { get; set; } + [Key] [Column("id")] [StringLength(32)] public string Id { get; set; } = null!; - - [Column("masto_id")] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public long MastoId { get; set; } public Notification WithPrecomputedNoteVisibilities(bool reply, bool renote) { diff --git a/Iceshrimp.Backend/Core/Database/Tables/PushSubscription.cs b/Iceshrimp.Backend/Core/Database/Tables/PushSubscription.cs index b9f1357f..773f6f6f 100644 --- a/Iceshrimp.Backend/Core/Database/Tables/PushSubscription.cs +++ b/Iceshrimp.Backend/Core/Database/Tables/PushSubscription.cs @@ -16,9 +16,12 @@ public class PushSubscription [PgName("all")] All, [PgName("followed")] Followed, [PgName("follower")] Follower, - [PgName("none")] None, + [PgName("none")] None } + [Column("types", TypeName = "character varying(32)[]")] + public List Types = null!; + [Key] [Column("id")] [StringLength(32)] @@ -42,9 +45,6 @@ public class PushSubscription [StringLength(128)] public string PublicKey { get; set; } = null!; - [Column("types", TypeName = "character varying(32)[]")] - public List Types = null!; - [Column("policy")] public PushPolicy Policy { get; set; } [ForeignKey("UserId")] diff --git a/Iceshrimp.Backend/Core/Database/Tables/User.cs b/Iceshrimp.Backend/Core/Database/Tables/User.cs index 79f385c9..7404c03c 100644 --- a/Iceshrimp.Backend/Core/Database/Tables/User.cs +++ b/Iceshrimp.Backend/Core/Database/Tables/User.cs @@ -494,6 +494,9 @@ public class User : IEntity [NotMapped] public bool? PrecomputedIsRequested { get; set; } [NotMapped] public bool? PrecomputedIsRequestedBy { get; set; } + public bool IsLocalUser => Host == null; + public bool IsRemoteUser => Host != null; + [Key] [Column("id")] [StringLength(32)] @@ -616,7 +619,4 @@ public class User : IEntity : throw new Exception("Cannot access PublicUrl for remote user"); public string GetIdenticonUrl(string webDomain) => $"https://{webDomain}/identicon/{Id}"; - - public bool IsLocalUser => Host == null; - public bool IsRemoteUser => Host != null; } \ No newline at end of file diff --git a/Iceshrimp.Backend/Core/Database/Tables/UserProfile.cs b/Iceshrimp.Backend/Core/Database/Tables/UserProfile.cs index 2b3d6c89..88ff3ee5 100644 --- a/Iceshrimp.Backend/Core/Database/Tables/UserProfile.cs +++ b/Iceshrimp.Backend/Core/Database/Tables/UserProfile.cs @@ -20,6 +20,8 @@ public class UserProfile [PgName("private")] Private } + [Column("mentionsResolved")] public bool MentionsResolved; + [Key] [Column("userId")] [StringLength(32)] @@ -176,9 +178,6 @@ public class UserProfile [InverseProperty(nameof(Tables.User.UserProfile))] public virtual User User { get; set; } = null!; - [Column("mentionsResolved")] - public bool MentionsResolved; - public class Field { [J("name")] public required string Name { get; set; } diff --git a/Iceshrimp.Backend/Core/Extensions/DistributedCacheExtensions.cs b/Iceshrimp.Backend/Core/Extensions/DistributedCacheExtensions.cs index 859059fd..d0626059 100644 --- a/Iceshrimp.Backend/Core/Extensions/DistributedCacheExtensions.cs +++ b/Iceshrimp.Backend/Core/Extensions/DistributedCacheExtensions.cs @@ -124,7 +124,7 @@ public static class DistributedCacheExtensions if (res != null) return; await SetAsync(cache, key, fetcher(), type, ttl, renew); } - + public static async Task CacheAsync( this IDistributedCache cache, string key, TimeSpan ttl, object? value, Type type, bool renew = false ) diff --git a/Iceshrimp.Backend/Core/Extensions/MvcBuilderExtensions.cs b/Iceshrimp.Backend/Core/Extensions/MvcBuilderExtensions.cs index 4234a677..5d3bea3a 100644 --- a/Iceshrimp.Backend/Core/Extensions/MvcBuilderExtensions.cs +++ b/Iceshrimp.Backend/Core/Extensions/MvcBuilderExtensions.cs @@ -28,7 +28,7 @@ public static class MvcBuilderExtensions if (!opts.OutputFormatters.OfType().Any()) opts.OutputFormatters.Add(new SystemTextJsonOutputFormatter(jsonOpts.Value - .JsonSerializerOptions)); + .JsonSerializerOptions)); opts.InputFormatters.Insert(0, new JsonInputMultiFormatter()); opts.OutputFormatters.Insert(0, new JsonOutputMultiFormatter()); @@ -39,20 +39,19 @@ public static class MvcBuilderExtensions public static IMvcBuilder AddModelBindingProviders(this IMvcBuilder builder) { - builder.Services.AddOptions().PostConfigure(options => - { - options.ModelBinderProviders.AddHybridBindingProvider(); - }); + builder.Services.AddOptions() + .PostConfigure(options => { options.ModelBinderProviders.AddHybridBindingProvider(); }); return builder; } - + public static IMvcBuilder AddValueProviderFactories(this IMvcBuilder builder) { - builder.Services.AddOptions().PostConfigure(options => - { - options.ValueProviderFactories.Add(new JQueryQueryStringValueProviderFactory()); - }); + builder.Services.AddOptions() + .PostConfigure(options => + { + options.ValueProviderFactories.Add(new JQueryQueryStringValueProviderFactory()); + }); return builder; } diff --git a/Iceshrimp.Backend/Core/Extensions/QueryableExtensions.cs b/Iceshrimp.Backend/Core/Extensions/QueryableExtensions.cs index c91df610..9bb79266 100644 --- a/Iceshrimp.Backend/Core/Extensions/QueryableExtensions.cs +++ b/Iceshrimp.Backend/Core/Extensions/QueryableExtensions.cs @@ -289,7 +289,9 @@ public static class QueryableExtensions .Where(note => note.Reply == null || !note.Reply.User.IsMuting(user)); } - public static IQueryable FilterBlockedConversations(this IQueryable query, User user, DatabaseContext db) + public static IQueryable FilterBlockedConversations( + this IQueryable query, User user, DatabaseContext db + ) { return query.Where(p => !db.Blockings.Any(i => i.Blocker == user && p.VisibleUserIds.Contains(i.BlockeeId))); } diff --git a/Iceshrimp.Backend/Core/Extensions/WebApplicationExtensions.cs b/Iceshrimp.Backend/Core/Extensions/WebApplicationExtensions.cs index 52c49b49..8db2c32e 100644 --- a/Iceshrimp.Backend/Core/Extensions/WebApplicationExtensions.cs +++ b/Iceshrimp.Backend/Core/Extensions/WebApplicationExtensions.cs @@ -173,7 +173,7 @@ public static class WebApplicationExtensions var keypair = VapidHelper.GenerateVapidKeys(); return [keypair.PublicKey, keypair.PrivateKey]; }); - + app.Logger.LogInformation("Warming up meta cache..."); await meta.WarmupCache(); diff --git a/Iceshrimp.Backend/Core/Federation/ActivityPub/UserRenderer.cs b/Iceshrimp.Backend/Core/Federation/ActivityPub/UserRenderer.cs index d1c143ad..00e155fe 100644 --- a/Iceshrimp.Backend/Core/Federation/ActivityPub/UserRenderer.cs +++ b/Iceshrimp.Backend/Core/Federation/ActivityPub/UserRenderer.cs @@ -79,7 +79,9 @@ public class UserRenderer(IOptions config, DatabaseConte Endpoints = new ASEndpoints { SharedInbox = new ASObjectBase($"https://{config.Value.WebDomain}/inbox") }, PublicKey = new ASPublicKey { - Id = $"{id}#main-key", Owner = new ASObjectBase(id), PublicKey = keypair.PublicKey + Id = $"{id}#main-key", + Owner = new ASObjectBase(id), + PublicKey = keypair.PublicKey }, Tags = tags }; diff --git a/Iceshrimp.Backend/Core/Federation/ActivityStreams/LDHelpers.cs b/Iceshrimp.Backend/Core/Federation/ActivityStreams/LDHelpers.cs index d7528ed6..66392087 100644 --- a/Iceshrimp.Backend/Core/Federation/ActivityStreams/LDHelpers.cs +++ b/Iceshrimp.Backend/Core/Federation/ActivityStreams/LDHelpers.cs @@ -64,8 +64,6 @@ public static class LdHelpers JToken.Parse(File.ReadAllText(Path.Combine("Core", "Federation", "ActivityStreams", "Contexts", "as-extensions.json"))); - private static IEnumerable ASForceArray => ["tag", "to", "cc", "bcc", "bto"]; - private static readonly JsonLdProcessorOptions Options = new() { DocumentLoader = CustomLoader, @@ -75,7 +73,7 @@ public static class LdHelpers ForceArray = ASForceArray.Select(p => $"{Constants.ActivityStreamsNs}#{p}").ToList(), // separated for readability - RemoveUnusedInlineContextProperties = true, + RemoveUnusedInlineContextProperties = true }; public static readonly JsonSerializerSettings JsonSerializerSettings = new() @@ -88,6 +86,8 @@ public static class LdHelpers NullValueHandling = NullValueHandling.Ignore, DateTimeZoneHandling = DateTimeZoneHandling.Local }; + private static IEnumerable ASForceArray => ["tag", "to", "cc", "bcc", "bto"]; + private static RemoteDocument CustomLoader(Uri uri, JsonLdLoaderOptions jsonLdLoaderOptions) { var key = uri.AbsolutePath == "/schemas/litepub-0.1.jsonld" ? "litepub-0.1" : uri.ToString(); diff --git a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASActivity.cs b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASActivity.cs index 9aab4afe..5ce022c8 100644 --- a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASActivity.cs +++ b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASActivity.cs @@ -37,7 +37,7 @@ public class ASActivity : ASObject // Extensions public const string Bite = "https://ns.mia.jetzt/as#Bite"; - public const string EmojiReact = $"http://litepub.social/ns#EmojiReact"; + public const string EmojiReact = "http://litepub.social/ns#EmojiReact"; } } diff --git a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASActor.cs b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASActor.cs index d6766b20..7e8b2e8e 100644 --- a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASActor.cs +++ b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASActor.cs @@ -120,7 +120,7 @@ public class ASActor : ASObject [J($"{Constants.ActivityStreamsNs}#tag")] [JC(typeof(ASTagConverter))] public List? Tags { get; set; } - + [J($"{Constants.ActivityStreamsNs}#attachment")] [JC(typeof(ASAttachmentConverter))] public List? Attachments { get; set; } diff --git a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASAttachment.cs b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASAttachment.cs index d397b792..5c41bdc0 100644 --- a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASAttachment.cs +++ b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASAttachment.cs @@ -36,13 +36,13 @@ public class ASDocument : ASAttachment public class ASField : ASAttachment { - public ASField() => Type = $"{Constants.SchemaNs}#PropertyValue"; - [J($"{Constants.ActivityStreamsNs}#name")] [JC(typeof(ValueObjectConverter))] public string? Name; [J($"{Constants.SchemaNs}#value")] [JC(typeof(ValueObjectConverter))] public string? Value; + + public ASField() => Type = $"{Constants.SchemaNs}#PropertyValue"; } public sealed class ASAttachmentConverter : JsonConverter diff --git a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASCollection.cs b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASCollection.cs index 66d312cd..a81d42e6 100644 --- a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASCollection.cs +++ b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASCollection.cs @@ -10,6 +10,8 @@ namespace Iceshrimp.Backend.Core.Federation.ActivityStreams.Types; public class ASCollection : ASObject { + public const string ObjectType = $"{Constants.ActivityStreamsNs}#Collection"; + [JsonConstructor] public ASCollection(bool withType = true) => Type = withType ? ObjectType : null; @@ -37,8 +39,6 @@ public class ASCollection : ASObject public ASLink? Last { get; set; } public new bool IsUnresolved => !TotalItems.HasValue; - - public const string ObjectType = $"{Constants.ActivityStreamsNs}#Collection"; } public sealed class ASCollectionConverter : JsonConverter diff --git a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASCollectionBase.cs b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASCollectionBase.cs index 225f1729..e521cb57 100644 --- a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASCollectionBase.cs +++ b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASCollectionBase.cs @@ -7,6 +7,8 @@ namespace Iceshrimp.Backend.Core.Federation.ActivityStreams.Types; public class ASCollectionBase : ASObjectBase { + public const string ObjectType = $"{Constants.ActivityStreamsNs}#Collection"; + [J("@type")] [JC(typeof(StringListSingleConverter))] public string Type => ObjectType; @@ -14,8 +16,6 @@ public class ASCollectionBase : ASObjectBase [J($"{Constants.ActivityStreamsNs}#totalItems")] [JC(typeof(VC))] public ulong? TotalItems { get; set; } - - public const string ObjectType = $"{Constants.ActivityStreamsNs}#Collection"; } public sealed class ASCollectionBaseConverter : ASSerializer.ListSingleObjectConverter; \ No newline at end of file diff --git a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASCollectionPage.cs b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASCollectionPage.cs index 40b5520d..d3ec684c 100644 --- a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASCollectionPage.cs +++ b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASCollectionPage.cs @@ -10,6 +10,8 @@ namespace Iceshrimp.Backend.Core.Federation.ActivityStreams.Types; public class ASCollectionPage : ASObject { + public const string ObjectType = $"{Constants.ActivityStreamsNs}#CollectionPage"; + [JsonConstructor] public ASCollectionPage(bool withType = true) => Type = withType ? ObjectType : null; @@ -35,8 +37,6 @@ public class ASCollectionPage : ASObject [J($"{Constants.ActivityStreamsNs}#next")] [JC(typeof(ASLinkConverter))] public ASLink? Next { get; set; } - - public const string ObjectType = $"{Constants.ActivityStreamsNs}#CollectionPage"; } public sealed class ASCollectionPageConverter : JsonConverter diff --git a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASImage.cs b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASImage.cs index e1ff1c1d..8260fc0e 100644 --- a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASImage.cs +++ b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASImage.cs @@ -10,7 +10,7 @@ public class ASImage [J("@type")] [JC(typeof(StringListSingleConverter))] public string Type => $"{Constants.ActivityStreamsNs}#Image"; - + [J($"{Constants.ActivityStreamsNs}#url")] [JC(typeof(ASLinkConverter))] public ASLink? Url { get; set; } @@ -20,4 +20,4 @@ public class ASImage public bool? Sensitive { get; set; } } -public class ASImageConverter : ASSerializer.ListSingleObjectConverter; +public class ASImageConverter : ASSerializer.ListSingleObjectConverter; \ No newline at end of file diff --git a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASNote.cs b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASNote.cs index b9062b55..2cde6c22 100644 --- a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASNote.cs +++ b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASNote.cs @@ -42,7 +42,7 @@ public class ASNote : ASObject [J($"{Constants.ActivityStreamsNs}#summary")] [JC(typeof(VC))] public string? Summary { get; set; } - + [J($"{Constants.ActivityStreamsNs}#name")] [JC(typeof(VC))] public string? Name { get; set; } @@ -94,13 +94,13 @@ public class ASNote : ASObject { if (actor.Host == null) throw new Exception("Can't get recipients for local actor"); return (To ?? []).Concat(Cc ?? []) - .Select(p => p.Id) - .Distinct() - .Where(p => p != $"{Constants.ActivityStreamsNs}#Public" && - p != (actor.FollowersUri ?? actor.Uri + "/followers")) - .Where(p => p != null) - .Select(p => p!) - .ToList(); + .Select(p => p.Id) + .Distinct() + .Where(p => p != $"{Constants.ActivityStreamsNs}#Public" && + p != (actor.FollowersUri ?? actor.Uri + "/followers")) + .Where(p => p != null) + .Select(p => p!) + .ToList(); } public new static class Types diff --git a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASOrderedCollection.cs b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASOrderedCollection.cs index 9669d5b0..853b3d3d 100644 --- a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASOrderedCollection.cs +++ b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASOrderedCollection.cs @@ -9,6 +9,8 @@ namespace Iceshrimp.Backend.Core.Federation.ActivityStreams.Types; public class ASOrderedCollection : ASCollection { + public new const string ObjectType = $"{Constants.ActivityStreamsNs}#OrderedCollection"; + [JsonConstructor] public ASOrderedCollection(bool withType = true) => Type = withType ? ObjectType : null; @@ -22,8 +24,6 @@ public class ASOrderedCollection : ASCollection get => base.Items; set => base.Items = value; } - - public new const string ObjectType = $"{Constants.ActivityStreamsNs}#OrderedCollection"; } internal sealed class ASOrderedCollectionItemsConverter : ASCollectionItemsConverter diff --git a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASOrderedCollectionPage.cs b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASOrderedCollectionPage.cs index a746e517..2b87eb02 100644 --- a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASOrderedCollectionPage.cs +++ b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASOrderedCollectionPage.cs @@ -10,9 +10,11 @@ namespace Iceshrimp.Backend.Core.Federation.ActivityStreams.Types; public class ASOrderedCollectionPage : ASObject { + public const string ObjectType = $"{Constants.ActivityStreamsNs}#OrderedCollectionPage"; + [JsonConstructor] public ASOrderedCollectionPage(bool withType = true) => Type = withType ? ObjectType : null; - + [SetsRequiredMembers] public ASOrderedCollectionPage(string id, bool withType = false) : this(withType) => Id = id; @@ -35,8 +37,6 @@ public class ASOrderedCollectionPage : ASObject [J($"{Constants.ActivityStreamsNs}#next")] [JC(typeof(ASLinkConverter))] public ASLink? Next { get; set; } - - public const string ObjectType = $"{Constants.ActivityStreamsNs}#OrderedCollectionPage"; } public sealed class ASOrderedCollectionPageConverter : JsonConverter diff --git a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASQuestion.cs b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASQuestion.cs index a371c310..e32dbd10 100644 --- a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASQuestion.cs +++ b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASQuestion.cs @@ -7,10 +7,9 @@ namespace Iceshrimp.Backend.Core.Federation.ActivityStreams.Types; public class ASQuestion : ASNote { - public ASQuestion() => Type = Types.Question; - private List? _anyOf; private List? _oneOf; + public ASQuestion() => Type = Types.Question; [J($"{Constants.ActivityStreamsNs}#oneOf")] public List? OneOf diff --git a/Iceshrimp.Backend/Core/Helpers/LibMfm/Parsing/MfmParser.cs b/Iceshrimp.Backend/Core/Helpers/LibMfm/Parsing/MfmParser.cs index 27faaa81..47ad4c7a 100644 --- a/Iceshrimp.Backend/Core/Helpers/LibMfm/Parsing/MfmParser.cs +++ b/Iceshrimp.Backend/Core/Helpers/LibMfm/Parsing/MfmParser.cs @@ -306,7 +306,9 @@ internal class MentionNodeParser : INodeParser var node = new MfmMentionNode { - Username = split[0], Host = split.Length == 2 ? split[1] : null, Acct = $"@{buffer[start..end]}" + Username = split[0], + Host = split.Length == 2 ? split[1] : null, + Acct = $"@{buffer[start..end]}" }; return (node, chars); diff --git a/Iceshrimp.Backend/Core/Middleware/AuthenticationMiddleware.cs b/Iceshrimp.Backend/Core/Middleware/AuthenticationMiddleware.cs index 81121e69..3ac8be26 100644 --- a/Iceshrimp.Backend/Core/Middleware/AuthenticationMiddleware.cs +++ b/Iceshrimp.Backend/Core/Middleware/AuthenticationMiddleware.cs @@ -59,7 +59,7 @@ public class AuthenticationMiddleware(DatabaseContext db, UserService userSvc, M userSvc.UpdateOauthTokenMetadata(oauthToken); ctx.SetOauthToken(oauthToken); - + mfmConverter.SupportsHtmlFormatting = oauthToken.SupportsHtmlFormatting; } else diff --git a/Iceshrimp.Backend/Core/Middleware/InboxValidationMiddleware.cs b/Iceshrimp.Backend/Core/Middleware/InboxValidationMiddleware.cs index eb2320e3..01c2d9f0 100644 --- a/Iceshrimp.Backend/Core/Middleware/InboxValidationMiddleware.cs +++ b/Iceshrimp.Backend/Core/Middleware/InboxValidationMiddleware.cs @@ -90,7 +90,7 @@ public class InboxValidationMiddleware( if (user == null) throw AuthFetchException.NotFound("Delete activity actor is unknown"); key = await db.UserPublickeys.Include(p => p.User) .FirstOrDefaultAsync(p => p.User == user, ct); - + // If the key is still null here, we have a data consistency issue and need to update the key manually key ??= await userSvc.UpdateUserPublicKeyAsync(user).WaitAsync(ct); } diff --git a/Iceshrimp.Backend/Core/Queues/BackgroundTaskQueue.cs b/Iceshrimp.Backend/Core/Queues/BackgroundTaskQueue.cs index b1abcf0d..18088c54 100644 --- a/Iceshrimp.Backend/Core/Queues/BackgroundTaskQueue.cs +++ b/Iceshrimp.Backend/Core/Queues/BackgroundTaskQueue.cs @@ -146,11 +146,11 @@ public abstract class BackgroundTaskQueue ) { var db = scope.GetRequiredService(); - var poll = await db.Polls.FirstOrDefaultAsync(p => p.NoteId == job.NoteId, cancellationToken: token); + var poll = await db.Polls.FirstOrDefaultAsync(p => p.NoteId == job.NoteId, token); if (poll == null) return; if (poll.ExpiresAt > DateTime.UtcNow + TimeSpan.FromSeconds(30)) return; var note = await db.Notes.IncludeCommonProperties() - .FirstOrDefaultAsync(p => p.Id == poll.NoteId, cancellationToken: token); + .FirstOrDefaultAsync(p => p.Id == poll.NoteId, token); if (note == null) return; var notificationSvc = scope.GetRequiredService(); @@ -159,7 +159,7 @@ public abstract class BackgroundTaskQueue { var voters = await db.PollVotes.Where(p => p.Note == note && p.User.Host != null) .Select(p => p.User) - .ToListAsync(cancellationToken: token); + .ToListAsync(token); if (voters.Count == 0) return; diff --git a/Iceshrimp.Backend/Core/Services/InstanceService.cs b/Iceshrimp.Backend/Core/Services/InstanceService.cs index 91c2ad0c..e5ae3ace 100644 --- a/Iceshrimp.Backend/Core/Services/InstanceService.cs +++ b/Iceshrimp.Backend/Core/Services/InstanceService.cs @@ -30,7 +30,7 @@ public class InstanceService(DatabaseContext db, HttpClient httpClient) Id = IdHelpers.GenerateSlowflakeId(), Host = host, CaughtAt = DateTime.UtcNow, - LastCommunicatedAt = DateTime.UtcNow, + LastCommunicatedAt = DateTime.UtcNow }; await db.AddAsync(instance); await db.SaveChangesAsync(); diff --git a/Iceshrimp.Backend/Core/Services/NoteService.cs b/Iceshrimp.Backend/Core/Services/NoteService.cs index 7e05c3ac..4e149aa4 100644 --- a/Iceshrimp.Backend/Core/Services/NoteService.cs +++ b/Iceshrimp.Backend/Core/Services/NoteService.cs @@ -191,7 +191,7 @@ public class NoteService( } /// - /// This needs to be called before SaveChangesAsync on create & after on delete + /// This needs to be called before SaveChangesAsync on create & after on delete /// private async Task UpdateNoteCountersAsync(Note note, bool create) { diff --git a/Iceshrimp.Backend/Core/Services/SystemUserService.cs b/Iceshrimp.Backend/Core/Services/SystemUserService.cs index 8c799938..3157fa45 100644 --- a/Iceshrimp.Backend/Core/Services/SystemUserService.cs +++ b/Iceshrimp.Backend/Core/Services/SystemUserService.cs @@ -76,7 +76,12 @@ public class SystemUserService(ILogger logger, DatabaseContex PublicKey = keypair.ExportSubjectPublicKeyInfoPem() }; - var userProfile = new UserProfile { UserId = user.Id, AutoAcceptFollowed = false, Password = null }; + var userProfile = new UserProfile + { + UserId = user.Id, + AutoAcceptFollowed = false, + Password = null + }; var usedUsername = new UsedUsername { CreatedAt = DateTime.UtcNow, Username = username.ToLowerInvariant() }; diff --git a/Iceshrimp.Backend/Core/Services/UserService.cs b/Iceshrimp.Backend/Core/Services/UserService.cs index 38d4300e..7100e802 100644 --- a/Iceshrimp.Backend/Core/Services/UserService.cs +++ b/Iceshrimp.Backend/Core/Services/UserService.cs @@ -298,8 +298,8 @@ public class UserService( db.Update(user); await db.SaveChangesAsync(); await processPendingDeletes(); - user = await UpdateProfileMentions(user, actor, force: true); - UpdateUserPinnedNotesInBackground(actor, user, force: true); + user = await UpdateProfileMentions(user, actor, true); + UpdateUserPinnedNotesInBackground(actor, user, true); return user; } diff --git a/Iceshrimp.Backend/Iceshrimp.Backend.csproj b/Iceshrimp.Backend/Iceshrimp.Backend.csproj index 0389ebaa..6c84bf8e 100644 --- a/Iceshrimp.Backend/Iceshrimp.Backend.csproj +++ b/Iceshrimp.Backend/Iceshrimp.Backend.csproj @@ -16,53 +16,53 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - + + + + + + + + + + - - - - + + + + - + - + - + diff --git a/Iceshrimp.Parsing/Iceshrimp.Parsing.fsproj b/Iceshrimp.Parsing/Iceshrimp.Parsing.fsproj index 1b7f43bd..b6bd4a15 100644 --- a/Iceshrimp.Parsing/Iceshrimp.Parsing.fsproj +++ b/Iceshrimp.Parsing/Iceshrimp.Parsing.fsproj @@ -6,11 +6,11 @@ - + - + diff --git a/Iceshrimp.Tests/Parsing/SearchQueryTests.cs b/Iceshrimp.Tests/Parsing/SearchQueryTests.cs index c5939c2d..adaa7ef9 100644 --- a/Iceshrimp.Tests/Parsing/SearchQueryTests.cs +++ b/Iceshrimp.Tests/Parsing/SearchQueryTests.cs @@ -16,7 +16,8 @@ public class SearchQueryTests } [TestMethod] - [DataRow(false), DataRow(true)] + [DataRow(false)] + [DataRow(true)] public void TestParseFrom(bool negated) { List candidates = ["from", "author", "by", "user"]; @@ -27,7 +28,8 @@ public class SearchQueryTests } [TestMethod] - [DataRow(false), DataRow(true)] + [DataRow(false)] + [DataRow(true)] public void TestParseMention(bool negated) { List candidates = ["mention", "mentions", "mentioning"]; @@ -38,7 +40,8 @@ public class SearchQueryTests } [TestMethod] - [DataRow(false), DataRow(true)] + [DataRow(false)] + [DataRow(true)] public void TestParseReply(bool negated) { List candidates = ["reply", "replying", "to"]; @@ -49,7 +52,8 @@ public class SearchQueryTests } [TestMethod] - [DataRow(false), DataRow(true)] + [DataRow(false)] + [DataRow(true)] public void TestParseInstance(bool negated) { List candidates = ["instance", "domain", "host"]; @@ -78,7 +82,8 @@ public class SearchQueryTests } [TestMethod] - [DataRow(false), DataRow(true)] + [DataRow(false)] + [DataRow(true)] public void TestParseAttachment(bool negated) { List keyCandidates = ["has", "attachment", "attached"]; @@ -127,7 +132,8 @@ public class SearchQueryTests } [TestMethod] - [DataRow(false), DataRow(true)] + [DataRow(false)] + [DataRow(true)] public void TestParseIn(bool negated) { var key = negated ? "-in" : "in"; @@ -147,7 +153,8 @@ public class SearchQueryTests } [TestMethod] - [DataRow(false), DataRow(true)] + [DataRow(false)] + [DataRow(true)] public void TestParseMisc(bool negated) { var key = negated ? "-filter" : "filter"; @@ -165,7 +172,7 @@ public class SearchQueryTests new MiscFilter(negated, "renotes"), new MiscFilter(negated, "renotes"), new MiscFilter(negated, "renotes"), - new MiscFilter(negated, "renotes"), + new MiscFilter(negated, "renotes") ]; results.Should() .HaveCount(expectedResults.Count) @@ -173,7 +180,8 @@ public class SearchQueryTests } [TestMethod] - [DataRow(false), DataRow(true)] + [DataRow(false)] + [DataRow(true)] public void TestParseWord(bool negated) { List candidates = ["test", "word", "since:2023-10-10invalid", "in:bookmarkstypo"];