This repository has been archived on 2024-12-22. You can view files and clone it, but cannot push or open issues or pull requests.
elliebot/src/EllieBot/Modules/Patronage/CurrencyRewardService.cs

194 lines
No EOL
6.7 KiB
C#

#nullable disable
using LinqToDB;
using LinqToDB.EntityFrameworkCore;
using EllieBot.Common.ModuleBehaviors;
using EllieBot.Modules.Gambling.Services;
using EllieBot.Modules.Patronage;
using EllieBot.Services.Currency;
using EllieBot.Db.Models;
namespace EllieBot.Modules.Utility;
public sealed class CurrencyRewardService : IEService, IReadyExecutor
{
private readonly ICurrencyService _cs;
private readonly IPatronageService _ps;
private readonly DbService _db;
private readonly IMessageSenderService _sender;
private readonly GamblingConfigService _config;
private readonly DiscordSocketClient _client;
public CurrencyRewardService(
ICurrencyService cs,
IPatronageService ps,
DbService db,
IMessageSenderService sender,
GamblingConfigService config,
DiscordSocketClient client)
{
_cs = cs;
_ps = ps;
_db = db;
_sender = sender;
_config = config;
_client = client;
}
public Task OnReadyAsync()
{
_ps.OnNewPatronPayment += OnNewPayment;
_ps.OnPatronRefunded += OnPatronRefund;
_ps.OnPatronUpdated += OnPatronUpdate;
return Task.CompletedTask;
}
private async Task OnPatronUpdate(Patron oldPatron, Patron newPatron)
{
// if pledge was increased
if (oldPatron.Amount < newPatron.Amount)
{
var conf = _config.Data;
var newAmount = (long)(newPatron.Amount * conf.PatreonCurrencyPerCent);
RewardedUser old;
await using (var ctx = _db.GetDbContext())
{
old = await ctx.GetTable<RewardedUser>()
.Where(x => x.PlatformUserId == newPatron.UniquePlatformUserId)
.FirstOrDefaultAsync();
if (old is null)
{
await OnNewPayment(newPatron);
return;
}
// no action as the amount is the same or lower
if (old.AmountRewardedThisMonth >= newAmount)
return;
var count = await ctx.GetTable<RewardedUser>()
.Where(x => x.PlatformUserId == newPatron.UniquePlatformUserId)
.UpdateAsync(_ => new()
{
PlatformUserId = newPatron.UniquePlatformUserId,
UserId = newPatron.UserId,
// amount before bonuses
AmountRewardedThisMonth = newAmount,
LastReward = newPatron.PaidAt
});
// shouldn't ever happen
if (count == 0)
return;
}
var oldAmount = old.AmountRewardedThisMonth;
var realNewAmount = GetRealCurrencyReward(
(int)(newAmount / conf.PatreonCurrencyPerCent),
newAmount,
out var percentBonus);
var realOldAmount = GetRealCurrencyReward(
(int)(oldAmount / conf.PatreonCurrencyPerCent),
oldAmount,
out _);
var diff = realNewAmount - realOldAmount;
if (diff <= 0)
return; // no action if new is lower
// if the user pledges 5$ or more, they will get X % more flowers where X is amount in dollars,
// up to 100%
await _cs.AddAsync(newPatron.UserId, diff, new TxData("patron","update"));
_ = SendMessageToUser(newPatron.UserId,
$"You've received an additional **{diff}**{_config.Data.Currency.Sign} as a currency reward (+{percentBonus}%)!");
}
}
private long GetRealCurrencyReward(int pledgeCents, long modifiedAmount, out int percentBonus)
{
// needs at least 5$ to be eligible for a bonus
if (pledgeCents < 500)
{
percentBonus = 0;
return modifiedAmount;
}
var dollarValue = pledgeCents / 100;
percentBonus = dollarValue switch
{
>= 100 => 25,
>= 50 => 20,
>= 20 => 15,
>= 10 => 10,
>= 5 => 5,
_ => 0
};
return (long)(modifiedAmount * (1 + (percentBonus / 100.0f)));
}
// on a new payment, always give the full amount.
private async Task OnNewPayment(Patron patron)
{
var amount = (long)(patron.Amount * _config.Data.PatreonCurrencyPerCent);
await using var ctx = _db.GetDbContext();
await ctx.GetTable<RewardedUser>()
.InsertOrUpdateAsync(() => new()
{
PlatformUserId = patron.UniquePlatformUserId,
UserId = patron.UserId,
AmountRewardedThisMonth = amount,
LastReward = patron.PaidAt,
},
old => new()
{
AmountRewardedThisMonth = amount,
UserId = patron.UserId,
LastReward = patron.PaidAt
},
() => new()
{
PlatformUserId = patron.UniquePlatformUserId
});
var realAmount = GetRealCurrencyReward(patron.Amount, amount, out var percentBonus);
await _cs.AddAsync(patron.UserId, realAmount, new("patron", "new"));
_ = SendMessageToUser(patron.UserId,
$"You've received **{realAmount}**{_config.Data.Currency.Sign} as a currency reward (**+{percentBonus}%**)!");
}
private async Task SendMessageToUser(ulong userId, string message)
{
try
{
var user = (IUser)_client.GetUser(userId) ?? await _client.Rest.GetUserAsync(userId);
if (user is null)
return;
var eb = _sender.CreateEmbed()
.WithOkColor()
.WithDescription(message);
await _sender.Response(user).Embed(eb).SendAsync();
}
catch
{
Log.Warning("Unable to send a \"Currency Reward\" message to the patron {UserId}", userId);
}
}
private async Task OnPatronRefund(Patron patron)
{
await using var ctx = _db.GetDbContext();
_ = await ctx.GetTable<RewardedUser>()
.UpdateAsync(old => new()
{
AmountRewardedThisMonth = old.AmountRewardedThisMonth * 2
});
}
}