public async Task InteractiveSetupCommandAsync(CommandContext ctx) { // Check for donor rank updates // then display welcome message // along with donor features this server gets // or an advert for unlocking the donor features // (check, cross, and lock symbols next to features for avalible, used, and need to buy stuff) // have setup requirements displayed // and options to setup parts of the message // along with a toggle option, once everything is setup // once setup is closed, save new data. GuildBan?ban; if ((ban = await this._ban.GetBanAsync(ctx.Guild.Id)) is not null || (ban = await this._ban.GetBanAsync(ctx.Guild.OwnerId)) is not null) { await RespondError($"Your server is banned due to: {ban.Reason}\n\n" + $"Contact a staff member on the [support server](https://discord.gg/3SCTnhCMam) to learn more."); await ctx.Guild.LeaveAsync(); return; } using var scope = this._services.CreateScope(); var db = scope.ServiceProvider.GetRequiredService <PartnerDatabaseContext>(); Partner?partner = await db.Partners.AsNoTracking().FirstOrDefaultAsync(x => x.GuildId == ctx.Guild.Id); if (partner is null) { partner = new() { GuildId = ctx.Guild.Id, }; await db.AddAsync(partner); await db.SaveChangesAsync(); } partner.OwnerId = ctx.Guild.OwnerId; partner.GuildName = ctx.Guild.Name; partner.GuildIcon = ctx.Guild.IconUrl; partner.UserCount = ctx.Guild.MemberCount; partner.DonorRank = await this._donor.GetDonorRankAsync(partner.OwnerId); await db.SaveChangesAsync(); partner.ModifyToDonorRank(); DiscordChannel?channel = null; ulong oldChannelId = 0; DiscordWebhook?hook = null; if (!string.IsNullOrWhiteSpace(partner.WebhookToken)) { try { hook = await ctx.Client.GetWebhookAsync(partner.WebhookId); channel = await ctx.Client.GetChannelAsync(hook.ChannelId); oldChannelId = channel.Id; } catch { hook = null; oldChannelId = 0; channel = null; } } DSharpPlus.Interactivity.InteractivityExtension?interact = ctx.Client.GetInteractivity(); bool done = false; bool isChanged = false; string? errorMessage = null; DiscordMessage? requirementsMessage = null; HashSet <string>?tagUpdate = null; ComponentInteractionCreateEventArgs?lastButtonEvent = null; do { if (lastButtonEvent is null) { var messageBuilder = await GetMessageBuilder(partner, isChanged, channel); if (requirementsMessage is null) { requirementsMessage = await messageBuilder.SendAsync(ctx.Channel); } else { await requirementsMessage.ModifyAsync(messageBuilder); } } else { await lastButtonEvent.Interaction.EditOriginalResponseAsync( await GetInteractionEditAsync(partner, isChanged, channel, errorMessage) ); requirementsMessage = lastButtonEvent.Message; } var response = await GetButtonPressAsync(interact, requirementsMessage); if (!response.Item2) { return; } lastButtonEvent = response.Item1; await lastButtonEvent.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, await GetInteractionResponseAsync(partner, isChanged, channel, errorMessage)); errorMessage = null; switch (lastButtonEvent.Id) { // Exit calls. case "exit": await RespondError("Aborting..."); return; case "save": done = true; break; // Primary Settings. case "channel": ((DiscordChannel, DiscordWebhook, string)?, string?, bool)chanRes = await GetNewPartnerChannelAsync(partner, lastButtonEvent); if (chanRes.Item3) { return; } if (chanRes.Item1 is null) { await RespondError(chanRes.Item2 ?? "An unknown error occurred."); return; } channel = chanRes.Item1.Value.Item1; partner.WebhookId = chanRes.Item1.Value.Item2.Id; partner.WebhookToken = chanRes.Item1.Value.Item2.Token; partner.Invite = chanRes.Item1.Value.Item3; break; case "message": (string?, string?, bool)messageRes = await GetNewMessage(partner, lastButtonEvent, partner.Message.GetUrls().Count); if (messageRes.Item3) { return; } if (messageRes.Item1 is null) { await RespondError(messageRes.Item2 ?? "An unknown error occurred."); return; } partner.Message = messageRes.Item1; break; case "toggle": var setup = partner.IsSetup(); if (partner.Active) { partner.Active = false; } else if (!partner.Active && setup.Item1) { partner.Active = true; } else { errorMessage = $"**Core setup is not complete. Please complete the required settings before toggling Partner Bot**\n\n" + $"**Setup Erroed because:** `{setup.Item2}`"; } break; // Secondary Settings. case "add-embed": if (partner.DonorRank < DonorService.EMBED_LIMIT) { errorMessage = $"**You need to be a Tripple Partner to use custom embeds! Consider [donating](https://www.patreon.com/cessumdevelopment?fan_landing=true) to get access to embeds.**"; } else if (partner.DonorRank >= DonorService.HIGHEST_RANK ? partner.MessageEmbeds.Count >= DonorService.QUADRUPLE_EMBEDS : partner.MessageEmbeds.Count >= DonorService.TRIPPLE_EMBEDS) { errorMessage = $"**You have used up all your embeds! You can edit a existing one, or remove an old one and add a new one.**"; } else { var statusEmbed = new DiscordEmbedBuilder() .WithDescription($"**Please enter the title for your new embed:**") .WithColor(Color_PartnerBotMagenta); var builder = new DiscordMessageBuilder() .WithEmbed(statusEmbed); var statusMessage = await builder.SendAsync(lastButtonEvent.Channel); (DSharpPlus.Interactivity.InteractivityResult <DiscordMessage>, bool)editStart = await GetFollowupMessageAsync(interact); if (!editStart.Item2) { return; } DSharpPlus.Interactivity.InteractivityResult <DiscordMessage> startRes = editStart.Item1; string?title = startRes.Result.Content.Trim(); if (title.Length > 256) { errorMessage = $"**The embed title cannot be longer than 256 characters. Returning to main menu.**"; } else { (DiscordEmbedBuilder?, string?, bool)addEnd = await GetCustomDiscordEmbedAsync(partner, lastButtonEvent, title); if (addEnd.Item3) { return; } if (addEnd.Item1 is null) { await RespondError(addEnd.Item2 ?? "An unknown error occurred."); return; } partner.MessageEmbeds.Add(addEnd.Item1); } await statusMessage.DeleteAsync(); } break; case "edit-embed": if (partner.DonorRank < DonorService.EMBED_LIMIT) { errorMessage = $"**You need to be a Tripple Partner to use custom embeds! Consider [donating](https://www.patreon.com/cessumdevelopment?fan_landing=true) to get access to embeds.**"; } else if (partner.MessageEmbeds.Count <= 0) { errorMessage = $"**There are no embeds to edit!**"; } else { string desc = $"Please select an embed to edit:\n\n"; List <string> items = new(); int c = 1; var buttons = new List <DiscordButtonComponent>(); foreach (DiscordEmbed f in partner.MessageEmbeds) { items.Add($"`{c}` - {f.Title}"); buttons.Add(new(ButtonStyle.Primary, c.ToString(), c.ToString())); c++; } var statusEmbed = new DiscordEmbedBuilder() .WithDescription($"{desc}{string.Join("\n", items)}") .WithColor(DiscordColor.Gold); var builder = new DiscordMessageBuilder() .WithEmbed(statusEmbed) .AddComponents(buttons); var statusMessage = await builder.SendAsync(lastButtonEvent.Channel); var addStart = await GetButtonPressAsync(interact, statusMessage); if (!addStart.Item2) { return; } var startRes = addStart.Item1; await startRes.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate); if (!int.TryParse(startRes.Id, out int index)) { errorMessage = $"**The value provided was not a number! Returning to main menu.**"; } else if (index > partner.MessageEmbeds.Count || index < 0) { errorMessage = $"**The value provided was not a valid embed! Returning to main menu.**"; } else { DiscordEmbed?oldEmbed = partner.MessageEmbeds[index - 1]; (DiscordEmbedBuilder?, string?, bool)editEnd = await GetCustomDiscordEmbedAsync(partner, lastButtonEvent, oldEmbed.Title, new(oldEmbed)); if (editEnd.Item3) { return; } if (editEnd.Item1 is null) { await RespondError(editEnd.Item2 ?? "An unknown error occurred."); return; } partner.MessageEmbeds[index - 1] = editEnd.Item1; } await statusMessage.DeleteAsync(); } break; case "remove-embed": if (partner.DonorRank < DonorService.EMBED_LIMIT) { errorMessage = $"**You need to be a Tripple Partner to use custom embeds! Consider [donating](https://www.patreon.com/cessumdevelopment?fan_landing=true) to get access to embeds.**"; } else if (partner.MessageEmbeds.Count <= 0) { errorMessage = $"**There are no embeds to remove!**"; } else { string desc = $"Please select an embed to delete:\n\n"; List <string> items = new(); int c = 1; var buttons = new List <DiscordButtonComponent>(); foreach (DiscordEmbed f in partner.MessageEmbeds) { items.Add($"`{c}` - {f.Title}"); buttons.Add(new(ButtonStyle.Primary, c.ToString(), c.ToString())); c++; } var statusEmbed = new DiscordEmbedBuilder() .WithDescription($"{desc}{string.Join("\n", items)}") .WithColor(DiscordColor.Gold); var builder = new DiscordMessageBuilder() .WithEmbed(statusEmbed) .AddComponents(buttons); var statusMessage = await builder.SendAsync(lastButtonEvent.Channel); var addStart = await GetButtonPressAsync(interact, statusMessage); if (!addStart.Item2) { return; } var startRes = addStart.Item1; if (!int.TryParse(startRes.Id, out int index)) { errorMessage = $"**The value provided was not a number! Returning to main menu.**"; await startRes.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate); } else if (index > partner.MessageEmbeds.Count || index < 0) { errorMessage = $"**The value provided was not a valid embed! Returning to main menu.**"; await startRes.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate); } else { await startRes.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, new DiscordInteractionResponseBuilder() .AddEmbed(statusEmbed .WithTitle("Partner Bot Setup - Main") .WithDescription($"**Embed removed.**"))); partner.MessageEmbeds.RemoveAt(index - 1); await Task.Delay(TimeSpan.FromSeconds(2)); } await statusMessage.DeleteAsync(); } break; case "banner": (Uri?, string?, bool)bannerRes = await GetNewPartnerBanner(lastButtonEvent); if (bannerRes.Item3) { return; } if (bannerRes.Item1 is null) { await RespondError(bannerRes.Item2 ?? "An unknown error occurred."); return; } partner.Banner = bannerRes.Item1.AbsoluteUri; break; case "color": case "colour": (DiscordColor?, string?, bool)colorRes = await GetCustomEmbedColorAsync(partner, lastButtonEvent); if (colorRes.Item3) { return; } if (colorRes.Item1 is null) { await RespondError(colorRes.Item2 ?? "An unknown error occurred."); return; } partner.BaseColor = colorRes.Item1.Value; break; case "tag": case "tags": (HashSet <string>?, string?, bool)tagRes = await UpdateTagsAsync(partner, lastButtonEvent); if (tagRes.Item3) { return; } if (tagRes.Item1 is null) { await RespondError(tagRes.Item2 ?? "An unknown error occurred."); return; } tagUpdate = tagRes.Item1; break; case "vanity": if (partner.DonorRank >= DonorService.VANITY_LIMIT) { if (partner.VanityInvite is not null) { await lastButtonEvent.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, new DiscordInteractionResponseBuilder() .AddEmbed(new DiscordEmbedBuilder() .WithDescription($"**Vanity Invite disabled!**"))); await Task.Delay(TimeSpan.FromSeconds(2)); } else { DiscordInvite?vanity; try { vanity = await this.Context.Guild.GetVanityInviteAsync(); } catch { vanity = null; } if (vanity is not null) { await lastButtonEvent.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, new DiscordInteractionResponseBuilder() .AddEmbed(new DiscordEmbedBuilder() .WithDescription($"**Vanity Invite enabled!**"))); await Task.Delay(TimeSpan.FromSeconds(2)); } else { errorMessage = $"**You do not have a vanity invite for your server!**"; } } } else { errorMessage = $"**You do not have a high enough donor rank to use vanity invites." + $" Consider [donating](https://www.patreon.com/cessumdevelopment?fan_landing=true)" + $" to use your vanity invite!**"; } break; case "get-nsfw": if (!partner.NSFW) { partner.ReceiveNSFW = !partner.ReceiveNSFW; } else { errorMessage = $"**If your server is marked NSFW you must be allwoed to receive other NSFW server advertisments." + $" Make your advertisment *not* NSFW, then use `set-nsfw` again before turning this option off with" + $" `get-nsfw`.**"; } break; case "set-nsfw": partner.NSFW = !partner.NSFW; if (partner.NSFW) { partner.ReceiveNSFW = true; } break; default: break; } isChanged = true; } while (!done); (Partner?, string)updateRes = await this._partners.UpdateOrAddPartnerAsync(ctx.Guild.Id, () => { var update = PartnerUpdater.BuildFromPartner(partner); if (channel is not null) { update.ChannelId = channel.Id; } if (tagUpdate is not null) { update.TagOverride = tagUpdate; } return(update); }); if (updateRes.Item1 is not null) { await lastButtonEvent.Interaction.EditOriginalResponseAsync( new DiscordWebhookBuilder() .AddEmbed(new DiscordEmbedBuilder() .WithTitle("Partner Bot Setup - Main") .WithColor(DiscordColor.Green) .WithDescription("Partner Setup Saved!"))); } else { await lastButtonEvent.Interaction.EditOriginalResponseAsync( new DiscordWebhookBuilder() .AddEmbed(new DiscordEmbedBuilder() .WithTitle("Partner Bot Setup - Main") .WithDescription("An error occurred while saving:\n\n```\n" + $"{updateRes.Item2}" + $"\n```") .WithColor(DiscordColor.DarkRed))); ; } }
public async Task PurgeCommandAsync(CommandContext ctx) { DSharpPlus.Interactivity.InteractivityExtension?interact = ctx.Client.GetInteractivity(); await ctx.RespondAsync("**Purging your data will delete all saved partner information then remove the bot from your server. Are you sure" + " you want to proceed? Type `yes` to purge data. Type anything else to cancel this operation.**"); DSharpPlus.Interactivity.InteractivityResult <DSharpPlus.Entities.DiscordMessage> res = await interact.WaitForMessageAsync(x => x.Author.Id == ctx.User.Id); if (res.TimedOut) { await RespondError("Time out."); } else { if (res.Result.Content.Trim().ToLower().Equals("yes")) { await this._partners.RemovePartnerAsync(ctx.Guild.Id); using var scope = this._services.CreateScope(); var db = scope.ServiceProvider.GetRequiredService <PartnerDatabaseContext>(); await RespondSuccess("Partner config purged, leaving guild.\n\n" + "Thanks for using Partner Bot!"); DiscordGuildConfiguration?guild = await db.FindAsync <DiscordGuildConfiguration>(ctx.Guild.Id); db.Remove(guild); await db.SaveChangesAsync(); await ctx.Guild.LeaveAsync(); } else { await RespondError("Aborting..."); } } }
public async Task SetupTestServers(CommandContext ctx, params DiscordGuild[] guilds) { List <string> names = new(); foreach (DiscordGuild?g in guilds) { names.Add(g.Name); } DSharpPlus.Interactivity.InteractivityExtension?interact = ctx.Client.GetInteractivity(); DiscordEmbedBuilder?embed = new DiscordEmbedBuilder() .WithColor(DiscordColor.Red) .WithTitle("Partner Test Server Setup") .WithDescription("Setting up Partner Bot Test Server. Please ensure the bot has admin on all servers. Type `continue` to start.\n\n" + "**THIS WILL DELETE ALL CONTENT FROM THE FOLLOWING GUILDS:**") .AddField("Guilds: ", string.Join(",", names)); DiscordMessage?message = await ctx.RespondAsync(embed); DSharpPlus.Interactivity.InteractivityResult <DiscordMessage> response = await interact.WaitForMessageAsync(x => x.Channel.Id == ctx.Channel.Id && x.Author.Id == ctx.Member.Id); if (response.TimedOut) { await InteractTimeout(); return; } else if (!response.Result.Content.ToLower().Equals("continue")) { await RespondError("Aborting..."); return; } var queue = new Queue <DiscordGuild>(guilds); List <DevelopmentStressTestChannel>?data = await DevelopmentStressTestDataManager.GetDataAsync(); if (data is null) { data = new(); } DiscordMessage?msg = null; while (queue.TryDequeue(out DiscordGuild? guild)) { int channelStage = 0; int webhookStage = 0; msg = await Update(ctx, guild, queue, true, channelStage, webhookStage, msg); await CleanupGuild(guild); var baseChan = new DevelopmentStressTestChannel() { GuildId = guild.Id, GuildName = Names[ThreadSafeRandom.Next(0, Names.Count)] }; await guild.ModifyAsync(x => x.Name = $"Test Server {baseChan.GuildName}"); msg = await Update(ctx, guild, queue, false, channelStage, webhookStage, msg); List <DevelopmentStressTestChannel> createdChannels = new(); List <DiscordChannel> rawChannels = new(); // build new channels int x = 1; for (int i = 0; i < 50; i++) { if (x % 5 == 0) { msg = await Update(ctx, guild, queue, false, ++channelStage, webhookStage, msg); } (DevelopmentStressTestChannel, DiscordChannel)chan = await BuildChannel(guild, baseChan); createdChannels.Add(chan.Item1); rawChannels.Add(chan.Item2); x++; await Task.Delay(TimeSpan.FromSeconds(.5)); } msg = await Update(ctx, guild, queue, false, channelStage, webhookStage, msg); // build new webhooks x = 1; int rc = 0; foreach (DevelopmentStressTestChannel?c in createdChannels) { if (x % 5 == 0) { msg = await Update(ctx, guild, queue, false, channelStage, ++webhookStage, msg); } await ApplyWebhookData(c, rawChannels[rc++]); x++; await Task.Delay(TimeSpan.FromSeconds(.5)); } // save data data.AddRange(createdChannels); } await msg.ModifyAsync(embed : new DiscordEmbedBuilder() .WithColor(DiscordColor.Orange) .WithTitle("Partner Test Server Cleanup") .WithDescription("Cleaning up test server data...") .Build()); data.RemoveAll(x => { bool found = false; foreach (DiscordClient?shard in this._client.ShardClients.Values) { if (shard.Guilds.ContainsKey(x.GuildId)) { found = true; break; } } return(!found); }); await DevelopmentStressTestDataManager.SaveDataAsync(data); await RespondSuccess("Setup Complete."); }