using Femto.Api.Controllers.Posts.Dto; using Femto.Common; using Femto.Modules.Blog.Application; using Femto.Modules.Blog.Application.Commands.AddPostComment; using Femto.Modules.Blog.Application.Commands.AddPostReaction; using Femto.Modules.Blog.Application.Commands.ClearPostReaction; using Femto.Modules.Blog.Application.Commands.CreatePost; using Femto.Modules.Blog.Application.Commands.DeletePost; using Femto.Modules.Blog.Application.Queries.GetPosts; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace Femto.Api.Controllers.Posts; [ApiController] [Route("posts")] public class PostsController(IBlogModule blogModule, ICurrentUserContext currentUserContext, IAuthorizationService auth) : ControllerBase { [HttpGet] public async Task> LoadPosts( [FromQuery] GetPublicPostsSearchParams searchParams, CancellationToken cancellationToken ) { var res = await blogModule.Query( new GetPostsQuery(currentUserContext.CurrentUser?.Id) { After = searchParams.After, Amount = searchParams.Amount ?? 20, AuthorId = searchParams.AuthorId, Author = searchParams.Author, }, cancellationToken ); return new LoadPostsResponse(res.Posts.Select(PostDto.FromModel)); } [HttpPost] [Authorize] public async Task> CreatePost( [FromBody] CreatePostRequest req, CancellationToken cancellationToken ) { var post = await blogModule.Command( new CreatePostCommand( req.AuthorId, req.Content, req.Media.Select( (media, idx) => new CreatePostMedia( media.MediaId, media.Url, media.Type, idx, media.Width, media.Height ) ), req.IsPublic, currentUserContext.CurrentUser! ), cancellationToken ); return new CreatePostResponse(PostDto.FromModel(post)); } [HttpGet("{postId}")] public async Task> GetPost( Guid postId, CancellationToken cancellationToken ) { var result = await blogModule.Query( new GetPostsQuery(postId, currentUserContext.CurrentUser?.Id), cancellationToken ); var post = result.Posts.SingleOrDefault(); if (post is null) return NotFound(); return new GetPostResponse(PostDto.FromModel(post)); } [HttpDelete("{postId}")] [Authorize] public async Task DeletePost(Guid postId, CancellationToken cancellationToken) { await blogModule.Command( new DeletePostCommand(postId, currentUserContext.CurrentUser!.Id), cancellationToken ); } [HttpPost("{postId}/reactions")] [Authorize] public async Task AddPostReaction( Guid postId, [FromBody] AddPostReactionRequest request, CancellationToken cancellationToken ) { var currentUser = currentUserContext.CurrentUser!; await blogModule.Command( new AddPostReactionCommand(postId, request.Emoji, currentUser.Id), cancellationToken ); return this.Ok(); } [HttpDelete("{postId}/reactions")] [Authorize] public async Task DeletePostReaction( Guid postId, [FromBody] DeletePostReactionRequest request, CancellationToken cancellationToken ) { var currentUser = currentUserContext.CurrentUser!; await blogModule.Command( new ClearPostReactionCommand(postId, request.Emoji, currentUser.Id), cancellationToken ); return this.Ok(); } [HttpPost("{postId}/comments")] [Authorize] public async Task AddPostComment( Guid postId, [FromBody] AddPostCommentRequest request, CancellationToken cancellationToken ) { if (currentUserContext.CurrentUser?.Id != request.AuthorId) return this.BadRequest(); await blogModule.Command( new AddPostCommentCommand(postId, request.AuthorId, request.Content), cancellationToken ); return this.Ok(); } }