♻️ Finish centerlizing the data models

This commit is contained in:
2025-09-27 15:14:05 +08:00
parent e70d8371f8
commit 9ce31c4dd8
167 changed files with 780 additions and 42880 deletions

View File

@@ -25,7 +25,7 @@ public class OrderController(PaymentService payment, AuthService auth, AppDataba
[Authorize]
public async Task<ActionResult<SnWalletOrder>> PayOrder(Guid id, [FromBody] PayOrderRequest request)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
// Validate PIN code
if (!await auth.ValidatePinCode(currentUser.Id, request.PinCode))

View File

@@ -2,7 +2,6 @@ using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.EntityFrameworkCore;
using NodaTime;
namespace DysonNetwork.Pass.Wallet.PaymentHandlers;

View File

@@ -1,14 +1,11 @@
using System.Globalization;
using System.Text.Json;
using DysonNetwork.Pass.Localization;
using DysonNetwork.Shared.Models;
using DysonNetwork.Shared.Proto;
using DysonNetwork.Shared.Stream;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.Localization;
using NATS.Client.Core;
using NATS.Client.JetStream;
using NATS.Net;
using NodaTime;
using AccountService = DysonNetwork.Pass.Account.AccountService;
@@ -23,7 +20,7 @@ public class PaymentService(
INatsConnection nats
)
{
public async Task<Order> CreateOrderAsync(
public async Task<SnWalletOrder> CreateOrderAsync(
Guid? payeeWalletId,
string currency,
decimal amount,
@@ -36,11 +33,11 @@ public class PaymentService(
)
{
// Check if there's an existing unpaid order that can be reused
var now = SystemClock.Instance.GetCurrentInstant();
if (reuseable && appIdentifier != null)
{
var now = SystemClock.Instance.GetCurrentInstant();
var existingOrder = await db.PaymentOrders
.Where(o => o.Status == OrderStatus.Unpaid &&
.Where(o => o.Status == Shared.Models.OrderStatus.Unpaid &&
o.PayeeWalletId == payeeWalletId &&
o.Currency == currency &&
o.Amount == amount &&
@@ -60,13 +57,13 @@ public class PaymentService(
}
}
// Create a new order if no reusable order was found
var order = new Order
// Create a new SnWalletOrder if no reusable order was found
var order = new SnWalletOrder
{
PayeeWalletId = payeeWalletId,
Currency = currency,
Amount = amount,
ExpiredAt = SystemClock.Instance.GetCurrentInstant().Plus(expiration ?? Duration.FromHours(24)),
ExpiredAt = now.Plus(expiration ?? Duration.FromHours(24)),
AppIdentifier = appIdentifier,
ProductIdentifier = productIdentifier,
Remarks = remarks,
@@ -78,16 +75,16 @@ public class PaymentService(
return order;
}
public async Task<Transaction> CreateTransactionWithAccountAsync(
public async Task<SnWalletTransaction> CreateTransactionWithAccountAsync(
Guid? payerAccountId,
Guid? payeeAccountId,
string currency,
decimal amount,
string? remarks = null,
TransactionType type = TransactionType.System
Shared.Models.TransactionType type = Shared.Models.TransactionType.System
)
{
Wallet? payer = null, payee = null;
SnWallet? payer = null, payee = null;
if (payerAccountId.HasValue)
payer = await db.Wallets.FirstOrDefaultAsync(e => e.AccountId == payerAccountId.Value);
if (payeeAccountId.HasValue)
@@ -108,13 +105,13 @@ public class PaymentService(
);
}
public async Task<Transaction> CreateTransactionAsync(
public async Task<SnWalletTransaction> CreateTransactionAsync(
Guid? payerWalletId,
Guid? payeeWalletId,
string currency,
decimal amount,
string? remarks = null,
TransactionType type = TransactionType.System,
Shared.Models.TransactionType type = Shared.Models.TransactionType.System,
bool silent = false
)
{
@@ -122,7 +119,7 @@ public class PaymentService(
throw new ArgumentException("At least one wallet must be specified.");
if (amount <= 0) throw new ArgumentException("Cannot create transaction with negative or zero amount.");
var transaction = new Transaction
var transaction = new SnWalletTransaction
{
PayerWalletId = payerWalletId,
PayeeWalletId = payeeWalletId,
@@ -132,7 +129,7 @@ public class PaymentService(
Type = type
};
Wallet? payerWallet = null, payeeWallet = null;
SnWallet? payerWallet = null, payeeWallet = null;
if (payerWalletId.HasValue)
{
@@ -173,7 +170,7 @@ public class PaymentService(
return transaction;
}
private async Task NotifyNewTransaction(Transaction transaction, Wallet? payerWallet, Wallet? payeeWallet)
private async Task NotifyNewTransaction(SnWalletTransaction transaction, SnWallet? payerWallet, SnWallet? payeeWallet)
{
if (payerWallet is not null)
{
@@ -244,21 +241,15 @@ public class PaymentService(
}
}
public async Task<Order> PayOrderAsync(Guid orderId, Wallet payerWallet)
public async Task<SnWalletOrder> PayOrderAsync(Guid orderId, SnWallet payerWallet)
{
var order = await db.PaymentOrders
.Include(o => o.Transaction)
.Include(o => o.PayeeWallet)
.FirstOrDefaultAsync(o => o.Id == orderId);
if (order == null)
{
throw new InvalidOperationException("Order not found");
}
.FirstOrDefaultAsync(o => o.Id == orderId) ?? throw new InvalidOperationException("Order not found");
var js = nats.CreateJetStreamContext();
if (order.Status == OrderStatus.Paid)
if (order.Status == Shared.Models.OrderStatus.Paid)
{
await js.PublishAsync(
PaymentOrderEventBase.Type,
@@ -277,14 +268,14 @@ public class PaymentService(
return order;
}
if (order.Status != OrderStatus.Unpaid)
if (order.Status != Shared.Models.OrderStatus.Unpaid)
{
throw new InvalidOperationException($"Order is in invalid status: {order.Status}");
}
if (order.ExpiredAt < SystemClock.Instance.GetCurrentInstant())
{
order.Status = OrderStatus.Expired;
order.Status = Shared.Models.OrderStatus.Expired;
await db.SaveChangesAsync();
throw new InvalidOperationException("Order has expired");
}
@@ -295,12 +286,12 @@ public class PaymentService(
order.Currency,
order.Amount,
order.Remarks ?? $"Payment for Order #{order.Id}",
type: TransactionType.Order,
type: Shared.Models.TransactionType.Order,
silent: true);
order.TransactionId = transaction.Id;
order.Transaction = transaction;
order.Status = OrderStatus.Paid;
order.Status = Shared.Models.OrderStatus.Paid;
await db.SaveChangesAsync();
@@ -323,7 +314,7 @@ public class PaymentService(
return order;
}
private async Task NotifyOrderPaid(Order order, Wallet? payerWallet, Wallet? payeeWallet)
private async Task NotifyOrderPaid(SnWalletOrder order, SnWallet? payerWallet, SnWallet? payeeWallet)
{
if (payerWallet is not null)
{
@@ -387,7 +378,7 @@ public class PaymentService(
}
}
public async Task<Order> CancelOrderAsync(Guid orderId)
public async Task<SnWalletOrder> CancelOrderAsync(Guid orderId)
{
var order = await db.PaymentOrders.FindAsync(orderId);
if (order == null)
@@ -395,28 +386,22 @@ public class PaymentService(
throw new InvalidOperationException("Order not found");
}
if (order.Status != OrderStatus.Unpaid)
if (order.Status != Shared.Models.OrderStatus.Unpaid)
{
throw new InvalidOperationException($"Cannot cancel order in status: {order.Status}");
}
order.Status = OrderStatus.Cancelled;
order.Status = Shared.Models.OrderStatus.Cancelled;
await db.SaveChangesAsync();
return order;
}
public async Task<(Order Order, Transaction RefundTransaction)> RefundOrderAsync(Guid orderId)
public async Task<(SnWalletOrder Order, SnWalletTransaction RefundTransaction)> RefundOrderAsync(Guid orderId)
{
var order = await db.PaymentOrders
.Include(o => o.Transaction)
.FirstOrDefaultAsync(o => o.Id == orderId);
if (order == null)
{
throw new InvalidOperationException("Order not found");
}
if (order.Status != OrderStatus.Paid)
.FirstOrDefaultAsync(o => o.Id == orderId) ?? throw new InvalidOperationException("Order not found");
if (order.Status != Shared.Models.OrderStatus.Paid)
{
throw new InvalidOperationException($"Cannot refund order in status: {order.Status}");
}
@@ -433,13 +418,13 @@ public class PaymentService(
order.Amount,
$"Refund for order {order.Id}");
order.Status = OrderStatus.Finished;
order.Status = Shared.Models.OrderStatus.Finished;
await db.SaveChangesAsync();
return (order, refundTransaction);
}
public async Task<Transaction> TransferAsync(Guid payerAccountId, Guid payeeAccountId, string currency,
public async Task<SnWalletTransaction> TransferAsync(Guid payerAccountId, Guid payeeAccountId, string currency,
decimal amount)
{
var payerWallet = await wat.GetWalletAsync(payerAccountId);
@@ -460,6 +445,6 @@ public class PaymentService(
currency,
amount,
$"Transfer from account {payerAccountId} to {payeeAccountId}",
TransactionType.Transfer);
Shared.Models.TransactionType.Transfer);
}
}

View File

@@ -14,7 +14,7 @@ public class PaymentServiceGrpc(PaymentService paymentService) : Shared.Proto.Pa
request.Currency,
decimal.Parse(request.Amount),
request.Expiration is not null ? Duration.FromSeconds(request.Expiration.Seconds) : null,
request.HasAppIdentifier ? request.AppIdentifier : Order.InternalAppIdentifier,
request.HasAppIdentifier ? request.AppIdentifier : SnWalletOrder.InternalAppIdentifier,
request.HasProductIdentifier ? request.ProductIdentifier : null,
request.HasRemarks ? request.Remarks : null,
request.HasMeta
@@ -34,7 +34,7 @@ public class PaymentServiceGrpc(PaymentService paymentService) : Shared.Proto.Pa
request.Currency,
decimal.Parse(request.Amount),
request.HasRemarks ? request.Remarks : null,
(TransactionType)request.Type
(Shared.Models.TransactionType)request.Type
);
return transaction.ToProtoValue();
}
@@ -48,7 +48,7 @@ public class PaymentServiceGrpc(PaymentService paymentService) : Shared.Proto.Pa
request.Currency,
decimal.Parse(request.Amount),
request.HasRemarks ? request.Remarks : null,
(TransactionType)request.Type
(Shared.Models.TransactionType)request.Type
);
return transaction.ToProtoValue();
}

View File

@@ -15,12 +15,12 @@ public class SubscriptionController(SubscriptionService subscriptions, AfdianPay
{
[HttpGet]
[Authorize]
public async Task<ActionResult<List<SnSubscription>>> ListSubscriptions(
public async Task<ActionResult<List<SnWalletSubscription>>> ListSubscriptions(
[FromQuery] int offset = 0,
[FromQuery] int take = 20
)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var query = db.WalletSubscriptions.AsQueryable()
.Where(s => s.AccountId == currentUser.Id)
@@ -41,9 +41,9 @@ public class SubscriptionController(SubscriptionService subscriptions, AfdianPay
[HttpGet("fuzzy/{prefix}")]
[Authorize]
public async Task<ActionResult<SnSubscription>> GetSubscriptionFuzzy(string prefix)
public async Task<ActionResult<SnWalletSubscription>> GetSubscriptionFuzzy(string prefix)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var subscription = await db.WalletSubscriptions
.Where(s => s.AccountId == currentUser.Id && s.IsActive)
@@ -57,9 +57,9 @@ public class SubscriptionController(SubscriptionService subscriptions, AfdianPay
[HttpGet("{identifier}")]
[Authorize]
public async Task<ActionResult<SnSubscription>> GetSubscription(string identifier)
public async Task<ActionResult<SnWalletSubscription>> GetSubscription(string identifier)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var subscription = await subscriptions.GetSubscriptionAsync(currentUser.Id, identifier);
if (subscription is null) return NotFound($"Subscription with identifier {identifier} was not found.");
@@ -71,7 +71,7 @@ public class SubscriptionController(SubscriptionService subscriptions, AfdianPay
{
[Required] public string Identifier { get; set; } = null!;
[Required] public string PaymentMethod { get; set; } = null!;
[Required] public PaymentDetails PaymentDetails { get; set; } = null!;
[Required] public SnPaymentDetails PaymentDetails { get; set; } = null!;
public string? Coupon { get; set; }
public int? CycleDurationDays { get; set; }
public bool IsFreeTrial { get; set; } = false;
@@ -80,12 +80,12 @@ public class SubscriptionController(SubscriptionService subscriptions, AfdianPay
[HttpPost]
[Authorize]
public async Task<ActionResult<SnSubscription>> CreateSubscription(
public async Task<ActionResult<SnWalletSubscription>> CreateSubscription(
[FromBody] CreateSubscriptionRequest request,
[FromHeader(Name = "X-Noop")] bool noop = false
)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
Duration? cycleDuration = null;
if (request.CycleDurationDays.HasValue)
@@ -119,9 +119,9 @@ public class SubscriptionController(SubscriptionService subscriptions, AfdianPay
[HttpPost("{identifier}/cancel")]
[Authorize]
public async Task<ActionResult<SnSubscription>> CancelSubscription(string identifier)
public async Task<ActionResult<SnWalletSubscription>> CancelSubscription(string identifier)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
try
{
@@ -138,7 +138,7 @@ public class SubscriptionController(SubscriptionService subscriptions, AfdianPay
[Authorize]
public async Task<ActionResult<SnWalletOrder>> CreateSubscriptionOrder(string identifier)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
try
{

View File

@@ -6,11 +6,9 @@ using DysonNetwork.Pass.Wallet.PaymentHandlers;
using DysonNetwork.Shared.Cache;
using DysonNetwork.Shared.Models;
using DysonNetwork.Shared.Proto;
using Google.Protobuf.WellKnownTypes;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using NodaTime;
using AccountService = DysonNetwork.Pass.Account.AccountService;
using Duration = NodaTime.Duration;
namespace DysonNetwork.Pass.Wallet;
@@ -18,7 +16,7 @@ namespace DysonNetwork.Pass.Wallet;
public class SubscriptionService(
AppDatabase db,
PaymentService payment,
AccountService accounts,
Account.AccountService accounts,
RingService.RingServiceClient pusher,
IStringLocalizer<NotificationResource> localizer,
IConfiguration configuration,
@@ -26,11 +24,11 @@ public class SubscriptionService(
ILogger<SubscriptionService> logger
)
{
public async Task<Subscription> CreateSubscriptionAsync(
Account.Account account,
public async Task<SnWalletSubscription> CreateSubscriptionAsync(
SnAccount account,
string identifier,
string paymentMethod,
PaymentDetails paymentDetails,
SnPaymentDetails paymentDetails,
Duration? cycleDuration = null,
string? coupon = null,
bool isFreeTrial = false,
@@ -80,7 +78,7 @@ public class SubscriptionService(
throw new InvalidOperationException("Free trial already exists.");
}
Coupon? couponData = null;
SnWalletCoupon? couponData = null;
if (coupon is not null)
{
var inputCouponId = Guid.TryParse(coupon, out var parsedCouponId) ? parsedCouponId : Guid.Empty;
@@ -91,14 +89,14 @@ public class SubscriptionService(
}
var now = SystemClock.Instance.GetCurrentInstant();
var subscription = new Subscription
var subscription = new SnWalletSubscription
{
BegunAt = now,
EndedAt = now.Plus(cycleDuration.Value),
Identifier = identifier,
IsActive = true,
IsFreeTrial = isFreeTrial,
Status = SubscriptionStatus.Unpaid,
Status = Shared.Models.SubscriptionStatus.Unpaid,
PaymentMethod = paymentMethod,
PaymentDetails = paymentDetails,
BasePrice = subscriptionInfo.BasePrice,
@@ -114,7 +112,7 @@ public class SubscriptionService(
return subscription;
}
public async Task<Subscription> CreateSubscriptionFromOrder(ISubscriptionOrder order)
public async Task<SnWalletSubscription> CreateSubscriptionFromOrder(ISubscriptionOrder order)
{
var cfgSection = configuration.GetSection("Payment:Subscriptions");
var provider = order.Provider;
@@ -141,7 +139,7 @@ public class SubscriptionService(
throw new ArgumentOutOfRangeException(nameof(subscriptionIdentifier),
$@"Subscription {subscriptionIdentifier} was not found.");
Account.Account? account = null;
SnAccount? account = null;
if (!string.IsNullOrEmpty(provider))
account = await accounts.LookupAccountByConnection(order.AccountId, provider);
else if (Guid.TryParse(order.AccountId, out var accountId))
@@ -164,7 +162,7 @@ public class SubscriptionService(
existingSubscription.PaymentDetails.OrderId = order.Id;
existingSubscription.EndedAt = order.BegunAt.Plus(cycleDuration);
existingSubscription.RenewalAt = order.BegunAt.Plus(cycleDuration);
existingSubscription.Status = SubscriptionStatus.Active;
existingSubscription.Status = Shared.Models.SubscriptionStatus.Active;
db.Update(existingSubscription);
await db.SaveChangesAsync();
@@ -172,15 +170,15 @@ public class SubscriptionService(
return existingSubscription;
}
var subscription = new Subscription
var subscription = new SnWalletSubscription
{
BegunAt = order.BegunAt,
EndedAt = order.BegunAt.Plus(cycleDuration),
IsActive = true,
Status = SubscriptionStatus.Active,
Status = Shared.Models.SubscriptionStatus.Active,
Identifier = subscriptionIdentifier,
PaymentMethod = provider,
PaymentDetails = new PaymentDetails
PaymentDetails = new Shared.Models.SnPaymentDetails
{
Currency = currency,
OrderId = order.Id,
@@ -205,12 +203,12 @@ public class SubscriptionService(
/// <param name="identifier">The subscription identifier</param>
/// <returns></returns>
/// <exception cref="InvalidOperationException">The active subscription was not found</exception>
public async Task<Subscription> CancelSubscriptionAsync(Guid accountId, string identifier)
public async Task<SnWalletSubscription> CancelSubscriptionAsync(Guid accountId, string identifier)
{
var subscription = await GetSubscriptionAsync(accountId, identifier);
if (subscription is null)
throw new InvalidOperationException($"Subscription with identifier {identifier} was not found.");
if (subscription.Status != SubscriptionStatus.Active)
if (subscription.Status != Shared.Models.SubscriptionStatus.Active)
throw new InvalidOperationException("Subscription is already cancelled.");
if (subscription.RenewalAt is null)
throw new InvalidOperationException("Subscription is no need to be cancelled.");
@@ -238,11 +236,11 @@ public class SubscriptionService(
/// <param name="identifier">The unique subscription identifier.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the created subscription order.</returns>
/// <exception cref="InvalidOperationException">Thrown when no matching unpaid or expired subscription is found.</exception>
public async Task<Order> CreateSubscriptionOrder(Guid accountId, string identifier)
public async Task<SnWalletOrder> CreateSubscriptionOrder(Guid accountId, string identifier)
{
var subscription = await db.WalletSubscriptions
.Where(s => s.AccountId == accountId && s.Identifier == identifier)
.Where(s => s.Status != SubscriptionStatus.Expired)
.Where(s => s.Status != Shared.Models.SubscriptionStatus.Expired)
.Include(s => s.Coupon)
.OrderByDescending(s => s.BegunAt)
.FirstOrDefaultAsync();
@@ -268,9 +266,9 @@ public class SubscriptionService(
);
}
public async Task<Subscription> HandleSubscriptionOrder(Order order)
public async Task<SnWalletSubscription> HandleSubscriptionOrder(SnWalletOrder order)
{
if (order.Status != OrderStatus.Paid || order.Meta?["subscription_id"] is not JsonElement subscriptionIdJson)
if (order.Status != Shared.Models.OrderStatus.Paid || order.Meta?["subscription_id"] is not JsonElement subscriptionIdJson)
throw new InvalidOperationException("Invalid order.");
var subscriptionId = Guid.TryParse(subscriptionIdJson.ToString(), out var parsedSubscriptionId)
@@ -285,7 +283,7 @@ public class SubscriptionService(
if (subscription is null)
throw new InvalidOperationException("Invalid order.");
if (subscription.Status == SubscriptionStatus.Expired)
if (subscription.Status == Shared.Models.SubscriptionStatus.Expired)
{
var now = SystemClock.Instance.GetCurrentInstant();
var cycle = subscription.BegunAt.Minus(subscription.RenewalAt ?? subscription.EndedAt ?? now);
@@ -297,7 +295,7 @@ public class SubscriptionService(
subscription.EndedAt = nextEndedAt;
}
subscription.Status = SubscriptionStatus.Active;
subscription.Status = Shared.Models.SubscriptionStatus.Active;
db.Update(subscription);
await db.SaveChangesAsync();
@@ -320,7 +318,7 @@ public class SubscriptionService(
// Find active subscriptions that have passed their end date
var expiredSubscriptions = await db.WalletSubscriptions
.Where(s => s.IsActive)
.Where(s => s.Status == SubscriptionStatus.Active)
.Where(s => s.Status == Shared.Models.SubscriptionStatus.Active)
.Where(s => s.EndedAt.HasValue && s.EndedAt.Value < now)
.Take(batchSize)
.ToListAsync();
@@ -330,7 +328,7 @@ public class SubscriptionService(
foreach (var subscription in expiredSubscriptions)
{
subscription.Status = SubscriptionStatus.Expired;
subscription.Status = Shared.Models.SubscriptionStatus.Expired;
// Clear the cache for this subscription
var cacheKey = $"{SubscriptionCacheKeyPrefix}{subscription.AccountId}:{subscription.Identifier}";
@@ -341,12 +339,12 @@ public class SubscriptionService(
return expiredSubscriptions.Count;
}
private async Task NotifySubscriptionBegun(Subscription subscription)
private async Task NotifySubscriptionBegun(SnWalletSubscription subscription)
{
var account = await db.Accounts.FirstOrDefaultAsync(a => a.Id == subscription.AccountId);
if (account is null) return;
AccountService.SetCultureInfo(account);
Account.AccountService.SetCultureInfo(account);
var humanReadableName =
SubscriptionTypeData.SubscriptionHumanReadable.TryGetValue(subscription.Identifier, out var humanReadable)
@@ -378,7 +376,7 @@ public class SubscriptionService(
private const string SubscriptionCacheKeyPrefix = "subscription:";
public async Task<Subscription?> GetSubscriptionAsync(Guid accountId, params string[] identifiers)
public async Task<SnWalletSubscription?> GetSubscriptionAsync(Guid accountId, params string[] identifiers)
{
// Create a unique cache key for this subscription
var hashBytes = MD5.HashData(Encoding.UTF8.GetBytes(string.Join(",", identifiers)));
@@ -387,7 +385,7 @@ public class SubscriptionService(
var cacheKey = $"{SubscriptionCacheKeyPrefix}{accountId}:{hashIdentifier}";
// Try to get the subscription from cache first
var (found, cachedSubscription) = await cache.GetAsyncWithStatus<Subscription>(cacheKey);
var (found, cachedSubscription) = await cache.GetAsyncWithStatus<SnWalletSubscription>(cacheKey);
if (found && cachedSubscription != null)
{
return cachedSubscription;
@@ -411,12 +409,12 @@ public class SubscriptionService(
private static readonly List<string> PerkIdentifiers =
[SubscriptionType.Stellar, SubscriptionType.Nova, SubscriptionType.Supernova];
public async Task<Subscription?> GetPerkSubscriptionAsync(Guid accountId)
public async Task<SnWalletSubscription?> GetPerkSubscriptionAsync(Guid accountId)
{
var cacheKey = $"{SubscriptionPerkCacheKeyPrefix}{accountId}";
// Try to get the subscription from cache first
var (found, cachedSubscription) = await cache.GetAsyncWithStatus<Subscription>(cacheKey);
var (found, cachedSubscription) = await cache.GetAsyncWithStatus<SnWalletSubscription>(cacheKey);
if (found && cachedSubscription != null)
{
return cachedSubscription;
@@ -426,7 +424,7 @@ public class SubscriptionService(
var now = SystemClock.Instance.GetCurrentInstant();
var subscription = await db.WalletSubscriptions
.Where(s => s.AccountId == accountId && PerkIdentifiers.Contains(s.Identifier))
.Where(s => s.Status == SubscriptionStatus.Active)
.Where(s => s.Status == Shared.Models.SubscriptionStatus.Active)
.Where(s => s.EndedAt == null || s.EndedAt > now)
.OrderByDescending(s => s.BegunAt)
.FirstOrDefaultAsync();
@@ -439,16 +437,16 @@ public class SubscriptionService(
}
public async Task<Dictionary<Guid, Subscription?>> GetPerkSubscriptionsAsync(List<Guid> accountIds)
public async Task<Dictionary<Guid, SnWalletSubscription?>> GetPerkSubscriptionsAsync(List<Guid> accountIds)
{
var result = new Dictionary<Guid, Subscription?>();
var result = new Dictionary<Guid, SnWalletSubscription?>();
var missingAccountIds = new List<Guid>();
// Try to get the subscription from cache first
foreach (var accountId in accountIds)
{
var cacheKey = $"{SubscriptionPerkCacheKeyPrefix}{accountId}";
var (found, cachedSubscription) = await cache.GetAsyncWithStatus<Subscription>(cacheKey);
var (found, cachedSubscription) = await cache.GetAsyncWithStatus<SnWalletSubscription>(cacheKey);
if (found && cachedSubscription != null)
result[accountId] = cachedSubscription;
else
@@ -462,7 +460,7 @@ public class SubscriptionService(
var subscriptions = await db.WalletSubscriptions
.Where(s => missingAccountIds.Contains(s.AccountId))
.Where(s => PerkIdentifiers.Contains(s.Identifier))
.Where(s => s.Status == SubscriptionStatus.Active)
.Where(s => s.Status == Shared.Models.SubscriptionStatus.Active)
.Where(s => s.EndedAt == null || s.EndedAt > now)
.OrderByDescending(s => s.BegunAt)
.ToListAsync();

View File

@@ -13,9 +13,9 @@ public class WalletController(AppDatabase db, WalletService ws, PaymentService p
{
[HttpPost]
[Authorize]
public async Task<ActionResult<Wallet>> CreateWallet()
public async Task<ActionResult<SnWallet>> CreateWallet()
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
try
{
@@ -30,9 +30,9 @@ public class WalletController(AppDatabase db, WalletService ws, PaymentService p
[HttpGet]
[Authorize]
public async Task<ActionResult<Wallet>> GetWallet()
public async Task<ActionResult<SnWallet>> GetWallet()
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var wallet = await ws.GetWalletAsync(currentUser.Id);
if (wallet is null) return NotFound("Wallet was not found, please create one first.");
@@ -45,7 +45,7 @@ public class WalletController(AppDatabase db, WalletService ws, PaymentService p
[FromQuery] int offset = 0, [FromQuery] int take = 20
)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var accountWallet = await db.Wallets.Where(w => w.AccountId == currentUser.Id).FirstOrDefaultAsync();
if (accountWallet is null) return NotFound();
@@ -72,7 +72,7 @@ public class WalletController(AppDatabase db, WalletService ws, PaymentService p
[FromQuery] int offset = 0, [FromQuery] int take = 20
)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var accountWallet = await db.Wallets.Where(w => w.AccountId == currentUser.Id).FirstOrDefaultAsync();
if (accountWallet is null) return NotFound();

View File

@@ -5,14 +5,14 @@ namespace DysonNetwork.Pass.Wallet;
public class WalletService(AppDatabase db)
{
public async Task<Wallet?> GetWalletAsync(Guid accountId)
public async Task<SnWallet?> GetWalletAsync(Guid accountId)
{
return await db.Wallets
.Include(w => w.Pockets)
.FirstOrDefaultAsync(w => w.AccountId == accountId);
}
public async Task<Wallet> CreateWalletAsync(Guid accountId)
public async Task<SnWallet> CreateWalletAsync(Guid accountId)
{
var existingWallet = await db.Wallets.FirstOrDefaultAsync(w => w.AccountId == accountId);
if (existingWallet != null)
@@ -20,7 +20,7 @@ public class WalletService(AppDatabase db)
throw new InvalidOperationException($"Wallet already exists for account {accountId}");
}
var wallet = new Wallet { AccountId = accountId };
var wallet = new SnWallet { AccountId = accountId };
db.Wallets.Add(wallet);
await db.SaveChangesAsync();