🐛 Fix wallet service authorization check

This commit is contained in:
2026-02-04 01:52:43 +08:00
parent 69f21d5b02
commit 0bc4ea68e1
6 changed files with 82 additions and 79 deletions

View File

@@ -1,5 +1,3 @@
using DysonNetwork.Shared.Models;
namespace DysonNetwork.Messager.Wallet; namespace DysonNetwork.Messager.Wallet;
public class FundEmbed public class FundEmbed

View File

@@ -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.");

View File

@@ -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)

View File

@@ -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)

View File

@@ -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
}; };

View File

@@ -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
); );