Swarm/DysonNetwork.Sphere/Wallet/SubscriptionController.cs
2025-06-22 03:15:16 +08:00

155 lines
4.9 KiB
C#

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using NodaTime;
using System.ComponentModel.DataAnnotations;
namespace DysonNetwork.Sphere.Wallet;
[ApiController]
[Route("/subscriptions")]
public class SubscriptionController(SubscriptionService subscriptions, AppDatabase db) : ControllerBase
{
[HttpGet]
[Authorize]
public async Task<ActionResult<List<Subscription>>> ListSubscriptions(
[FromQuery] int offset = 0,
[FromQuery] int take = 20
)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
var query = db.WalletSubscriptions.AsQueryable()
.Where(s => s.AccountId == currentUser.Id)
.Include(s => s.Coupon)
.OrderByDescending(s => s.BegunAt);
var totalCount = await query.CountAsync();
var subscriptionsList = await query
.Skip(offset)
.Take(take)
.ToListAsync();
Response.Headers["X-Total"] = totalCount.ToString();
return subscriptionsList;
}
[HttpGet("{identifier}")]
[Authorize]
public async Task<ActionResult<Subscription>> GetSubscription(string identifier)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
var subscription = await subscriptions.GetSubscriptionAsync(currentUser.Id, identifier);
if (subscription is null) return NotFound($"Subscription with identifier {identifier} was not found.");
return subscription;
}
public class CreateSubscriptionRequest
{
[Required] public string Identifier { get; set; } = null!;
[Required] public string PaymentMethod { get; set; } = null!;
[Required] public PaymentDetails PaymentDetails { get; set; } = null!;
public string? Coupon { get; set; }
public int? CycleDurationDays { get; set; }
public bool IsFreeTrial { get; set; } = false;
public bool IsAutoRenewal { get; set; } = true;
}
[HttpPost]
[Authorize]
public async Task<ActionResult<Subscription>> CreateSubscription([FromBody] CreateSubscriptionRequest request)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
Duration? cycleDuration = null;
if (request.CycleDurationDays.HasValue)
{
cycleDuration = Duration.FromDays(request.CycleDurationDays.Value);
}
try
{
var subscription = await subscriptions.CreateSubscriptionAsync(
currentUser,
request.Identifier,
request.PaymentMethod,
request.PaymentDetails,
cycleDuration,
request.Coupon,
request.IsFreeTrial,
request.IsAutoRenewal
);
return subscription;
}
catch (ArgumentOutOfRangeException ex)
{
return BadRequest(ex.Message);
}
catch (InvalidOperationException ex)
{
return BadRequest(ex.Message);
}
}
[HttpPost("{identifier}/cancel")]
[Authorize]
public async Task<ActionResult<Subscription>> CancelSubscription(string identifier)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
try
{
var subscription = await subscriptions.CancelSubscriptionAsync(currentUser.Id, identifier);
return subscription;
}
catch (InvalidOperationException ex)
{
return BadRequest(ex.Message);
}
}
[HttpPost("{identifier}/order")]
[Authorize]
public async Task<ActionResult<Order>> CreateSubscriptionOrder(string identifier)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
try
{
var order = await subscriptions.CreateSubscriptionOrder(currentUser.Id, identifier);
return order;
}
catch (InvalidOperationException ex)
{
return BadRequest(ex.Message);
}
}
public class SubscriptionOrderRequest
{
[Required] public string OrderId { get; set; } = null!;
}
[HttpPost("order/handle")]
[Authorize]
public async Task<ActionResult<Subscription>> HandleSubscriptionOrder([FromBody] SubscriptionOrderRequest request)
{
var order = await db.PaymentOrders.FindAsync(request.OrderId);
if (order is null) return NotFound($"Order with ID {request.OrderId} was not found.");
try
{
var subscription = await subscriptions.HandleSubscriptionOrder(order);
return subscription;
}
catch (InvalidOperationException ex)
{
return BadRequest(ex.Message);
}
}
}