🐛 Fix wallet service authorization check
This commit is contained in:
@@ -1,5 +1,3 @@
|
|||||||
using DysonNetwork.Shared.Models;
|
|
||||||
|
|
||||||
namespace DysonNetwork.Messager.Wallet;
|
namespace DysonNetwork.Messager.Wallet;
|
||||||
|
|
||||||
public class FundEmbed
|
public class FundEmbed
|
||||||
|
|||||||
@@ -76,12 +76,12 @@ public class OrderController(
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<SnWalletOrder>> PayOrder(Guid id, [FromBody] PayOrderRequest request)
|
public async Task<ActionResult<SnWalletOrder>> PayOrder(Guid id, [FromBody] PayOrderRequest request)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Get the wallet for the current user
|
// Get the wallet for the current user
|
||||||
var wallet = await db.Wallets.FirstOrDefaultAsync(w => w.AccountId == currentUser.Id);
|
var wallet = await db.Wallets.FirstOrDefaultAsync(w => w.AccountId == Guid.Parse(currentUser.Id));
|
||||||
if (wallet == null)
|
if (wallet == null)
|
||||||
return BadRequest("Wallet was not found.");
|
return BadRequest("Wallet was not found.");
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using NodaTime;
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using DysonNetwork.Wallet.Payment.PaymentHandlers;
|
using DysonNetwork.Wallet.Payment.PaymentHandlers;
|
||||||
using DysonNetwork.Shared.Models;
|
using DysonNetwork.Shared.Models;
|
||||||
|
using DysonNetwork.Shared.Proto;
|
||||||
|
|
||||||
namespace DysonNetwork.Wallet.Payment;
|
namespace DysonNetwork.Wallet.Payment;
|
||||||
|
|
||||||
@@ -20,10 +21,10 @@ public class SubscriptionController(SubscriptionService subscriptions, AfdianPay
|
|||||||
[FromQuery] int take = 20
|
[FromQuery] int take = 20
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
var query = db.WalletSubscriptions.AsQueryable()
|
var query = db.WalletSubscriptions.AsQueryable()
|
||||||
.Where(s => s.AccountId == currentUser.Id)
|
.Where(s => s.AccountId == Guid.Parse(currentUser.Id))
|
||||||
.Include(s => s.Coupon)
|
.Include(s => s.Coupon)
|
||||||
.OrderByDescending(s => s.BegunAt);
|
.OrderByDescending(s => s.BegunAt);
|
||||||
|
|
||||||
@@ -43,10 +44,10 @@ public class SubscriptionController(SubscriptionService subscriptions, AfdianPay
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<SnWalletSubscription>> GetSubscriptionFuzzy(string prefix)
|
public async Task<ActionResult<SnWalletSubscription>> GetSubscriptionFuzzy(string prefix)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
var subscription = await db.WalletSubscriptions
|
var subscription = await db.WalletSubscriptions
|
||||||
.Where(s => s.AccountId == currentUser.Id && s.IsActive)
|
.Where(s => s.AccountId == Guid.Parse(currentUser.Id) && s.IsActive)
|
||||||
.Where(s => EF.Functions.ILike(s.Identifier, prefix + "%"))
|
.Where(s => EF.Functions.ILike(s.Identifier, prefix + "%"))
|
||||||
.OrderByDescending(s => s.BegunAt)
|
.OrderByDescending(s => s.BegunAt)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
@@ -59,9 +60,9 @@ public class SubscriptionController(SubscriptionService subscriptions, AfdianPay
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<SnWalletSubscription>> GetSubscription(string identifier)
|
public async Task<ActionResult<SnWalletSubscription>> GetSubscription(string identifier)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
var subscription = await subscriptions.GetSubscriptionAsync(currentUser.Id, identifier);
|
var subscription = await subscriptions.GetSubscriptionAsync(Guid.Parse(currentUser.Id), identifier);
|
||||||
if (subscription is null) return NotFound($"Subscription with identifier {identifier} was not found.");
|
if (subscription is null) return NotFound($"Subscription with identifier {identifier} was not found.");
|
||||||
|
|
||||||
return subscription;
|
return subscription;
|
||||||
@@ -85,7 +86,7 @@ public class SubscriptionController(SubscriptionService subscriptions, AfdianPay
|
|||||||
[FromHeader(Name = "X-Noop")] bool noop = false
|
[FromHeader(Name = "X-Noop")] bool noop = false
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
Duration? cycleDuration = null;
|
Duration? cycleDuration = null;
|
||||||
if (request.CycleDurationDays.HasValue)
|
if (request.CycleDurationDays.HasValue)
|
||||||
@@ -121,11 +122,11 @@ public class SubscriptionController(SubscriptionService subscriptions, AfdianPay
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<SnWalletSubscription>> CancelSubscription(string identifier)
|
public async Task<ActionResult<SnWalletSubscription>> CancelSubscription(string identifier)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var subscription = await subscriptions.CancelSubscriptionAsync(currentUser.Id, identifier);
|
var subscription = await subscriptions.CancelSubscriptionAsync(Guid.Parse(currentUser.Id), identifier);
|
||||||
return subscription;
|
return subscription;
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException ex)
|
catch (InvalidOperationException ex)
|
||||||
@@ -138,11 +139,11 @@ public class SubscriptionController(SubscriptionService subscriptions, AfdianPay
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<SnWalletOrder>> CreateSubscriptionOrder(string identifier)
|
public async Task<ActionResult<SnWalletOrder>> CreateSubscriptionOrder(string identifier)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var order = await subscriptions.CreateSubscriptionOrder(currentUser.Id, identifier);
|
var order = await subscriptions.CreateSubscriptionOrder(Guid.Parse(currentUser.Id), identifier);
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException ex)
|
catch (InvalidOperationException ex)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using NodaTime;
|
using NodaTime;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using DysonNetwork.Shared.Models;
|
using DysonNetwork.Shared.Models;
|
||||||
|
using DysonNetwork.Shared.Proto;
|
||||||
|
|
||||||
namespace DysonNetwork.Wallet.Payment;
|
namespace DysonNetwork.Wallet.Payment;
|
||||||
|
|
||||||
@@ -24,9 +25,9 @@ public class SubscriptionGiftController(
|
|||||||
[FromQuery] int take = 20
|
[FromQuery] int take = 20
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
var query = await subscriptions.GetGiftsByGifterAsync(currentUser.Id);
|
var query = await subscriptions.GetGiftsByGifterAsync(Guid.Parse(currentUser.Id));
|
||||||
var totalCount = query.Count;
|
var totalCount = query.Count;
|
||||||
|
|
||||||
var gifts = query
|
var gifts = query
|
||||||
@@ -49,9 +50,9 @@ public class SubscriptionGiftController(
|
|||||||
[FromQuery] int take = 20
|
[FromQuery] int take = 20
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
var gifts = await subscriptions.GetGiftsByRecipientAsync(currentUser.Id);
|
var gifts = await subscriptions.GetGiftsByRecipientAsync(Guid.Parse(currentUser.Id));
|
||||||
var totalCount = gifts.Count;
|
var totalCount = gifts.Count;
|
||||||
|
|
||||||
gifts = gifts
|
gifts = gifts
|
||||||
@@ -71,8 +72,9 @@ public class SubscriptionGiftController(
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<SnWalletGift>> GetGift(Guid giftId)
|
public async Task<ActionResult<SnWalletGift>> GetGift(Guid giftId)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
|
var currentUserId = Guid.Parse(currentUser.Id);
|
||||||
var gift = await db.WalletGifts
|
var gift = await db.WalletGifts
|
||||||
.Include(g => g.Gifter).ThenInclude(a => a!.Profile)
|
.Include(g => g.Gifter).ThenInclude(a => a!.Profile)
|
||||||
.Include(g => g.Recipient).ThenInclude(a => a!.Profile)
|
.Include(g => g.Recipient).ThenInclude(a => a!.Profile)
|
||||||
@@ -82,8 +84,8 @@ public class SubscriptionGiftController(
|
|||||||
.FirstOrDefaultAsync(g => g.Id == giftId);
|
.FirstOrDefaultAsync(g => g.Id == giftId);
|
||||||
|
|
||||||
if (gift is null) return NotFound();
|
if (gift is null) return NotFound();
|
||||||
if (gift.GifterId != currentUser.Id && gift.RecipientId != currentUser.Id &&
|
if (gift.GifterId != currentUserId && gift.RecipientId != currentUserId &&
|
||||||
!(gift.IsOpenGift && gift.RedeemerId == currentUser.Id))
|
!(gift.IsOpenGift && gift.RedeemerId == currentUserId))
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
return gift;
|
return gift;
|
||||||
@@ -96,7 +98,7 @@ public class SubscriptionGiftController(
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<GiftCheckResponse>> CheckGiftCode(string giftCode)
|
public async Task<ActionResult<GiftCheckResponse>> CheckGiftCode(string giftCode)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
var gift = await subscriptions.GetGiftByCodeAsync(giftCode);
|
var gift = await subscriptions.GetGiftByCodeAsync(giftCode);
|
||||||
if (gift is null) return NotFound("Gift code not found.");
|
if (gift is null) return NotFound("Gift code not found.");
|
||||||
@@ -119,7 +121,7 @@ public class SubscriptionGiftController(
|
|||||||
{
|
{
|
||||||
error = "Gift has expired.";
|
error = "Gift has expired.";
|
||||||
}
|
}
|
||||||
else if (!gift.IsOpenGift && gift.RecipientId != currentUser.Id)
|
else if (!gift.IsOpenGift && gift.RecipientId != Guid.Parse(currentUser.Id))
|
||||||
{
|
{
|
||||||
error = "This gift is intended for someone else.";
|
error = "This gift is intended for someone else.";
|
||||||
}
|
}
|
||||||
@@ -141,7 +143,7 @@ public class SubscriptionGiftController(
|
|||||||
: [gift.SubscriptionIdentifier];
|
: [gift.SubscriptionIdentifier];
|
||||||
|
|
||||||
var existingSubscription =
|
var existingSubscription =
|
||||||
await subscriptions.GetSubscriptionAsync(currentUser.Id, subscriptionsInGroup);
|
await subscriptions.GetSubscriptionAsync(Guid.Parse(currentUser.Id), subscriptionsInGroup);
|
||||||
if (existingSubscription is not null)
|
if (existingSubscription is not null)
|
||||||
{
|
{
|
||||||
error = "You already have an active subscription of this type.";
|
error = "You already have an active subscription of this type.";
|
||||||
@@ -193,7 +195,7 @@ public class SubscriptionGiftController(
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<SnWalletGift>> PurchaseGift([FromBody] PurchaseGiftRequest request)
|
public async Task<ActionResult<SnWalletGift>> PurchaseGift([FromBody] PurchaseGiftRequest request)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
if (currentUser.Profile.Level < MinimumAccountLevel)
|
if (currentUser.Profile.Level < MinimumAccountLevel)
|
||||||
{
|
{
|
||||||
@@ -247,7 +249,7 @@ public class SubscriptionGiftController(
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<RedeemGiftResponse>> RedeemGift([FromBody] RedeemGiftRequest request)
|
public async Task<ActionResult<RedeemGiftResponse>> RedeemGift([FromBody] RedeemGiftRequest request)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -278,11 +280,11 @@ public class SubscriptionGiftController(
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<SnWalletGift>> SendGift(Guid giftId)
|
public async Task<ActionResult<SnWalletGift>> SendGift(Guid giftId)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var gift = await subscriptions.MarkGiftAsSentAsync(giftId, currentUser.Id);
|
var gift = await subscriptions.MarkGiftAsSentAsync(giftId, Guid.Parse(currentUser.Id));
|
||||||
return gift;
|
return gift;
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException ex)
|
catch (InvalidOperationException ex)
|
||||||
@@ -298,11 +300,11 @@ public class SubscriptionGiftController(
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<SnWalletGift>> CancelGift(Guid giftId)
|
public async Task<ActionResult<SnWalletGift>> CancelGift(Guid giftId)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var gift = await subscriptions.CancelGiftAsync(giftId, currentUser.Id);
|
var gift = await subscriptions.CancelGiftAsync(giftId, Guid.Parse(currentUser.Id));
|
||||||
return gift;
|
return gift;
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException ex)
|
catch (InvalidOperationException ex)
|
||||||
@@ -318,11 +320,11 @@ public class SubscriptionGiftController(
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<SnWalletOrder>> CreateGiftOrder(Guid giftId)
|
public async Task<ActionResult<SnWalletOrder>> CreateGiftOrder(Guid giftId)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var order = await subscriptions.CreateGiftOrder(currentUser.Id, giftId);
|
var order = await subscriptions.CreateGiftOrder(Guid.Parse(currentUser.Id), giftId);
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException ex)
|
catch (InvalidOperationException ex)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public class SubscriptionService(
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
public async Task<SnWalletSubscription> CreateSubscriptionAsync(
|
public async Task<SnWalletSubscription> CreateSubscriptionAsync(
|
||||||
SnAccount account,
|
Account account,
|
||||||
string identifier,
|
string identifier,
|
||||||
string paymentMethod,
|
string paymentMethod,
|
||||||
SnPaymentDetails paymentDetails,
|
SnPaymentDetails paymentDetails,
|
||||||
@@ -53,7 +53,8 @@ public class SubscriptionService(
|
|||||||
|
|
||||||
cycleDuration ??= Duration.FromDays(30);
|
cycleDuration ??= Duration.FromDays(30);
|
||||||
|
|
||||||
var existingSubscription = await GetSubscriptionAsync(account.Id, subscriptionsInGroup);
|
var accountId = Guid.Parse(account.Id);
|
||||||
|
var existingSubscription = await GetSubscriptionAsync(accountId, subscriptionsInGroup);
|
||||||
if (existingSubscription is not null && !noop)
|
if (existingSubscription is not null && !noop)
|
||||||
throw new InvalidOperationException($"Active subscription with identifier {identifier} already exists.");
|
throw new InvalidOperationException($"Active subscription with identifier {identifier} already exists.");
|
||||||
if (existingSubscription is not null)
|
if (existingSubscription is not null)
|
||||||
@@ -61,7 +62,7 @@ public class SubscriptionService(
|
|||||||
|
|
||||||
// Batch database queries for coupon and free trial check
|
// Batch database queries for coupon and free trial check
|
||||||
var prevFreeTrialTask = isFreeTrial
|
var prevFreeTrialTask = isFreeTrial
|
||||||
? db.WalletSubscriptions.FirstOrDefaultAsync(s => s.AccountId == account.Id && s.Identifier == identifier && s.IsFreeTrial)
|
? db.WalletSubscriptions.FirstOrDefaultAsync(s => s.AccountId == accountId && s.Identifier == identifier && s.IsFreeTrial)
|
||||||
: Task.FromResult((SnWalletSubscription?)null);
|
: Task.FromResult((SnWalletSubscription?)null);
|
||||||
|
|
||||||
Guid couponGuidId = Guid.TryParse(coupon ?? "", out var parsedId) ? parsedId : Guid.Empty;
|
Guid couponGuidId = Guid.TryParse(coupon ?? "", out var parsedId) ? parsedId : Guid.Empty;
|
||||||
@@ -96,7 +97,7 @@ public class SubscriptionService(
|
|||||||
CouponId = couponData?.Id,
|
CouponId = couponData?.Id,
|
||||||
Coupon = couponData,
|
Coupon = couponData,
|
||||||
RenewalAt = (isFreeTrial || !isAutoRenewal) ? null : now.Plus(cycleDuration.Value),
|
RenewalAt = (isFreeTrial || !isAutoRenewal) ? null : now.Plus(cycleDuration.Value),
|
||||||
AccountId = account.Id,
|
AccountId = accountId,
|
||||||
};
|
};
|
||||||
|
|
||||||
db.WalletSubscriptions.Add(subscription);
|
db.WalletSubscriptions.Add(subscription);
|
||||||
@@ -572,7 +573,7 @@ public class SubscriptionService(
|
|||||||
/// <param name="cycleDuration">The duration of the subscription once redeemed (default 30 days).</param>
|
/// <param name="cycleDuration">The duration of the subscription once redeemed (default 30 days).</param>
|
||||||
/// <returns>The created gift record.</returns>
|
/// <returns>The created gift record.</returns>
|
||||||
public async Task<SnWalletGift> PurchaseGiftAsync(
|
public async Task<SnWalletGift> PurchaseGiftAsync(
|
||||||
SnAccount gifter,
|
Account gifter,
|
||||||
Guid? recipientId,
|
Guid? recipientId,
|
||||||
string subscriptionIdentifier,
|
string subscriptionIdentifier,
|
||||||
string paymentMethod,
|
string paymentMethod,
|
||||||
@@ -592,12 +593,12 @@ public class SubscriptionService(
|
|||||||
$@"Subscription {subscriptionIdentifier} was not found.");
|
$@"Subscription {subscriptionIdentifier} was not found.");
|
||||||
|
|
||||||
// Check if recipient account exists (if specified)
|
// Check if recipient account exists (if specified)
|
||||||
SnAccount? recipient = null;
|
Account? recipient = null;
|
||||||
if (recipientId.HasValue)
|
if (recipientId.HasValue)
|
||||||
{
|
{
|
||||||
var accountProto = await accounts.GetAccountAsync(new GetAccountRequest { Id = recipientId.Value.ToString() });
|
var accountProto = await accounts.GetAccountAsync(new GetAccountRequest { Id = recipientId.Value.ToString() });
|
||||||
if (accountProto != null)
|
if (accountProto != null)
|
||||||
recipient = SnAccount.FromProtoValue(accountProto);
|
recipient = accountProto;
|
||||||
if (recipient is null)
|
if (recipient is null)
|
||||||
throw new ArgumentOutOfRangeException(nameof(recipientId), "Recipient account not found.");
|
throw new ArgumentOutOfRangeException(nameof(recipientId), "Recipient account not found.");
|
||||||
}
|
}
|
||||||
@@ -634,7 +635,7 @@ public class SubscriptionService(
|
|||||||
|
|
||||||
var gift = new SnWalletGift
|
var gift = new SnWalletGift
|
||||||
{
|
{
|
||||||
GifterId = gifter.Id,
|
GifterId = Guid.Parse(gifter.Id),
|
||||||
RecipientId = recipientId,
|
RecipientId = recipientId,
|
||||||
GiftCode = giftCode,
|
GiftCode = giftCode,
|
||||||
Message = message,
|
Message = message,
|
||||||
@@ -654,8 +655,6 @@ public class SubscriptionService(
|
|||||||
db.WalletGifts.Add(gift);
|
db.WalletGifts.Add(gift);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
gift.Gifter = gifter;
|
|
||||||
|
|
||||||
return gift;
|
return gift;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -666,10 +665,11 @@ public class SubscriptionService(
|
|||||||
/// <param name="giftCode">The unique redemption code.</param>
|
/// <param name="giftCode">The unique redemption code.</param>
|
||||||
/// <returns>A tuple containing the activated gift and the created subscription.</returns>
|
/// <returns>A tuple containing the activated gift and the created subscription.</returns>
|
||||||
public async Task<(SnWalletGift Gift, SnWalletSubscription Subscription)> RedeemGiftAsync(
|
public async Task<(SnWalletGift Gift, SnWalletSubscription Subscription)> RedeemGiftAsync(
|
||||||
SnAccount redeemer,
|
Account redeemer,
|
||||||
string giftCode)
|
string giftCode)
|
||||||
{
|
{
|
||||||
var now = SystemClock.Instance.GetCurrentInstant();
|
var now = SystemClock.Instance.GetCurrentInstant();
|
||||||
|
var redeemerId = Guid.Parse(redeemer.Id);
|
||||||
|
|
||||||
// Find and validate the gift
|
// Find and validate the gift
|
||||||
var gift = await db.WalletGifts
|
var gift = await db.WalletGifts
|
||||||
@@ -685,11 +685,11 @@ public class SubscriptionService(
|
|||||||
if (now > gift.ExpiresAt)
|
if (now > gift.ExpiresAt)
|
||||||
throw new InvalidOperationException("Gift has expired.");
|
throw new InvalidOperationException("Gift has expired.");
|
||||||
|
|
||||||
if (gift.GifterId == redeemer.Id)
|
if (gift.GifterId == redeemerId)
|
||||||
throw new InvalidOperationException("You cannot redeem your own gift.");
|
throw new InvalidOperationException("You cannot redeem your own gift.");
|
||||||
|
|
||||||
// Validate redeemer permissions
|
// Validate redeemer permissions
|
||||||
if (!gift.IsOpenGift && gift.RecipientId != redeemer.Id)
|
if (!gift.IsOpenGift && gift.RecipientId != redeemerId)
|
||||||
throw new InvalidOperationException("This gift is not intended for you.");
|
throw new InvalidOperationException("This gift is not intended for you.");
|
||||||
|
|
||||||
// Check if redeemer already has this subscription type
|
// Check if redeemer already has this subscription type
|
||||||
@@ -700,7 +700,7 @@ public class SubscriptionService(
|
|||||||
if (subscriptionInfo is null)
|
if (subscriptionInfo is null)
|
||||||
throw new InvalidOperationException("Invalid gift subscription type.");
|
throw new InvalidOperationException("Invalid gift subscription type.");
|
||||||
|
|
||||||
var sameTypeSubscription = await GetSubscriptionAsync(redeemer.Id, gift.SubscriptionIdentifier);
|
var sameTypeSubscription = await GetSubscriptionAsync(redeemerId, gift.SubscriptionIdentifier);
|
||||||
if (sameTypeSubscription is not null)
|
if (sameTypeSubscription is not null)
|
||||||
{
|
{
|
||||||
// Extend existing subscription
|
// Extend existing subscription
|
||||||
@@ -722,7 +722,7 @@ public class SubscriptionService(
|
|||||||
// Update gift status and link
|
// Update gift status and link
|
||||||
gift.Status = Shared.Models.GiftStatus.Redeemed;
|
gift.Status = Shared.Models.GiftStatus.Redeemed;
|
||||||
gift.RedeemedAt = now;
|
gift.RedeemedAt = now;
|
||||||
gift.RedeemerId = redeemer.Id;
|
gift.RedeemerId = redeemerId;
|
||||||
gift.SubscriptionId = sameTypeSubscription.Id;
|
gift.SubscriptionId = sameTypeSubscription.Id;
|
||||||
gift.UpdatedAt = now;
|
gift.UpdatedAt = now;
|
||||||
|
|
||||||
@@ -740,7 +740,7 @@ public class SubscriptionService(
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gift.GifterId == redeemer.Id) return (gift, sameTypeSubscription);
|
if (gift.GifterId == redeemerId) return (gift, sameTypeSubscription);
|
||||||
await NotifyGiftClaimedByRecipient(gift, sameTypeSubscription, gift.GifterId, redeemer);
|
await NotifyGiftClaimedByRecipient(gift, sameTypeSubscription, gift.GifterId, redeemer);
|
||||||
|
|
||||||
return (gift, sameTypeSubscription);
|
return (gift, sameTypeSubscription);
|
||||||
@@ -753,7 +753,7 @@ public class SubscriptionService(
|
|||||||
.ToArray()
|
.ToArray()
|
||||||
: [gift.SubscriptionIdentifier];
|
: [gift.SubscriptionIdentifier];
|
||||||
|
|
||||||
var existingSubscription = await GetSubscriptionAsync(redeemer.Id, subscriptionsInGroup);
|
var existingSubscription = await GetSubscriptionAsync(redeemerId, subscriptionsInGroup);
|
||||||
if (existingSubscription is not null)
|
if (existingSubscription is not null)
|
||||||
throw new InvalidOperationException("You already have an active subscription of this type.");
|
throw new InvalidOperationException("You already have an active subscription of this type.");
|
||||||
|
|
||||||
@@ -779,13 +779,13 @@ public class SubscriptionService(
|
|||||||
CouponId = gift.CouponId,
|
CouponId = gift.CouponId,
|
||||||
Coupon = gift.Coupon,
|
Coupon = gift.Coupon,
|
||||||
RenewalAt = now.Plus(cycleDuration),
|
RenewalAt = now.Plus(cycleDuration),
|
||||||
AccountId = redeemer.Id,
|
AccountId = redeemerId,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update the gift status
|
// Update the gift status
|
||||||
gift.Status = DysonNetwork.Shared.Models.GiftStatus.Redeemed;
|
gift.Status = DysonNetwork.Shared.Models.GiftStatus.Redeemed;
|
||||||
gift.RedeemedAt = now;
|
gift.RedeemedAt = now;
|
||||||
gift.RedeemerId = redeemer.Id;
|
gift.RedeemerId = redeemerId;
|
||||||
gift.Subscription = subscription;
|
gift.Subscription = subscription;
|
||||||
gift.UpdatedAt = now;
|
gift.UpdatedAt = now;
|
||||||
|
|
||||||
@@ -806,7 +806,7 @@ public class SubscriptionService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send notification to gifter if different from redeemer
|
// Send notification to gifter if different from redeemer
|
||||||
if (gift.GifterId == redeemer.Id) return (gift, subscription);
|
if (gift.GifterId == redeemerId) return (gift, subscription);
|
||||||
await NotifyGiftClaimedByRecipient(gift, subscription, gift.GifterId, redeemer);
|
await NotifyGiftClaimedByRecipient(gift, subscription, gift.GifterId, redeemer);
|
||||||
|
|
||||||
return (gift, subscription);
|
return (gift, subscription);
|
||||||
@@ -910,7 +910,7 @@ public class SubscriptionService(
|
|||||||
return new string(result);
|
return new string(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task NotifyGiftClaimedByRecipient(SnWalletGift gift, SnWalletSubscription subscription, Guid gifterId, SnAccount redeemer)
|
private async Task NotifyGiftClaimedByRecipient(SnWalletGift gift, SnWalletSubscription subscription, Guid gifterId, Account redeemer)
|
||||||
{
|
{
|
||||||
var humanReadableName =
|
var humanReadableName =
|
||||||
SubscriptionTypeData.SubscriptionHumanReadable.TryGetValue(subscription.Identifier, out var humanReadable)
|
SubscriptionTypeData.SubscriptionHumanReadable.TryGetValue(subscription.Identifier, out var humanReadable)
|
||||||
@@ -926,7 +926,7 @@ public class SubscriptionService(
|
|||||||
{
|
{
|
||||||
["gift_id"] = gift.Id.ToString(),
|
["gift_id"] = gift.Id.ToString(),
|
||||||
["subscription_id"] = subscription.Id.ToString(),
|
["subscription_id"] = subscription.Id.ToString(),
|
||||||
["redeemer_id"] = redeemer.Id.ToString()
|
["redeemer_id"] = redeemer.Id
|
||||||
}),
|
}),
|
||||||
IsSavable = true
|
IsSavable = true
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
using DysonNetwork.Shared.Auth;
|
using DysonNetwork.Shared.Auth;
|
||||||
using DysonNetwork.Shared.Cache;
|
using DysonNetwork.Shared.Cache;
|
||||||
using DysonNetwork.Shared.Models;
|
using DysonNetwork.Shared.Models;
|
||||||
|
using DysonNetwork.Shared.Proto;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@@ -23,11 +24,11 @@ public class WalletController(
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<SnWallet>> CreateWallet()
|
public async Task<ActionResult<SnWallet>> CreateWallet()
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var wallet = await ws.CreateWalletAsync(currentUser.Id);
|
var wallet = await ws.CreateWalletAsync(Guid.Parse(currentUser.Id));
|
||||||
return Ok(wallet);
|
return Ok(wallet);
|
||||||
}
|
}
|
||||||
catch (Exception err)
|
catch (Exception err)
|
||||||
@@ -40,9 +41,9 @@ public class WalletController(
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<SnWallet>> GetWallet()
|
public async Task<ActionResult<SnWallet>> GetWallet()
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
var wallet = await ws.GetWalletAsync(currentUser.Id);
|
var wallet = await ws.GetWalletAsync(Guid.Parse(currentUser.Id));
|
||||||
if (wallet is null) return NotFound("Wallet was not found, please create one first.");
|
if (wallet is null) return NotFound("Wallet was not found, please create one first.");
|
||||||
return Ok(wallet);
|
return Ok(wallet);
|
||||||
}
|
}
|
||||||
@@ -64,9 +65,9 @@ public class WalletController(
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<WalletStats>> GetWalletStats([FromQuery] int period = 30)
|
public async Task<ActionResult<WalletStats>> GetWalletStats([FromQuery] int period = 30)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
var wallet = await ws.GetWalletAsync(currentUser.Id);
|
var wallet = await ws.GetWalletAsync(Guid.Parse(currentUser.Id));
|
||||||
if (wallet is null) return NotFound("Wallet was not found, please create one first.");
|
if (wallet is null) return NotFound("Wallet was not found, please create one first.");
|
||||||
|
|
||||||
var periodEnd = SystemClock.Instance.GetCurrentInstant();
|
var periodEnd = SystemClock.Instance.GetCurrentInstant();
|
||||||
@@ -119,9 +120,9 @@ public class WalletController(
|
|||||||
[FromQuery] int offset = 0, [FromQuery] int take = 20
|
[FromQuery] int offset = 0, [FromQuery] int take = 20
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
var accountWallet = await db.Wallets.Where(w => w.AccountId == currentUser.Id).FirstOrDefaultAsync();
|
var accountWallet = await db.Wallets.Where(w => w.AccountId == Guid.Parse(currentUser.Id)).FirstOrDefaultAsync();
|
||||||
if (accountWallet is null) return NotFound();
|
if (accountWallet is null) return NotFound();
|
||||||
|
|
||||||
var query = db.PaymentTransactions
|
var query = db.PaymentTransactions
|
||||||
@@ -150,9 +151,9 @@ public class WalletController(
|
|||||||
[FromQuery] int offset = 0, [FromQuery] int take = 20
|
[FromQuery] int offset = 0, [FromQuery] int take = 20
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
var accountWallet = await db.Wallets.Where(w => w.AccountId == currentUser.Id).FirstOrDefaultAsync();
|
var accountWallet = await db.Wallets.Where(w => w.AccountId == Guid.Parse(currentUser.Id)).FirstOrDefaultAsync();
|
||||||
if (accountWallet is null) return NotFound();
|
if (accountWallet is null) return NotFound();
|
||||||
|
|
||||||
var query = db.PaymentOrders.AsQueryable()
|
var query = db.PaymentOrders.AsQueryable()
|
||||||
@@ -221,14 +222,14 @@ public class WalletController(
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<SnWalletTransaction>> Transfer([FromBody] WalletTransferRequest request)
|
public async Task<ActionResult<SnWalletTransaction>> Transfer([FromBody] WalletTransferRequest request)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
if (currentUser.Id == request.PayeeAccountId) return BadRequest("Cannot transfer to yourself.");
|
if (Guid.Parse(currentUser.Id) == request.PayeeAccountId) return BadRequest("Cannot transfer to yourself.");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var transaction = await payment.TransferAsync(
|
var transaction = await payment.TransferAsync(
|
||||||
payerAccountId: currentUser.Id,
|
payerAccountId: Guid.Parse(currentUser.Id),
|
||||||
payeeAccountId: request.PayeeAccountId,
|
payeeAccountId: request.PayeeAccountId,
|
||||||
currency: request.Currency,
|
currency: request.Currency,
|
||||||
amount: request.Amount
|
amount: request.Amount
|
||||||
@@ -248,7 +249,7 @@ public class WalletController(
|
|||||||
[Required] public string Currency { get; set; } = null!;
|
[Required] public string Currency { get; set; } = null!;
|
||||||
[Required] public decimal TotalAmount { get; set; }
|
[Required] public decimal TotalAmount { get; set; }
|
||||||
[Required] public int AmountOfSplits { get; set; }
|
[Required] public int AmountOfSplits { get; set; }
|
||||||
[Required] public FundSplitType SplitType { get; set; }
|
[Required] public Shared.Models.FundSplitType SplitType { get; set; }
|
||||||
public string? Message { get; set; }
|
public string? Message { get; set; }
|
||||||
public int? ExpirationHours { get; set; } // Optional: hours until expiration
|
public int? ExpirationHours { get; set; } // Optional: hours until expiration
|
||||||
}
|
}
|
||||||
@@ -257,7 +258,7 @@ public class WalletController(
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<SnWalletFund>> CreateFund([FromBody] CreateFundRequest request)
|
public async Task<ActionResult<SnWalletFund>> CreateFund([FromBody] CreateFundRequest request)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -268,7 +269,7 @@ public class WalletController(
|
|||||||
}
|
}
|
||||||
|
|
||||||
var fund = await payment.CreateFundAsync(
|
var fund = await payment.CreateFundAsync(
|
||||||
creatorAccountId: currentUser.Id,
|
creatorAccountId: Guid.Parse(currentUser.Id),
|
||||||
recipientAccountIds: request.RecipientAccountIds,
|
recipientAccountIds: request.RecipientAccountIds,
|
||||||
currency: request.Currency,
|
currency: request.Currency,
|
||||||
totalAmount: request.TotalAmount,
|
totalAmount: request.TotalAmount,
|
||||||
@@ -291,17 +292,18 @@ public class WalletController(
|
|||||||
public async Task<ActionResult<List<SnWalletFund>>> GetFunds(
|
public async Task<ActionResult<List<SnWalletFund>>> GetFunds(
|
||||||
[FromQuery] int offset = 0,
|
[FromQuery] int offset = 0,
|
||||||
[FromQuery] int take = 20,
|
[FromQuery] int take = 20,
|
||||||
[FromQuery] FundStatus? status = null
|
[FromQuery] Shared.Models.FundStatus? status = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
|
var currentUserId = Guid.Parse(currentUser.Id);
|
||||||
var query = db.WalletFunds
|
var query = db.WalletFunds
|
||||||
.Include(f => f.Recipients)
|
.Include(f => f.Recipients)
|
||||||
.ThenInclude(r => r.RecipientAccount)
|
.ThenInclude(r => r.RecipientAccount)
|
||||||
.Include(f => f.CreatorAccount)
|
.Include(f => f.CreatorAccount)
|
||||||
.Where(f => f.CreatorAccountId == currentUser.Id ||
|
.Where(f => f.CreatorAccountId == currentUserId ||
|
||||||
f.Recipients.Any(r => r.RecipientAccountId == currentUser.Id))
|
f.Recipients.Any(r => r.RecipientAccountId == currentUserId))
|
||||||
.AsQueryable();
|
.AsQueryable();
|
||||||
|
|
||||||
if (status.HasValue)
|
if (status.HasValue)
|
||||||
@@ -340,12 +342,12 @@ public class WalletController(
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<SnWalletTransaction>> ReceiveFund(Guid id)
|
public async Task<ActionResult<SnWalletTransaction>> ReceiveFund(Guid id)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var walletTransaction = await payment.ReceiveFundAsync(
|
var walletTransaction = await payment.ReceiveFundAsync(
|
||||||
recipientAccountId: currentUser.Id,
|
recipientAccountId: Guid.Parse(currentUser.Id),
|
||||||
fundId: id
|
fundId: id
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -365,12 +367,12 @@ public class WalletController(
|
|||||||
[FromQuery] DateTime? endDate = null
|
[FromQuery] DateTime? endDate = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var overview = await payment.GetWalletOverviewAsync(
|
var overview = await payment.GetWalletOverviewAsync(
|
||||||
accountId: currentUser.Id,
|
accountId: Guid.Parse(currentUser.Id),
|
||||||
startDate: startDate,
|
startDate: startDate,
|
||||||
endDate: endDate
|
endDate: endDate
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user