frontend_projekt/OnlyPrompt.Backend/Controllers/SubscriptionController.cs
2026-04-12 03:45:01 +02:00

181 lines
6.1 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.Subscription;
using OnlyPrompt.Backend.Database;
using OnlyPrompt.Backend.Database.Models;
using OnlyPrompt.Backend.Utils;
using System.ComponentModel.DataAnnotations;
using System.Formats.Asn1;
namespace OnlyPrompt.Backend.Controllers
{
[ApiController]
[Route("api/v1/subscriptions")]
[Authorize(Roles = ModelConstants.UserRole)]
public class SubscriptionController : BaseController
{
private static ValidationProblem TierLevelExistsProblem = TypedResults.ValidationProblem(new Dictionary<string, string[]>
{
{ nameof(SubscriptionTierModel.Level), new[] { "Tier with this level already exists." } }
});
public SubscriptionController(OnlyPromptContext db, IMapper mapper) : base(db, mapper)
{
}
[HttpPut("{userId}/{level}")]
public async Task<Results<Ok, BadRequest<string>, NotFound<string>>> SubscribeAsync(Identifier subscribeToId, int? level = null)
{
var userId = User.GetUserId();
var subscribeTo = await _db.Users.Include(x => x.SubscriptionTiers.Where(st => st.Level == level))
.FirstOrDefaultAsync(
user => subscribeToId.Id.HasValue ? user.Id == subscribeToId.Id.Value : user.Profile.Slug == subscribeToId.Slug
);
if (subscribeTo is null)
return TypedResults.NotFound($"No user found with identifier {subscribeToId}");
if (subscribeTo.Id == userId)
return TypedResults.BadRequest("Cannot subscribe to yourself");
SubscriptionTierModel? tier = subscribeTo.SubscriptionTiers.FirstOrDefault();
if (level.HasValue && tier is null)
return TypedResults.NotFound($"No subscription tier found for user {subscribeToId} with level {level.Value}");
var existingSubscription = await _db.Subscriptions.FirstOrDefaultAsync(
sub => subscribeToId.Id.HasValue ? sub.SubscribedToId == subscribeToId.Id.Value : sub.SubscribedTo.Profile.Slug == subscribeToId.Slug
&& sub.SubscriberId == userId
);
if (existingSubscription is null)
{
existingSubscription = new SubscriptionModel
{
SubscribedTo = subscribeTo,
SubscriberId = userId.Value,
SubscriptionTier = tier
};
_db.Subscriptions.Add(existingSubscription);
}
else
{
existingSubscription.SubscriptionTier = tier;
}
await _db.SaveChangesAsync();
return TypedResults.Ok();
}
[HttpGet]
public async Task<ApiSubscription[]> GetSubscriptionsAsync([Range(0, double.MaxValue)]int offset = 0, [Range(1, 100)]int limit = 20)
{
var userId = User.GetUserId();
var subscriptions = await _db.Subscriptions
.Where(x => x.SubscriberId == userId)
.OrderBy(x => x.SubscribedToId)
.Skip(offset)
.Take(limit)
.ProjectTo<ApiSubscription>(_mapper.ConfigurationProvider)
.ToArrayAsync();
return subscriptions;
}
[HttpGet("{userId}")]
public async Task<ApiSubscription?> GetCurrentSubscriptionAsync(Identifier subscribeToId)
{
var userId = User.GetUserId();
var subscription = await _db.Subscriptions
.Where(
sub => subscribeToId.Id.HasValue ? sub.SubscribedToId == subscribeToId.Id.Value : sub.SubscribedTo.Profile.Slug == subscribeToId.Slug
&& sub.SubscriberId == userId
)
.ProjectTo<ApiSubscription>(_mapper.ConfigurationProvider)
.FirstOrDefaultAsync();
return subscription;
}
[HttpDelete("{userId}")]
public async Task<Results<Ok, NotFound<string>>> UnsubscribeAsync(Identifier subscribeToId)
{
var userId = User.GetUserId();
var count = await _db.Subscriptions
.Where(
sub => subscribeToId.Id.HasValue ? sub.SubscribedToId == subscribeToId.Id.Value : sub.SubscribedTo.Profile.Slug == subscribeToId.Slug
&& sub.SubscriberId == userId
)
.ExecuteDeleteAsync();
if (count == 0)
return TypedResults.NotFound($"No subscription found for user {subscribeToId}");
return TypedResults.Ok();
}
[HttpPost("tiers")]
public async Task<Results<Ok<ApiSubscriptionTier>, ValidationProblem>> CreateOrUpdateSubscriptionTierAsync([FromBody] ApiCreateSubscriptionTierRequest tier)
{
var userId = User.GetUserId();
var levelExists = await _db.SubscriptionTiers.AnyAsync(t => t.UserId == userId && t.Level == tier.Level);
if (levelExists)
return TierLevelExistsProblem;
var model = _mapper.Map<SubscriptionTierModel>(tier);
model.UserId = userId!.Value;
_db.SubscriptionTiers.Add(model);
await _db.SaveChangesAsync();
return TypedResults.Ok(_mapper.Map<ApiSubscriptionTier>(model));
}
[HttpPut("tiers/{id}")]
public async Task<Results<Ok<ApiSubscriptionTier>, NotFound<string>, ValidationProblem>> UpdateSubscriptionTierAsync(Guid id, [FromBody] ApiUpdateSubscriptionTierRequest tier)
{
var userId = User.GetUserId();
var existingTier = await _db.SubscriptionTiers.FirstOrDefaultAsync(t => t.Id == id && t.UserId == userId);
if (existingTier is null)
return TypedResults.NotFound($"No subscription tier found with id {id}");
if (existingTier.Level != tier.Level)
{
var levelExists = await _db.SubscriptionTiers.AnyAsync(t => t.UserId == userId && t.Level == tier.Level);
if (levelExists)
return TierLevelExistsProblem;
}
if (string.IsNullOrEmpty(tier.Name) == false)
existingTier.Name = tier.Name;
if (string.IsNullOrEmpty(tier.Description) == false)
existingTier.Description = tier.Description;
if (tier.Level.HasValue)
existingTier.Level = tier.Level.Value;
if (tier.MonthlyPrice.HasValue)
existingTier.MonthlyPrice = tier.MonthlyPrice.Value;
await _db.SaveChangesAsync();
return TypedResults.Ok(_mapper.Map<ApiSubscriptionTier>(existingTier));
}
[HttpDelete("tiers/{id}")]
public async Task<Results<Ok, NotFound<string>>> DeleteSubscriptionTierAsync(Guid id)
{
var userId = User.GetUserId();
var count = await _db.SubscriptionTiers
.Where(t => t.Id == id && t.UserId == userId)
.ExecuteDeleteAsync();
if (count == 0)
return TypedResults.NotFound($"No subscription tier found with id {id}");
return TypedResults.Ok();
}
}
}