using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using MongoDB.Entities; using PrivaPub.Api.Mastodon.Infrastructure; using PrivaPub.Api.Mastodon.Mappers; using PrivaPub.Domain.Privacy; using PrivaPub.Domain.Social; using PrivaPub.Models.Post; using PrivaPub.Models.Social; using PrivaPub.StaticServices; using PostEntity = PrivaPub.Models.Post.Post; namespace PrivaPub.Api.Mastodon.Controllers { public class ReactionsController : MastodonController { readonly DbEntities _dbEntities; readonly MastodonMapper _mapper; readonly IReactions _reactions; public ReactionsController(DbEntities dbEntities, MastodonMapper mapper, IReactions reactions) { _dbEntities = dbEntities; _mapper = mapper; _reactions = reactions; } [HttpGet("/api/v1/pleroma/statuses/{id}/reactions"), Scope("read:statuses", requiresUser: false), AllowAnonymous] public async Task List(string id, CancellationToken token) { var post = await Visible(id, token); if (post == default) return NotFoundError(); var reactions = await DB.Default.Find().Match(r => r.PostId == post.ID).ExecuteAsync(token); var accounts = await _mapper.Accounts(reactions.Select(r => r.AccountId), token); return Json(reactions.GroupBy(r => r.Emoji).Select(group => new { name = group.Key, count = group.Count(), me = MyId != default && group.Any(r => r.AccountId == MyId), url = _mapper.ProxiedUrl(group.First().EmojiURL), accounts = group.Select(r => accounts.GetValueOrDefault(r.AccountId)).Where(a => a != default).ToList() }).OrderByDescending(r => r.count).ToList()); } [HttpPut("/api/v1/pleroma/statuses/{id}/reactions/{emoji}"), Scope("write:favourites")] public async Task React(string id, string emoji, CancellationToken token) { var post = await Visible(id, token); if (post == default) return NotFoundError(); if (!await _reactions.React(Me, post, Uri.UnescapeDataString(emoji), token)) return Error(StatusCodes.Status422UnprocessableEntity, "Validation failed: That emoji cannot be used here"); return Json(await _mapper.Status(post, MyId, token)); } [HttpDelete("/api/v1/pleroma/statuses/{id}/reactions/{emoji}"), Scope("write:favourites")] public async Task Unreact(string id, string emoji, CancellationToken token) { var post = await Visible(id, token); if (post == default) return NotFoundError(); await _reactions.Unreact(Me, post, Uri.UnescapeDataString(emoji), token); return Json(await _mapper.Status(post, MyId, token)); } async Task Visible(string id, CancellationToken token) { var post = await _dbEntities.Posts.Match(p => p.ID == id && !p.DeletedAt.HasValue && p.ReblogOfPostId == null).ExecuteFirstAsync(token); return post != default && post.Visibility != PostVisibility.LocalGeo && await VisibilityPolicy.CanSee(post, MyId, token) ? post : default; } } }