private async Task <GumroadSale> GetSaleAsync(IDMChannel dm, RexoProduct product, Email email) { // Check if the user's data was provided in a previous gumroad request // Do I even use this? var foundSale = _cachedSales.FirstOrDefault(x => x.PurchaseEmail.ToLower() == email.ToString().ToLower()); if (foundSale == null) { var allSales = await _gumroad.GetSalesAsync(_config["gumroad:token"], new GetSalesParams { Email = email.ToString() }); if (allSales.IsSuccess) { return(allSales.Sales.FirstOrDefault()); } else { return(null); } } return(foundSale); }
public async Task LinkUserAsync(ulong userId, RexoProduct product) { // Check if user is in a shared guild var user = _discord.GetUser(userId) as SocketGuildUser; if (user == null) { return; } // Check if user is being ratelimited if (_ratelimitedUsers.TryGetValue(userId, out DateTime ratelimitStart)) { var ratelimitRemaining = DateTime.UtcNow - ratelimitStart; // If yes and time is remaining, silently drop the request if (ratelimitRemaining < _ratelimitLength) { _logger.LogInformation($"User `{userId}` was stopped by the ratelimiter: {Math.Round(ratelimitRemaining.TotalMinutes, 2)} minutes remaining"); return; } else { // Otherwise, remove them from ratelimiter and continue _ratelimitedUsers.Remove(userId, out DateTime _); _logger.LogInformation($"User `{userId}` removed from ratelimiter"); } } // Get guild and dm objects var guild = _discord.GetGuild(product.GuildId); var dm = await user.GetOrCreateDMChannelAsync(); Email email = default; GumroadSale foundSale = default; // Check if an email is already stored for the user var rexoUser = _db.Users.SingleOrDefault(x => x.Id == userId); if (rexoUser != null) { email = new Email(rexoUser.Email); foundSale = await GetSaleAsync(dm, product, email); if (foundSale == null) { await dm.SendMessageAsync($"Sorry, I couldn't find any sales for this product matching your linked email."); return; } } // Loop over several attempts allowing some space for user error int attempt = 0; while (!email.IsValid && attempt < 5) { // First attempt instruction message if (attempt == 0) { await dm.SendMessageAsync($"Hey {user.Username}! " + $"It looks like you want to link your purchase of {product.Name} to get a special role in {guild.Name}. " + $"If this is correct, please reply with your email so I can confirm this information on Gumroad."); } // Wait for user response attempt++; var emailReplyMsg = await _responsive.WaitForMessageAsync((msg) => true, TimeSpan.FromMinutes(1)); email = new Email(emailReplyMsg.Content); if (!email.IsValid) { await dm.SendMessageAsync($"Sorry, it doesn't look like that's a valid email. Check for typos and try again."); continue; } // Try to pull a sale matching this email from gumroad foundSale = await GetSaleAsync(dm, product, email); if (foundSale != null) { break; } await dm.SendMessageAsync($"Sorry, I couldn't find any sales for {product.Name} matching that email. Check for typos and try again."); } // If the loop breaks due to attempts, add the user to the ratelimiter and break. if (attempt >= 5) { _logger.LogInformation($"User `{userId}` is now being ratelimited"); _ratelimitedUsers.TryAdd(userId, DateTime.UtcNow); await dm.SendMessageAsync($"You have submitted 5 invalid emails and are now being ratelimited. Please try again in 30 minutes."); return; } // Save order information to the database var rexoRole = new RexoSyncedRole { OrderId = foundSale.OrderId, ProductId = product.Id }; _db.SyncedRoles.Add(rexoRole); _db.SaveChanges(); // Give the user their special role var role = guild.GetRole(product.RoleId); await user.AddRoleAsync(role); await dm.SendMessageAsync($"I have successfully gave you the {role.Name} role in {guild.Name}, have fun!"); }