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));
}
}