diff --git a/src/NadekoBot/Db/Models/PatronQuota.cs b/src/NadekoBot/Db/Models/PatronQuota.cs index 8b909afed..863dcd961 100644 --- a/src/NadekoBot/Db/Models/PatronQuota.cs +++ b/src/NadekoBot/Db/Models/PatronQuota.cs @@ -35,4 +35,14 @@ public class PatronUser // Date Only component public DateTime ValidThru { get; set; } + + public PatronUser Clone() + => new PatronUser() + { + UniquePlatformUserId = this.UniquePlatformUserId, + UserId = this.UserId, + AmountCents = this.AmountCents, + LastCharge = this.LastCharge, + ValidThru = this.ValidThru + }; } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Gambling/Bank/BankService.cs b/src/NadekoBot/Modules/Gambling/Bank/BankService.cs index e754df30e..557377c9c 100644 --- a/src/NadekoBot/Modules/Gambling/Bank/BankService.cs +++ b/src/NadekoBot/Modules/Gambling/Bank/BankService.cs @@ -75,19 +75,4 @@ public sealed class BankService : IBankService, INService ?.Balance ?? 0; } - - public async Task BurnAllAsync(ulong userId) - { - await using var ctx = _db.GetDbContext(); - var output = await ctx.GetTable() - .Where(x => x.UserId == userId) - .UpdateWithOutputAsync(old => new() - { - Balance = 0 - }); - if (output.Length == 0) - return 0; - - return output[0].Deleted.Balance; - } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Gambling/Bank/IBankService.cs b/src/NadekoBot/Modules/Gambling/Bank/IBankService.cs index 1140fbcde..d35166f68 100644 --- a/src/NadekoBot/Modules/Gambling/Bank/IBankService.cs +++ b/src/NadekoBot/Modules/Gambling/Bank/IBankService.cs @@ -5,5 +5,4 @@ public interface IBankService Task DepositAsync(ulong userId, long amount); Task WithdrawAsync(ulong userId, long amount); Task GetBalanceAsync(ulong userId); - Task BurnAllAsync(ulong userId); } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Utility/Patronage/CurrencyRewardService.cs b/src/NadekoBot/Modules/Utility/Patronage/CurrencyRewardService.cs index 5ba470879..800471529 100644 --- a/src/NadekoBot/Modules/Utility/Patronage/CurrencyRewardService.cs +++ b/src/NadekoBot/Modules/Utility/Patronage/CurrencyRewardService.cs @@ -50,67 +50,91 @@ public class CurrencyRewardService : INService, IDisposable private async Task OnPatronUpdate(Patron oldPatron, Patron newPatron) { - if (oldPatron.Amount != newPatron.Amount) + // if pledge was increased + if (oldPatron.Amount < newPatron.Amount) { var conf = _config.Data; + var newAmount = (long)(newPatron.Amount * conf.PatreonCurrencyPerCent); - var newAmount = (long)(Math.Max(newPatron.Amount, oldPatron.Amount) * conf.PatreonCurrencyPerCent); - UpdateOutput[] output; + RewardedUser old; await using (var ctx = _db.GetDbContext()) { - output = await ctx.GetTable() - .Where(x => x.PlatformUserId == newPatron.UnqiuePlatformUserId) - .UpdateWithOutputAsync(old => new() + old = await ctx.GetTable() + .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() + .Where(x => x.PlatformUserId == newPatron.UniquePlatformUserId) + .UpdateAsync(_ => new() { - PlatformUserId = newPatron.UnqiuePlatformUserId, + PlatformUserId = newPatron.UniquePlatformUserId, UserId = newPatron.UserId, // amount before bonuses AmountRewardedThisMonth = newAmount, LastReward = newPatron.PaidAt }); + + // shouldn't ever happen + if (count == 0) + return; } - // if the user wasn't previously in the db for some reason, - // we will treat him as a new patron - if (output.Length == 0) - { - await OnNewPayment(newPatron); - return; - } + var oldAmount = old.AmountRewardedThisMonth; - var oldAmount = output[0].Deleted.AmountRewardedThisMonth; - - var diff = newAmount - oldAmount; + 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% - - var realAmount = GetRealCurrencyReward(newPatron.Amount, diff, out var percentBonus); - await _cs.AddAsync(newPatron.UserId, realAmount, new TxData("patron","update")); + + await _cs.AddAsync(newPatron.UserId, diff, new TxData("patron","update")); _ = SendMessageToUser(newPatron.UserId, - $"You've received an additional **{realAmount}**{_config.Data.Currency.Sign} as a currency reward (+{percentBonus}%)!"); + $"You've received an additional **{diff}**{_config.Data.Currency.Sign} as a currency reward (+{percentBonus}%)!"); } } - private long GetRealCurrencyReward(int fullPledge, long currentAmount, out int percentBonus) + private long GetRealCurrencyReward(int pledgeCents, long modifiedAmount, out int percentBonus) { // needs at least 5$ to be eligible for a bonus - if (fullPledge < 500) + if (pledgeCents < 500) { percentBonus = 0; - return currentAmount; + return modifiedAmount; } - var dollarValue = fullPledge / 100; + var dollarValue = pledgeCents / 100; percentBonus = dollarValue switch { - > 100 => 100, - _ => dollarValue + >= 100 => 100, + >= 50 => 50, + >= 20 => 20, + >= 10 => 10, + >= 5 => 5, + _ => 0 }; - return (long)(currentAmount * (1 + (percentBonus / 100.0f))); + return (long)(modifiedAmount * (1 + (percentBonus / 100.0f))); } // on a new payment, always give the full amount. @@ -121,7 +145,7 @@ public class CurrencyRewardService : INService, IDisposable await ctx.GetTable() .InsertOrUpdateAsync(() => new() { - PlatformUserId = patron.UnqiuePlatformUserId, + PlatformUserId = patron.UniquePlatformUserId, UserId = patron.UserId, AmountRewardedThisMonth = amount, LastReward = patron.PaidAt, @@ -134,7 +158,7 @@ public class CurrencyRewardService : INService, IDisposable }, () => new() { - PlatformUserId = patron.UnqiuePlatformUserId + PlatformUserId = patron.UniquePlatformUserId }); var realAmount = GetRealCurrencyReward(patron.Amount, amount, out var percentBonus); @@ -167,24 +191,9 @@ public class CurrencyRewardService : INService, IDisposable { await using var ctx = _db.GetDbContext(); _ = await ctx.GetTable() - .UpdateWithOutputAsync(old => new() + .UpdateAsync(old => new() { AmountRewardedThisMonth = old.AmountRewardedThisMonth * 2 }); - - // var toTake = old.Length == 0 - // ? patron.Amount - // : old[0].Inserted.AmountRewardedThisMonth; - - // if (toTake > 0) - // { - // Log.Warning("Wiping the wallet and bank of the user {UserId} due to a refund/fraud...", - // patron.UserId); - // await _cs.RemoveAsync(patron.UserId, patron.Amount, new("patreon", "refund")); - // await _bs.BurnAllAsync(patron.UserId); - // Log.Warning("Burned {Amount} currency from the bank of the user {UserId} due to a refund/fraud.", - // patron.Amount, - // patron.UserId); - // } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Utility/Patronage/Patron.cs b/src/NadekoBot/Modules/Utility/Patronage/Patron.cs index ae5a1d888..bfe928f04 100644 --- a/src/NadekoBot/Modules/Utility/Patronage/Patron.cs +++ b/src/NadekoBot/Modules/Utility/Patronage/Patron.cs @@ -5,10 +5,10 @@ public readonly struct Patron /// /// Unique id assigned to this patron by the payment platform /// - public string UnqiuePlatformUserId { get; init; } + public string UniquePlatformUserId { get; init; } /// - /// Discord UserId to which this is connected to + /// Discord UserId to which this is connected to /// public ulong UserId { get; init; } diff --git a/src/NadekoBot/Modules/Utility/Patronage/PatronageService.cs b/src/NadekoBot/Modules/Utility/Patronage/PatronageService.cs index 387477220..9a537ac1b 100644 --- a/src/NadekoBot/Modules/Utility/Patronage/PatronageService.cs +++ b/src/NadekoBot/Modules/Utility/Patronage/PatronageService.cs @@ -173,7 +173,7 @@ public sealed class PatronageService var lastChargeUtc = subscriber.LastCharge.Value.ToUniversalTime(); var dateInOneMonth = lastChargeUtc.Date.AddMonths(1); - await using var tran = await ctx.Database.BeginTransactionAsync(); + // await using var tran = await ctx.Database.BeginTransactionAsync(); try { var dbPatron = await ctx.GetTable() @@ -193,7 +193,7 @@ public sealed class PatronageService ValidThru = dateInOneMonth, }); - await tran.CommitAsync(); + // await tran.CommitAsync(); var newPatron = PatronUserToPatron(dbPatron); _ = SendWelcomeMessage(newPatron); @@ -222,45 +222,38 @@ public sealed class PatronageService // this should never happen if (count == 0) { - await tran.RollbackAsync(); + // await tran.RollbackAsync(); continue; } - await tran.CommitAsync(); + // await tran.CommitAsync(); await OnNewPatronPayment(PatronUserToPatron(dbPatron)); } else if (dbPatron.AmountCents != subscriber.Cents // if user changed the amount || dbPatron.UserId != subscriber.UserId) // if user updated user id) { + var cents = subscriber.Cents; // the user updated the pledge or changed the connected discord account - var count = await ctx.GetTable() - .Where(x => x.UniquePlatformUserId == subscriber.UniquePlatformUserId - && x.LastCharge < lastChargeUtc) - .UpdateAsync(old => new() - { - UserId = subscriber.UserId, - AmountCents = subscriber.Cents, - LastCharge = lastChargeUtc, - ValidThru = old.ValidThru, - }); + await ctx.GetTable() + .Where(x => x.UniquePlatformUserId == subscriber.UniquePlatformUserId) + .UpdateAsync(old => new() + { + UserId = subscriber.UserId, + AmountCents = cents, + LastCharge = lastChargeUtc, + ValidThru = old.ValidThru, + }); - if (count == 0) - { - await tran.RollbackAsync(); - continue; - } - - var newData = await ctx.GetTable() - .FirstAsync(x => x.UniquePlatformUserId - == subscriber.UniquePlatformUserId); - - - await tran.CommitAsync(); + var newPatron = dbPatron.Clone(); + newPatron.AmountCents = cents; + newPatron.UserId = subscriber.UserId; + + // idk what's going on but UpdateWithOutputAsync doesn't work properly here + // nor does firstordefault after update. I'm not seeing something obvious await OnPatronUpdated( PatronUserToPatron(dbPatron), - PatronUserToPatron(newData)); - + PatronUserToPatron(newPatron)); } } } @@ -745,7 +738,7 @@ public sealed class PatronageService private Patron PatronUserToPatron(PatronUser user) => new Patron() { - UnqiuePlatformUserId = user.UniquePlatformUserId, + UniquePlatformUserId = user.UniquePlatformUserId, UserId = user.UserId, Amount = user.AmountCents, Tier = CalculateTier(user), @@ -798,7 +791,7 @@ public sealed class PatronageService *- Any user in any of your servers can use Patron-only commands, but they will spend **your quota**, which is why it's recommended to use Nadeko's command cooldown system (.h .cmdcd) or permission system to limit the command usage for your server members.* *- Permission guide can be found here if you're not familiar with it: *", isInline: false) - .WithFooter($"platform id: {patron.UnqiuePlatformUserId}"); + .WithFooter($"platform id: {patron.UniquePlatformUserId}"); await user.EmbedAsync(eb); } diff --git a/src/NadekoBot/NadekoBot.csproj b/src/NadekoBot/NadekoBot.csproj index c9b20801a..e8bc4b226 100644 --- a/src/NadekoBot/NadekoBot.csproj +++ b/src/NadekoBot/NadekoBot.csproj @@ -69,15 +69,15 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + diff --git a/src/NadekoBot/data/patron.yml b/src/NadekoBot/data/patron.yml index e8cec7cbc..9a9658a14 100644 --- a/src/NadekoBot/data/patron.yml +++ b/src/NadekoBot/data/patron.yml @@ -23,6 +23,8 @@ quotas: C: 100000 # Dictionary of commands with their respective quota data commands: + cleverbot: + V: null prune: X: PerHour: 1