Files
QuotifyBE/Controllers/CategoryController.cs

204 lines
6.8 KiB
C#

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using QuotifyBE.Data;
using QuotifyBE.Entities;
using QuotifyBE.DTOs;
using System.Threading.Tasks;
using QuotifyBE.Mapping;
using Microsoft.AspNetCore.Cors;
using Microsoft.EntityFrameworkCore;
namespace QuotifyBE.Controllers;
[ApiController]
[EnableCors]
[Route("api/v1/categories")]
[Produces("application/json")]
public class CategoryController : ControllerBase
{
private readonly ApplicationDbContext _db;
private readonly GeneralUseHelpers guhf;
public CategoryController(ApplicationDbContext db, GeneralUseHelpers GUHF)
{
_db = db;
guhf = GUHF;
}
// GET /api/v1/categories
/// <summary>
/// Get every category
/// </summary>
/// <remarks>
/// Can (and will) return an empty list if no categories are found in DB. <br/>
/// Has CORS set.
/// </remarks>
/// <response code="200">Returned on valid request</response>
// /// <response code="404">Returned when there are no categories to list</response>
[HttpGet]
[EnableCors]
[ProducesResponseType(typeof(CategoryShortDTO), 200)]
// [ProducesResponseType(typeof(ErrorDTO), 404)]
public async Task<IActionResult> GetQuotePage()
{
// The following seems to be a bad idea, so I leave it as is. ~eee4
//
// int totalCategories = await _db.Categories.CountAsync();
//
// if (totalCategories <= 0)
// {
// return NotFound(new ErrorDTO { Status = "error", Error_msg = "No categories to list" });
// }
// Get all the categories
List<Category> categories = await _db.Categories
.ToListAsync();
// Convert them to a list of DTO
List<CategoryShortDTO> result = categories
.Select(c => c.ToCategoryShortDTO())
.ToList();
// Return to user
return Ok(result);
}
// POST /api/v1/categories
/// <summary>
/// [AUTHED] Create a new category
/// </summary>
/// <remarks>
/// Allows authorized users to create categories.
/// <br/><br/>
/// <b>Important!</b>
/// Category names are case insensitive. <br/>
/// Has CORS set.
/// </remarks>
/// <response code="200">Returned on valid request</response>
/// <response code="406">Returned when such category already exists (case insensitive)</response>
[HttpPost]
[Authorize]
[EnableCors]
[ProducesResponseType(typeof(CategoryShortDTO), 200)]
[ProducesResponseType(typeof(ErrorDTO), 406)]
public async Task<IActionResult> PostNewCategory([FromBody] NewCategoryDTO formCategory)
{
// Check if such category doesn't already exist
Category? cat = await _db.Categories.FirstOrDefaultAsync(c => c.Name.ToLower() == formCategory.Name.ToLower());
if (cat != null)
{
return StatusCode(406, new ErrorDTO { Status = "error", Error_msg = "This category already exists" });
}
// Create new category
cat = new Category
{
Name = formCategory.Name,
Description = formCategory.Description,
CreatedAt = DateTime.UtcNow
};
// Add to DB
await _db.Categories.AddAsync(cat);
await _db.SaveChangesAsync();
// And send back to the user as DTO
return Ok(cat.ToCategoryShortDTO());
}
// DELETE /api/v1/categories
/// <summary>
/// [AUTHED] Delete a category
/// </summary>
/// <remarks>
/// Allows authorized users to delete categories.
/// <br/><br/>
/// Has CORS set.
/// </remarks>
/// <param name="id">Id of the category which shall be deleted</param>
/// <response code="200">Returned on valid request</response>
/// <response code="404">Returned when no such category exists</response>
[HttpDelete("{id}")]
[Authorize]
[EnableCors]
[ProducesResponseType(200)]
[ProducesResponseType(typeof(ErrorDTO), 404)]
public async Task<IActionResult> DeleteCategory(int id)
{
// (Attempt to) find the category
Category? cat = await _db.Categories
.FirstOrDefaultAsync(c => c.Id == id);
// Failed?
if (cat == null)
return NotFound(new { status = "error", error_msg = "Category not found" });
// Find all the QuoteId <-> CategoryId pairs for provided id
List<QuoteCategory> quoteLinks = await _db.QuoteCategories
.Where(qc => qc.CategoryId == id)
.ToListAsync();
// For each of the dependent quotes
foreach (var link in quoteLinks) {
// Remove all the associative pairs
_db.QuoteCategories.Remove(link);
}
// Finally, remove the category
_db.Categories.Remove(cat);
await _db.SaveChangesAsync();
// Return ok
return Ok(new { Status = "ok" });
}
// PATCH /api/v1/categories/1
/// <summary>
/// [AUTHED] Modify an existing category
/// </summary>
/// <remarks>
/// Allows authorized users to modify categories.
/// <br/><br/>
/// Has CORS set.
/// </remarks>
/// <param name="id">Id of the category which shall be modified</param>
/// <param name="updatedCategory">DTO with new name and description. Id and creation date are ignored.</param>
/// <response code="200">Returned on valid request</response>
/// <response code="400">Returned when category name is empty or null</response>
/// <response code="404">Returned when no such category exists</response>
[HttpPatch("{id}")]
[Authorize]
[EnableCors]
[ProducesResponseType(typeof(CategoryShortDTO), 200)]
[ProducesResponseType(typeof(ErrorDTO), 400)]
[ProducesResponseType(typeof(ErrorDTO), 404)]
public async Task<IActionResult> EditCategory(int id, [FromBody] CategoryShortDTO updatedCategory)
{
// Find the category to modify
Category? cat = await _db.Categories.FirstOrDefaultAsync(c => c.Id == id);
// Failed?
if (cat == null)
return NotFound(new { status = "error", error_msg = "Category not found" });
// Otherwise, ensure the category name is not empty or null
if (string.IsNullOrWhiteSpace(updatedCategory.Name))
return BadRequest(new ErrorDTO { Status = "error", Error_msg = "Category name cannot be empty." });
// Update the fields
cat.Name = updatedCategory.Name;
cat.Description = updatedCategory.Description;
// Note the user cannot modify the createdAt field,
// and we do not store last modification date.
await _db.SaveChangesAsync();
// Return the modified category to user
return Ok(cat.ToCategoryShortDTO());
}
}