using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using T120B165_ImgBoard.Dtos.Comment; using T120B165_ImgBoard.Dtos.Tag; using T120B165_ImgBoard.Models; using T120B165_ImgBoard.Services; using T120B165_ImgBoard.Utils; namespace T120B165_ImgBoard.Controllers; [ApiController] [Route("api/tags")] public class TagController( ITagService tagService, IPostService postService, ICommentService commentService) : ControllerBase { /// /// Creates a new tag. /// /// New tag data. /// Returns the newly created tag /// If request is malformed /// If authentication is missing /// If authorization is missing /// If tag already exists with such name [HttpPost] [Authorize(Roles = UserRoles.Admin)] [ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status409Conflict)] public async Task> Create(CreateTagDto dto) { // Check if tag exists, if it does, throw a conflict var existingTag = await tagService.GetByName(dto.Name); if (existingTag != null) { return Problem( detail: "Tag with such name already exists.", statusCode: StatusCodes.Status409Conflict ); } var createdTag = await tagService.Create(dto.Type, dto.Name); return CreatedAtAction(nameof(Get), new { name = createdTag.Name }, TagDto.FromTag(createdTag)); } /// /// Get a paginated list of tags. /// /// The page number /// Returns paginated list /// If request is malformed [HttpGet] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task>> GetAll(int page = 1) { var list = await tagService.GetAll(page); var newItems = list.Items.Select(TagDto.FromTag).ToList(); return Ok(new PagedList(newItems, list.CurrentPage, list.PageSize, list.TotalCount)); } /// /// Get specific tag by name. /// /// The tag name /// The tag data /// If request is malformed /// If tag does not exist [HttpGet("{name}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> Get(string name) { var tag = await tagService.GetByName(name); if (tag == null) { return NotFound(); } return Ok(TagDto.FromTag(tag)); } /// /// Delete specified tag. /// /// The tag name /// Indicates tag deletion success /// If request is malformed /// If authentication is missing /// If authorization is missing /// If tag does not exist [HttpDelete("{name}")] [Authorize(Roles = UserRoles.Admin)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task Delete(string name) { var deleted = await tagService.DeleteByName(name); if (!deleted) return NotFound(); return NoContent(); } /// /// Update specified tag. /// /// The tag name /// The new tag data /// Indicates tag update success /// If request is malformed /// If authentication is missing /// If authorization is missing /// If tag does not exist [HttpPatch("{name}")] [Authorize(Roles = UserRoles.Admin)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> Update(string name, EditTagDto dto) { var tag = await tagService.GetByName(name); if (tag == null) return NotFound(); var updatedTag = await tagService.Update(tag, dto.Type); return Ok(TagDto.FromTag(updatedTag)); } /// /// Get specific tag, specific post comment. /// /// Tag name /// Post ID /// Comment ID /// Comment data /// If request is malformed /// If tag or post or comment is not found [HttpGet("{tagName}/posts/{postId:int}/comments/{commentId:int}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> GetComment(string tagName, int postId, int commentId) { var tag = await tagService.GetByName(tagName); if (tag == null) return NotFound(); var entry = await postService.GetById(postId); if (entry == null) return NotFound(); if (entry.Tags.All(t => t.Name != tag.Name)) return NotFound(); var comment = await commentService.GetById(commentId); if (comment == null || entry.Id != comment.OriginalPost.Id) return NotFound(); return Ok(CommentDto.FromComment(comment)); } }