151 lines
4.8 KiB
C#
151 lines
4.8 KiB
C#
using MediatR;
|
|
using MiningService.Domain.AggregatesModel.MinerAggregate;
|
|
|
|
namespace MiningService.API.Application.Queries;
|
|
|
|
/// <summary>
|
|
/// EN: Query to get mining history for a user.
|
|
/// VI: Query để lấy lịch sử đào của người dùng.
|
|
/// </summary>
|
|
public record GetMiningHistoryQuery(Guid UserId, int Page = 1, int PageSize = 20) : IRequest<MiningHistoryDto>;
|
|
|
|
public record MiningHistoryDto(
|
|
List<MiningHistoryItemDto> Items,
|
|
int TotalCount,
|
|
int Page,
|
|
int PageSize);
|
|
|
|
public record MiningHistoryItemDto(
|
|
Guid Id,
|
|
decimal Amount,
|
|
string Source,
|
|
decimal RateSnapshot,
|
|
DateTime CreatedAt);
|
|
|
|
public class GetMiningHistoryQueryHandler : IRequestHandler<GetMiningHistoryQuery, MiningHistoryDto>
|
|
{
|
|
private readonly IMinerRepository _minerRepository;
|
|
|
|
public GetMiningHistoryQueryHandler(IMinerRepository minerRepository)
|
|
{
|
|
_minerRepository = minerRepository;
|
|
}
|
|
|
|
public async Task<MiningHistoryDto> Handle(GetMiningHistoryQuery request, CancellationToken cancellationToken)
|
|
{
|
|
var miner = await _minerRepository.GetByUserIdAsync(request.UserId, cancellationToken);
|
|
if (miner == null)
|
|
return new MiningHistoryDto(new List<MiningHistoryItemDto>(), 0, request.Page, request.PageSize);
|
|
|
|
var history = miner.MiningHistories
|
|
.OrderByDescending(h => h.EarnedAt)
|
|
.Skip((request.Page - 1) * request.PageSize)
|
|
.Take(request.PageSize)
|
|
.Select(h => new MiningHistoryItemDto(h.Id, h.PointsEarned, h.Source, h.HourlyRateSnapshot, h.EarnedAt))
|
|
.ToList();
|
|
|
|
return new MiningHistoryDto(history, miner.MiningHistories.Count, request.Page, request.PageSize);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// EN: Query to get current mining rate breakdown.
|
|
/// VI: Query để lấy chi tiết tỷ lệ đào hiện tại.
|
|
/// </summary>
|
|
public record GetMiningRateQuery(Guid UserId) : IRequest<MiningRateDto?>;
|
|
|
|
public record MiningRateDto(
|
|
decimal BaseRate,
|
|
decimal RoleMultiplier,
|
|
decimal CircleBonus,
|
|
decimal ReferralBonus,
|
|
decimal StreakBonus,
|
|
decimal TotalRate,
|
|
decimal HourlyPoints,
|
|
decimal DailyPoints);
|
|
|
|
public class GetMiningRateQueryHandler : IRequestHandler<GetMiningRateQuery, MiningRateDto?>
|
|
{
|
|
private readonly IMinerRepository _minerRepository;
|
|
|
|
public GetMiningRateQueryHandler(IMinerRepository minerRepository)
|
|
{
|
|
_minerRepository = minerRepository;
|
|
}
|
|
|
|
public async Task<MiningRateDto?> Handle(GetMiningRateQuery request, CancellationToken cancellationToken)
|
|
{
|
|
var miner = await _minerRepository.GetByUserIdAsync(request.UserId, cancellationToken);
|
|
if (miner == null) return null;
|
|
|
|
var rate = miner.CurrentRate;
|
|
var baseRate = 0.25m;
|
|
var roleMultiplier = GetRoleMultiplier(miner.Role);
|
|
var circleBonus = miner.CircleId.HasValue ? 0.25m : 0m;
|
|
var referralBonus = 0m; // Would need to query repository for actual count
|
|
var streakBonus = miner.Streak.BonusMultiplier;
|
|
|
|
var totalRate = baseRate * (1 + roleMultiplier) * (1 + circleBonus) * (1 + referralBonus) * (1 + streakBonus);
|
|
|
|
return new MiningRateDto(
|
|
baseRate,
|
|
roleMultiplier,
|
|
circleBonus,
|
|
referralBonus,
|
|
streakBonus,
|
|
totalRate,
|
|
totalRate,
|
|
totalRate * 24);
|
|
}
|
|
|
|
private static decimal GetRoleMultiplier(MinerRole role) => role switch
|
|
{
|
|
MinerRole.Pioneer => 0m,
|
|
MinerRole.Contributor => 0.10m,
|
|
MinerRole.Ambassador => 0.25m,
|
|
MinerRole.NodeOperator => 0.50m,
|
|
_ => 0m
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// EN: Query to get top miners leaderboard.
|
|
/// VI: Query để lấy bảng xếp hạng thợ đào.
|
|
/// </summary>
|
|
public record GetLeaderboardQuery(int Limit = 100) : IRequest<LeaderboardDto>;
|
|
|
|
public record LeaderboardDto(List<LeaderboardEntryDto> Entries);
|
|
|
|
public record LeaderboardEntryDto(
|
|
int Rank,
|
|
Guid MinerId,
|
|
Guid UserId,
|
|
decimal TotalPoints,
|
|
int StreakDays,
|
|
MinerRole Role);
|
|
|
|
public class GetLeaderboardQueryHandler : IRequestHandler<GetLeaderboardQuery, LeaderboardDto>
|
|
{
|
|
private readonly IMinerRepository _minerRepository;
|
|
|
|
public GetLeaderboardQueryHandler(IMinerRepository minerRepository)
|
|
{
|
|
_minerRepository = minerRepository;
|
|
}
|
|
|
|
public async Task<LeaderboardDto> Handle(GetLeaderboardQuery request, CancellationToken cancellationToken)
|
|
{
|
|
var topMiners = await _minerRepository.GetTopMinersAsync(request.Limit, cancellationToken);
|
|
|
|
var entries = topMiners.Select((m, i) => new LeaderboardEntryDto(
|
|
i + 1,
|
|
m.Id,
|
|
m.UserId,
|
|
m.TotalMinedPoints,
|
|
m.Streak.CurrentStreak,
|
|
m.Role)).ToList();
|
|
|
|
return new LeaderboardDto(entries);
|
|
}
|
|
}
|