181 lines
6.1 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|