Files
SocialPub/PrivaPub/Federation/Controllers/EmojisController.cs
T

77 lines
2.8 KiB
C#
Raw Normal View History

using Microsoft.AspNetCore.Mvc;
using MongoDB.Entities;
using PrivaPub.Domain.Content;
using PrivaPub.Federation.Actors;
using PrivaPub.Federation.Rendering;
using PrivaPub.Models.Post;
using System.Text.Json.Nodes;
namespace PrivaPub.Federation.Controllers
{
// Each of the server's custom emoji as an ActivityPub `Emoji` object at its id, /emojis/{shortcode} (completion program
// R7; the path is LocalEmojis.Path): the tag that posts, actors and reactions carry, with its @context. GoToSocial takes
// an emoji only with an id, and may read it there. A disabled emoji is not served (404, it may come back); a deleted one
// answers 410 with a Tombstone. An emoji tells nothing about anyone, so it is served unsigned under SecureMode too, as the
// server's own actors are; a browser is sent to the picture.
[ApiController]
public class EmojisController : ControllerBase
{
const string ActivityContentType = "application/activity+json; charset=utf-8";
readonly ILocalActorService _localActors;
public EmojisController(ILocalActorService localActors)
{
_localActors = localActors;
}
[HttpGet, Route("/" + LocalEmojis.Path + "/{shortcode}")]
public async Task<IActionResult> Get(string shortcode, CancellationToken token)
{
Response.Headers.Vary = "Accept";
if (!LocalEmojis.IsShortcode(shortcode))
return NotFound();
var key = shortcode.ToLowerInvariant();
var emoji = await DB.Default.Find<LocalEmoji>().Match(e => e.Key == key).ExecuteFirstAsync(token);
if (emoji == default || emoji.Shortcode != shortcode)
return NotFound();
if (emoji.DeletedAt is { } deleted)
return new ContentResult
{
Content = new JsonObject
{
["@context"] = ActivityPubRenderer.ActivityStreams,
["id"] = LocalEmojis.Uri(_localActors.BaseAddress, emoji.Shortcode),
["type"] = "Tombstone",
["formerType"] = "Emoji",
["deleted"] = ActivityPubRenderer.Timestamp(deleted)
}.ToJsonString(),
ContentType = ActivityContentType,
StatusCode = StatusCodes.Status410Gone
};
if (emoji.Disabled || string.IsNullOrEmpty(emoji.Url))
return NotFound();
if (WantsHtml())
return Redirect(emoji.Url);
var live = new LocalEmojis.Live(emoji.ID, emoji.Shortcode, emoji.Url, emoji.StaticUrl ?? emoji.Url, emoji.ContentType ?? "image/png",
emoji.ImageUpdatedAt, emoji.Category, emoji.VisibleInPicker);
return new ContentResult
{
Content = LocalEmojis.Document(live, _localActors.BaseAddress).ToJsonString(),
ContentType = ActivityContentType,
StatusCode = StatusCodes.Status200OK
};
}
bool WantsHtml()
{
var accept = Request.Headers.Accept.ToString();
return accept.Contains("text/html", StringComparison.OrdinalIgnoreCase)
&& !accept.Contains("activity+json", StringComparison.OrdinalIgnoreCase)
&& !accept.Contains("ld+json", StringComparison.OrdinalIgnoreCase);
}
}
}