using System.Net.Mime; using Iceshrimp.Backend.Controllers.Mastodon.Attributes; using Iceshrimp.Backend.Controllers.Mastodon.Schemas; using Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities; using Iceshrimp.Backend.Core.Configuration; using Iceshrimp.Backend.Core.Database; using Iceshrimp.Backend.Core.Services; 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(MediaTypeNames.Application.Json)] public class InstanceController(DatabaseContext db, MetaService meta) : ControllerBase { [HttpGet("/api/v1/instance")] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(InstanceInfoV1Response))] public async Task GetInstanceInfoV1([FromServices] IOptionsSnapshot config) { var userCount = await db.Users.LongCountAsync(p => p.Host == null && !Constants.SystemUsers.Contains(p.UsernameLower)); var noteCount = await db.Notes.LongCountAsync(p => p.UserHost == null); var instanceCount = await db.Instances.LongCountAsync(); var instanceName = await meta.Get(MetaEntity.InstanceName); var instanceDescription = await meta.Get(MetaEntity.InstanceDescription); var adminContact = await meta.Get(MetaEntity.AdminContactEmail); var res = new InstanceInfoV1Response(config.Value, instanceName, instanceDescription, adminContact) { Stats = new InstanceStats(userCount, noteCount, instanceCount) }; return Ok(res); } [HttpGet("/api/v2/instance")] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(InstanceInfoV2Response))] public async Task GetInstanceInfoV2([FromServices] IOptionsSnapshot config) { var cutoff = DateTime.UtcNow - TimeSpan.FromDays(30); var activeMonth = await db.Users.LongCountAsync(p => p.Host == null && !Constants.SystemUsers.Contains(p.UsernameLower) && p.LastActiveDate > cutoff); var instanceName = await meta.Get(MetaEntity.InstanceName); var instanceDescription = await meta.Get(MetaEntity.InstanceDescription); var adminContact = await meta.Get(MetaEntity.AdminContactEmail); var res = new InstanceInfoV2Response(config.Value, instanceName, instanceDescription, adminContact) { Usage = new InstanceUsage { Users = new InstanceUsersUsage { ActiveMonth = activeMonth } } }; return Ok(res); } [HttpGet("/api/v1/custom_emojis")] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable))] public async Task GetCustomEmojis() { var res = await db.Emojis.Where(p => p.Host == null) .Select(p => new EmojiEntity { Id = p.Id, Shortcode = p.Name, Url = p.PublicUrl, StaticUrl = p.PublicUrl, //TODO VisibleInPicker = true }) .ToListAsync(); return Ok(res); } [HttpGet("/api/v1/instance/translation_languages")] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Dictionary>))] public IActionResult GetTranslationLanguages() { return Ok(new Dictionary>()); } [HttpGet("/api/v1/instance/extended_description")] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(InstanceExtendedDescription))] public async Task GetExtendedDescription() { var description = await meta.Get(MetaEntity.InstanceDescription); var res = new InstanceExtendedDescription(description); return Ok(res); } }