From f30e7f4ac3a74acbf40dee18058c4c29415457dd Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Mon, 12 Feb 2024 02:54:54 +0100 Subject: [PATCH] [backend/masto-client] Add basic /v1/instance endpoint (ISH-6) --- .../Mastodon/InstanceController.cs | 34 +++++++++ .../Mastodon/Schemas/Entities/InstanceInfo.cs | 73 +++++++++++++++++++ .../Controllers/Mastodon/StatusController.cs | 2 +- 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 Iceshrimp.Backend/Controllers/Mastodon/InstanceController.cs create mode 100644 Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/InstanceInfo.cs diff --git a/Iceshrimp.Backend/Controllers/Mastodon/InstanceController.cs b/Iceshrimp.Backend/Controllers/Mastodon/InstanceController.cs new file mode 100644 index 00000000..d856d498 --- /dev/null +++ b/Iceshrimp.Backend/Controllers/Mastodon/InstanceController.cs @@ -0,0 +1,34 @@ +using Iceshrimp.Backend.Controllers.Mastodon.Attributes; +using Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities; +using Iceshrimp.Backend.Core.Configuration; +using Iceshrimp.Backend.Core.Database; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.RateLimiting; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; + +namespace Iceshrimp.Backend.Controllers.Mastodon; + +[MastodonApiController] +[EnableCors("mastodon")] +[EnableRateLimiting("sliding")] +[Produces("application/json")] +public class InstanceController(DatabaseContext db) : Controller { + [HttpGet("/api/v1/instance")] + [Produces("application/json")] + public async Task GetInstanceInfo([FromServices] IOptionsSnapshot config) { + var userCount = await db.Users.LongCountAsync(p => p.Host == null); + var noteCount = await db.Notes.LongCountAsync(p => p.UserHost == null); + var instanceCount = await db.Instances.LongCountAsync(); + //TODO: admin contact + + var res = new InstanceInfo(config.Value) { + Stats = new InstanceStats(userCount, noteCount, instanceCount) + }; + + return Ok(res); + } + + //TODO: v2 +} \ No newline at end of file diff --git a/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/InstanceInfo.cs b/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/InstanceInfo.cs new file mode 100644 index 00000000..d982fb36 --- /dev/null +++ b/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/InstanceInfo.cs @@ -0,0 +1,73 @@ +using Iceshrimp.Backend.Core.Configuration; +using J = System.Text.Json.Serialization.JsonPropertyNameAttribute; + +namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities; + +public class InstanceInfo(Config config) { + [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("uri")] public string AccountDomain => config.Instance.AccountDomain; + [J("title")] public string InstanceName => config.Instance.AccountDomain; + [J("short_description")] public string ShortDescription => $"{config.Instance.AccountDomain} on Iceshrimp.NET"; + [J("description")] public string Description => $"{config.Instance.AccountDomain} on Iceshrimp.NET"; + + [J("registrations")] public bool RegsOpen => config.Security.Registrations == Enums.Registrations.Open; + [J("invites_enabled")] public bool RegsInvite => config.Security.Registrations == Enums.Registrations.Invite; + [J("approval_required")] public bool RegsClosed => config.Security.Registrations == Enums.Registrations.Closed; + + [J("urls")] public InstanceUrls Urls => new(config.Instance); + [J("configuration")] public InstanceConfiguration Configuration => new(config.Instance); + [J("stats")] public required InstanceStats Stats; + + //TODO: add the rest +} + +public class InstanceUrls(Config.InstanceSection config) { + [J("streaming_api")] public string StreamingApi => $"wss://{config.WebDomain}"; +} + +public class InstanceStats(long userCount, long noteCount, long instanceCount) { + [J("users_count")] public long UserCount => userCount; + [J("status_count")] public long NoteCount => noteCount; + [J("domain_count")] public long InstanceCount => instanceCount; +} + +public class InstanceConfiguration(Config.InstanceSection config) { + [J("accounts")] public InstanceAccountsConfiguration Accounts => new(); + [J("statuses")] public InstanceStatusesConfiguration Statuses => new(config.CharacterLimit); + [J("media_attachments")] public InstanceMediaConfiguration Media => new(); + [J("polls")] public InstancePollConfiguration Polls => new(); + [J("reactions")] public InstanceReactionConfiguration Reactions => new(); +} + +public class InstanceAccountsConfiguration { + [J("max_featured_tags")] public int MaxFeaturedTags => 20; +} + +public class InstanceStatusesConfiguration(int maxNoteChars) { + [J("supported_mime_types")] public List SupportedMimeTypes => ["text/x.misskeymarkdown"]; + [J("max_characters")] public int MaxNoteChars => maxNoteChars; + [J("max_media_attachments")] public int MaxMediaAttachments => 16; + [J("characters_reserved_per_url")] public int ReservedUrlChars => 23; +} + +public class InstanceMediaConfiguration { + [J("supported_mime_types")] public List SupportedMimeTypes => Constants.BrowserSafeMimeTypes.ToList(); + [J("image_size_limit")] public int ImageSizeLimit => 10485760; + [J("image_matrix_limit")] public int ImageMatrixLimit => 16777216; + [J("video_size_limit")] public int VideoSizeLimit => 41943040; + [J("video_frame_limit")] public int VideoFrameLimit => 60; + [J("video_matrix_limit")] public int VideoMatrixLimit => 2304000; +} + +public class InstancePollConfiguration { + [J("max_options")] public int MaxOptions => 10; + [J("max_characters_per_option")] public int MaxCharsPerOption => 50; + [J("min_expiration")] public int MinExpiration => 50; + [J("max_expiration")] public int MaxExpiration => 2629746; +} + +public class InstanceReactionConfiguration { + [J("max_reactions")] public int MaxOptions => 1; +} \ No newline at end of file diff --git a/Iceshrimp.Backend/Controllers/Mastodon/StatusController.cs b/Iceshrimp.Backend/Controllers/Mastodon/StatusController.cs index 7983338f..a31f3cef 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/StatusController.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/StatusController.cs @@ -78,7 +78,7 @@ public class StatusController(DatabaseContext db, NoteRenderer noteRenderer, Not [Authorize("write:statuses")] [Produces("application/json")] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Status))] - [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(MastodonErrorResponse))] public async Task PostNote([FromHybrid] StatusSchemas.PostStatusRequest request) { var user = HttpContext.GetUserOrFail();