124 lines
4.2 KiB
C#
124 lines
4.2 KiB
C#
using AutoMapper;
|
|
using AutoMapper.QueryableExtensions;
|
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Http.HttpResults;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using OnlyPrompt.Backend.ApiModels.Category;
|
|
using OnlyPrompt.Backend.Database;
|
|
using OnlyPrompt.Backend.Database.Models;
|
|
using OnlyPrompt.Backend.Utils;
|
|
using System.ComponentModel.DataAnnotations;
|
|
|
|
namespace OnlyPrompt.Backend.Controllers
|
|
{
|
|
[ApiController]
|
|
[Route("api/v1/categories")]
|
|
[Authorize(Roles = ModelConstants.AdminRole, AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
|
public class CategoryController : BaseController
|
|
{
|
|
private static ValidationProblem SlugExistsProblem = TypedResults.ValidationProblem(new Dictionary<string, string[]>
|
|
{
|
|
{ nameof(CategoryModel.Slug), new[] { "Slug already exists." } }
|
|
});
|
|
|
|
public CategoryController(OnlyPromptContext db, IMapper mapper) : base(db, mapper)
|
|
{
|
|
}
|
|
|
|
[HttpGet("minimal")]
|
|
[Authorize(Roles = ModelConstants.UserRole)]
|
|
public async Task<ApiMinimalCategory[]> GetMinimalCategoriesAsync()
|
|
{
|
|
var categories = await _db.Categories
|
|
.ProjectTo<ApiMinimalCategory>(_mapper.ConfigurationProvider)
|
|
.ToArrayAsync();
|
|
|
|
return categories;
|
|
}
|
|
|
|
[HttpGet]
|
|
[Authorize(Roles = ModelConstants.UserRole)]
|
|
public async Task<ApiCategory[]> GetCategoriesAsync([Range(0, double.MaxValue)][FromQuery] int offset = 0, [Range(1, 100)][FromQuery] int limit = 20)
|
|
{
|
|
var categories = await _db.Categories
|
|
.OrderBy(c => c.Id)
|
|
.Skip(offset)
|
|
.Take(limit)
|
|
.ProjectTo<ApiCategory>(_mapper.ConfigurationProvider)
|
|
.ToArrayAsync();
|
|
|
|
return categories;
|
|
}
|
|
|
|
[HttpPost]
|
|
public async Task<Results<Ok<ApiCategory>, ValidationProblem>> CreateCategoryAsync([FromBody] ApiCreateCategoryRequest request)
|
|
{
|
|
var exists = await _db.Categories.AnyAsync(c => c.Slug == request.Slug);
|
|
if (exists)
|
|
return SlugExistsProblem;
|
|
|
|
var model = _mapper.Map<CategoryModel>(request);
|
|
if (string.IsNullOrWhiteSpace(model.Slug))
|
|
model.Slug = await SlugHelper.GenerateUniqueSlugAsync(request.Name, slug => _db.Categories.AnyAsync(c => c.Slug == slug), ModelConstants.MaxSlugLength);
|
|
|
|
_db.Categories.Add(model);
|
|
await _db.SaveChangesAsync();
|
|
return TypedResults.Ok(_mapper.Map<ApiCategory>(model));
|
|
}
|
|
|
|
[HttpPut("{id}")]
|
|
public async Task<Results<Ok<ApiCategory>, NotFound<string>, ValidationProblem>> UpdateCategoryAsync(Identifier id, [FromBody] ApiUpdateCategoryRequest request)
|
|
{
|
|
var category = await _db.Categories.FindByIdentifierAsync(id);
|
|
if (category is null)
|
|
return TypedResults.NotFound("Category not found");
|
|
|
|
if (string.IsNullOrWhiteSpace(request.Name) == false)
|
|
category.Name = request.Name;
|
|
|
|
if(string.IsNullOrWhiteSpace(request.Description) == false)
|
|
category.Description = request.Description;
|
|
|
|
if (string.IsNullOrWhiteSpace(request.Slug) == false && request.Slug != category.Slug)
|
|
{
|
|
var exists = await _db.Categories.AnyAsync(c => c.Slug == request.Slug && c.Id != category.Id);
|
|
if (exists)
|
|
return SlugExistsProblem;
|
|
|
|
category.Slug = request.Slug;
|
|
}
|
|
|
|
await _db.SaveChangesAsync();
|
|
return TypedResults.Ok(_mapper.Map<ApiCategory>(category));
|
|
}
|
|
|
|
[HttpDelete("{id}")]
|
|
public async Task<Results<NoContent, BadRequest<string>, NotFound<string>>> DeleteCategoryAsync(Identifier id, [FromQuery] Identifier? replaceWith = null)
|
|
{
|
|
var hasPrompts = await _db.Prompts.AnyAsync(p => p.CategoryId == id.Id);
|
|
if (hasPrompts)
|
|
{
|
|
if (replaceWith.HasValue == false)
|
|
return TypedResults.BadRequest("Category has associated prompts. Provide a replacement category to reassign them to.");
|
|
|
|
var replacement = await _db.Categories.FindByIdentifierAsync(replaceWith.Value);
|
|
if(replacement is null)
|
|
return TypedResults.NotFound("Replacement category not found.");
|
|
|
|
await _db.Prompts.Where(p => p.CategoryId == id.Id)
|
|
.ExecuteUpdateAsync(p => p.SetProperty(p => p.CategoryId, replacement.Id));
|
|
}
|
|
|
|
var count = await _db.Categories.OfIdentifer(id)
|
|
.ExecuteDeleteAsync();
|
|
|
|
if (count == 0)
|
|
return TypedResults.NotFound("Category not found");
|
|
|
|
return TypedResults.NoContent();
|
|
}
|
|
}
|
|
}
|