184 lines
5.4 KiB
C#
184 lines
5.4 KiB
C#
using AutoMapper;
|
|
using AutoMapper.QueryableExtensions;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Http.HttpResults;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using OnlyPrompt.Backend.ApiModels.Prompt;
|
|
using OnlyPrompt.Backend.ApiModels.UserProfile;
|
|
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/prompts")]
|
|
[Authorize(Roles = ModelConstants.UserRole)]
|
|
public class PromptController : BaseController
|
|
{
|
|
public PromptController(OnlyPromptContext db, IMapper mapper) : base(db, mapper)
|
|
{
|
|
}
|
|
|
|
private IQueryable<PromptModel> GetAccessiblePrompts(Guid userId)
|
|
{
|
|
return _db.Prompts.Where(
|
|
p => p.SubscriptionTier == null
|
|
|| p.Creator.Subscribers.Any(
|
|
sub => sub.SubscriberId == userId
|
|
&& p.SubscriptionTier!.Level <= sub.SubscriptionTier!.Level
|
|
)
|
|
);
|
|
}
|
|
|
|
[HttpGet("{id}")]
|
|
public async Task<Results<Ok<ApiPrompt>, NotFound<string>>> GetPromptAsync(Identifier id)
|
|
{
|
|
var userId = User.GetUserId();
|
|
var prompt = await GetAccessiblePrompts(userId.Value)
|
|
.OfIdentifer(id)
|
|
.FirstOrDefaultAsync();
|
|
|
|
if (prompt is null)
|
|
return TypedResults.NotFound("Prompt not found or no permission");
|
|
|
|
var apiPrompt = _mapper.Map<ApiPrompt>(prompt);
|
|
return TypedResults.Ok(apiPrompt);
|
|
}
|
|
|
|
[HttpDelete("{id}")]
|
|
public async Task<Results<NoContent, NotFound<string>>> DeletePromptAsync(Identifier id)
|
|
{
|
|
var userId = User.GetUserId();
|
|
var isAdmin = User.IsInRole(ModelConstants.AdminRole);
|
|
var count = await _db.Prompts
|
|
.OfIdentifer(id)
|
|
.Where(p => p.CreatorId == userId || isAdmin)
|
|
.ExecuteDeleteAsync();
|
|
|
|
if (count == 0)
|
|
return TypedResults.NotFound("Prompt not found or no permission");
|
|
|
|
return TypedResults.NoContent();
|
|
}
|
|
|
|
[HttpPost]
|
|
public async Task<Results<Ok<ApiPrompt>, NotFound<string>>> CreatePromptAsync([FromBody] ApiCreatePromptRequest request)
|
|
{
|
|
var userId = User.GetUserId();
|
|
|
|
var category = await _db.Categories.FindByIdentifierAsync(request.Category);
|
|
if (category is null)
|
|
return TypedResults.NotFound("Category not found");
|
|
|
|
SubscriptionTierModel? subscriptionTier = null;
|
|
if (request.SubscriptionTier.HasValue)
|
|
{
|
|
subscriptionTier = await _db.SubscriptionTiers.FirstOrDefaultAsync(
|
|
t => t.Level == request.SubscriptionTier.Value
|
|
&& t.UserId == userId
|
|
);
|
|
|
|
if (subscriptionTier is null)
|
|
return TypedResults.NotFound("Subscription tier not found");
|
|
}
|
|
|
|
var slug = request.Slug;
|
|
if (string.IsNullOrEmpty(slug))
|
|
slug = await SlugHelper.GenerateUniqueSlugAsync(request.Title, slug => _db.Prompts.AnyAsync(p => p.Slug == slug), ModelConstants.MaxSlugLength);
|
|
|
|
var prompt = new PromptModel
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Title = request.Title,
|
|
Description = request.Description,
|
|
Prompt = request.Content,
|
|
CreatorId = userId.Value,
|
|
SubscriptionTier = subscriptionTier,
|
|
Category = category,
|
|
Slug = slug
|
|
};
|
|
|
|
_db.Prompts.Add(prompt);
|
|
await _db.SaveChangesAsync();
|
|
var apiPrompt = _mapper.Map<ApiPrompt>(prompt);
|
|
return TypedResults.Ok(apiPrompt);
|
|
}
|
|
|
|
[HttpGet("{id}/reviews")]
|
|
public async Task<Ok<ApiReview[]>> GetReviewsAsync(Identifier id, [FromQuery] int offset = 0, [Range(1, 200)][FromQuery] int limit = 20)
|
|
{
|
|
var userId = User.GetUserId();
|
|
var accessiblePrompts = GetAccessiblePrompts(userId!.Value);
|
|
var reviews = await accessiblePrompts.Select(x => x.Reviews)
|
|
.Skip(offset)
|
|
.Take(limit)
|
|
.ProjectTo<ApiReview>(_mapper.ConfigurationProvider)
|
|
.ToArrayAsync();
|
|
|
|
return TypedResults.Ok(reviews);
|
|
}
|
|
|
|
[HttpPut("{id}/reviews")]
|
|
public async Task<Results<Ok<ApiReview>, BadRequest<string>, NotFound<string>>> AddReviewAsync(Identifier id, [FromBody] ApiCreateReviewRequest request)
|
|
{
|
|
var userId = User.GetUserId();
|
|
var prompt = await GetAccessiblePrompts(userId!.Value)
|
|
.OfIdentifer(id)
|
|
.FirstOrDefaultAsync();
|
|
|
|
if (prompt is null)
|
|
return TypedResults.NotFound("Prompt not found or no permission");
|
|
|
|
if(prompt.CreatorId == userId)
|
|
return TypedResults.BadRequest("Cannot review your own prompt");
|
|
|
|
var review = await _db.Reviews.FirstOrDefaultAsync(
|
|
r => r.PromptId == prompt.Id
|
|
&& r.ReviewerId == userId
|
|
);
|
|
|
|
if (review is null)
|
|
{
|
|
review = new ReviewModel
|
|
{
|
|
PromptId = prompt.Id,
|
|
ReviewerId = userId.Value,
|
|
Comment = request.Comment,
|
|
Rating = request.Rating
|
|
};
|
|
|
|
_db.Reviews.Add(review);
|
|
}
|
|
else
|
|
{
|
|
review.Comment = request.Comment;
|
|
review.Rating = request.Rating;
|
|
}
|
|
|
|
await _db.SaveChangesAsync();
|
|
var apiReview = _mapper.Map<ApiReview>(review);
|
|
return TypedResults.Ok(apiReview);
|
|
}
|
|
|
|
[HttpDelete("{promptId}/reviews/{reviewerId}")]
|
|
public async Task<Results<NoContent, NotFound<string>>> DeleteReviewAsync(Identifier promptId, Guid reviewerId)
|
|
{
|
|
var userId = User.GetUserId();
|
|
var isAdmin = User.IsInRole(ModelConstants.AdminRole);
|
|
var count = await _db.Reviews
|
|
.Where(
|
|
r => (promptId.Id.HasValue ? r.PromptId == promptId.Id : r.Prompt.Slug == promptId.Slug)
|
|
&& (r.ReviewerId == reviewerId || isAdmin)
|
|
)
|
|
.ExecuteDeleteAsync();
|
|
|
|
if (count == 0)
|
|
return TypedResults.NotFound("Review not found or no permission");
|
|
return TypedResults.NoContent();
|
|
}
|
|
}
|
|
}
|