/// <summary> /// Handles adding a button to the component builder /// </summary> /// <param name="btn">The attribute that represents the buttons config</param> /// <param name="method">The method the attribute handles</param> /// <param name="builder">The component builder</param> public void HandleButton(ButtonAttribute btn, MethodInfo method, ComponentBuilder builder) { var id = _handlers.IdFromMethod(method); builder.WithButton(btn.Label, id, btn.Style, btn.Emote?.GetEmote(), btn.Url, btn.Disabled, btn.Row); }
/// <summary> /// The basic structure for Component /// </summary> /// <returns>An component builder with basic settings</returns> public ComponentBuilder BaseComponent() { ComponentBuilder component = new ComponentBuilder(); return(component); }
/// <summary> /// Handles adding <see cref="SelectMenuComponent"/> to the given interaction /// </summary> /// <param name="sm">The <see cref="SelectMenuAttribute"/> that represents the select menu handler</param> /// <param name="method">The method that will be triggered when handling the interaction</param> /// <param name="type">The type of the class that will handle the interaction</param> /// <param name="builder">The <see cref="ComponentBuilder"/></param> /// <param name="channel">The channel the interaction happened in</param> /// <param name="user">The user that triggered the interaction</param> /// <param name="message">The message that triggered the interaction</param> /// <returns>A task representing the completion of the request</returns> /// <exception cref="ArgumentException">Thrown when the min or max values field on the select menu are less than 1</exception> public async Task HandleSelectMenu(SelectMenuAttribute sm, MethodInfo method, Type type, ComponentBuilder builder, IChannel channel, IUser user, IMessage?message) { if (sm.MinValues < 1 || sm.MaxValues < 1) { throw new ArgumentException("Min/Max values for Select Menu must be 1 or greater.", "(Max/Min)Values"); } var id = _handlers.IdFromMethod(method); var options = new List <SelectMenuOptionBuilder>(); if (!string.IsNullOrEmpty(sm.OptionsMethod)) { options.AddRange(await MenuOptionsFromMethod(sm.OptionsMethod, type, channel, user, message)); } options.AddRange(MenuOptionsFromAttributes(method)); builder.WithSelectMenu(id, options, sm.Placeholder, sm.MinValues, sm.MaxValues, sm.Disabled, sm.Row); }
public async Task ServerInfoAsync() { // Collect guild information. var guild = Context.Guild; var textChannels = guild.TextChannels; var voiceChannels = guild.VoiceChannels; var emotes = guild.Emotes; var roles = guild.Roles; string guildIconUrl = guild.IconUrl; int staticEmotesCount = emotes.Count(emote => !emote.Animated); int animatedEmotesCount = emotes.Count(emote => emote.Animated); // Sort collection of roles to print alphabetically. var rolesList = roles.Select(role => role.Name).ToList(); rolesList.Sort(); var regionsList = await guild.GetVoiceRegionsAsync(); var regions = regionsList.Select(region => region.Name); var embed = new EmbedBuilder() .WithAuthor(guild.Name, guildIconUrl) .WithColor(Config.Value.EmbedColor) .WithImageUrl(guild.BannerUrl) .WithThumbnailUrl(guildIconUrl) .WithFooter($"Created: {guild.CreatedAt.ToString("R")}") .AddField( "Voice regions", string.Join(", ", regions)) .AddField( "ID", guild.Id.ToString(), true) .AddField( "Max Bitrate", $"{guild.MaxBitrate.ToString()} kbps", true) .AddField( "Members", guild.MemberCount.ToString(), true) .AddField( "Channels", $"{textChannels.Count.ToString()} text\n{voiceChannels.Count.ToString()} voice", true) .AddField( "Emotes", $"{staticEmotesCount.ToString()} static\n{animatedEmotesCount.ToString()} animated", true) .AddField( "Premium", $"Level {((int) guild.PremiumTier).ToString()}\n{guild.PremiumSubscriptionCount.ToString()} boosts", true) .AddField( "Roles", string.Join(", ", rolesList)) .Build(); var components = new ComponentBuilder() .WithButton("Icon direct link", style: ButtonStyle.Link, url: guildIconUrl) .Build(); await RespondAsync(embed : embed, components : components); }
public void Get_ReleaseWithMultipleComponents_ComponentsAreOrderdByBuildDefinition() { //Arrange var request = new GetReleasesHttpRequestMessageBuilder().WithShowComponentsHeader(true).Build(); var expectedRelease = new ReleaseBuilder().Build(); var expectedComponentBuilder = new ComponentBuilder().ForRelease(expectedRelease); var expectedComponentWithBuildDefinitionA = expectedComponentBuilder.WithBuildDefinition("A").Build(); var expectedComponentWithBuildDefinitionB = expectedComponentBuilder.WithBuildDefinition("B").Build(); var expectedComponentWithBuildDefinitionC = expectedComponentBuilder.WithBuildDefinition("C").Build(); var dataModel = new DataModelBuilder() .WithRelease(expectedRelease) //add components in 'random' order to check sorting of components by build definition .WithComponent(expectedComponentWithBuildDefinitionB) .WithComponent(expectedComponentWithBuildDefinitionA) .WithComponent(expectedComponentWithBuildDefinitionC) .Build(); _releaseRepositoryMock.Setup((stub) => stub.GetReleaseData(It.IsAny<string>(), It.IsAny<int>())) .Returns(dataModel); //Act dynamic result = _sut.Get(request); //Assert Assert.IsNotNull(result, "Unexpected result"); Assert.AreEqual(expectedComponentWithBuildDefinitionA.Build, result.releases[0].components[0].build, "Unexpected first component"); Assert.AreEqual(expectedComponentWithBuildDefinitionB.Build, result.releases[0].components[1].build, "Unexpected second component"); Assert.AreEqual(expectedComponentWithBuildDefinitionC.Build, result.releases[0].components[2].build, "Unexpected third component"); }
public static ComponentBuilder <TConfig, TTag> AddFeedback <TConfig, TTag>(this ComponentBuilder <TConfig, TTag> builder, string style = "zoom-out") where TConfig : BootstrapConfig where TTag : Tag { return(builder.AddCss("ladda-button").AddData("style", style)); }
public async Task <CommandResult> InviteNextPlayerAsync(Invite invite) { IAsyncEnumerable <UserInGuild> list = guildData.GetSortedList().ToAsyncEnumerable(); if (invite.InviteRole is ulong roleId) { list = list.WhereAwait(async x => { var restGuildUser = await restClient.GetGuildUserAsync(guildId, x.UserId); var hasRole = restGuildUser.RoleIds.Contains(roleId); return(hasRole == invite.IsInviteRolePositive); }); } if (!await list.AnyAsync()) { return(CommandResult.FromError($"Could not invite additional player. List is empty.")); } string message; try { message = string.Format(guildData.DMMessageFormat, invite.FormatData); } catch (Exception) { return(CommandResult.FromError("The arguments had the wrong format")); } StringBuilder warnings = new StringBuilder(); // Send invites var player = await list.FirstAsync(); player.IsInWaitingList = false; player.PlayCount++; dataContext.Update(player); dataContext.SaveChanges(); var restGuildUser = await restClient.GetGuildUserAsync(guildId, player.UserId); try { ComponentBuilder componentBuilder = new ComponentBuilder(); componentBuilder.WithButton("Yes", customId: $"joinYes;{invite.Id}"); componentBuilder.WithButton("No", customId: $"joinNo;{invite.Id}"); var userMessage = await restGuildUser.SendMessageAsync($"Are you ready to join? You have 1 minute to respond.", component : componentBuilder.Build()); invite.InvitedUsers.Add(new InvitedUser { Invite = invite, InviteTime = DateTime.Now, DmQuestionMessageId = userMessage.Id, User = player }); dataContext.Update(invite); dataContext.SaveChanges(); } catch (Exception ex) { warnings.AppendLine($"Could not invite {restGuildUser.Mention}. Exception: {ex.Message}"); } await this.dataContext.SaveChangesAsync(); return(CommandResult.FromSuccess("Players have been invited." + (warnings.Length > 0 ? "\r\n" + warnings.ToString() : ""))); }
private async Task <bool> FavEmoteGetPage(int dir, string searchTerm, int page, int rows = 4, int columns = 5, bool secondTry = false) { var message = Context.Interaction as SocketMessageComponent; var user = Context.Interaction.User; if (message.Message.Embeds.First().Author.Value.Name != $"{user.Username}#{user.Discriminator}") { Context.Interaction.RespondAsync("You did not invoke this message.", null, false, true); //Context.Interaction.DeferAsync(); return(false); } page += dir; if (page < 0) { return(false); // disable prev button on page 0 } var emoteResult = DiscordHelper.SearchEmote(searchTerm, Context.Guild.Id, page, false, rows, columns); // TODO pass debug info aswell string desc = $"Available({page * emoteResult.PageSize}-{Math.Min((page + 1) * emoteResult.PageSize, emoteResult.TotalEmotesFound)}/{emoteResult.TotalEmotesFound}) '{searchTerm}' {Environment.NewLine}**To use the emotes (Usage .<name>)**"; EmbedBuilder builder = new EmbedBuilder() { ImageUrl = emoteResult.Url, Description = desc, Color = Color.DarkRed, Title = "Image full size", Footer = new EmbedFooterBuilder() { Text = searchTerm + " Page: " + page }, ThumbnailUrl = "https://cdn.battlerush.dev/bot_xmas.png", Timestamp = DateTimeOffset.Now, Url = emoteResult.Url, }; builder.WithAuthor(Context.Interaction.User); var builderComponent = new ComponentBuilder(); try { int row = 0; int col = 0; foreach (var emote in emoteResult.EmoteList) { if (emoteResult.valid.Skip(row * columns + col).First()) { builderComponent.WithButton(emote.Value, $"emote-fav-{emote.Key}", ButtonStyle.Primary, Emote.Parse($"<:{emote.Value}:{emote.Key}>"), null, false, row); } else { builderComponent.WithButton(emote.Value, $"emote-fav-{emote.Key}", ButtonStyle.Primary, null, null, false, row); } col++; if (col == columns) { row++; col = 0; } } // Start fresh row for paging if (col > 0) { row++; } builderComponent.WithButton("Prev <", $"emote-fav-get-prev-page-{searchTerm}-{page}", ButtonStyle.Danger, null, null, page == 0, row); builderComponent.WithButton("> Next", $"emote-fav-get-next-page-{searchTerm}-{page}", ButtonStyle.Success, null, null, (page + 1) * emoteResult.PageSize > emoteResult.TotalEmotesFound, row); await message.Message.ModifyAsync(i => { i.Embed = builder.Build(); i.Components = builderComponent.Build(); }); } catch (HttpException ex) { foreach (var error in ex.Errors) { if (error.Errors.Any(i => i.Code == "BUTTON_COMPONENT_INVALID_EMOJI")) { var parts = error.Path.Split('.'); int error_row = Convert.ToInt32(Regex.Replace(parts[0], "[^0-9]", "")); int error_column = Convert.ToInt32(Regex.Replace(parts[1], "[^0-9]", "")); var brokenEmote = emoteResult.EmoteList.Skip(error_row * columns + error_column).First(); EmoteDBManager.Instance().ChangeValidStatus(brokenEmote.Key, false); } } // call yourself again to retry -> if (secondTry == false) { await FavEmoteGetPage(dir, searchTerm, (page -= dir), rows = 4, columns = 5, true); } // Some emotes may no lonver be valid -> db entry to invalidate the emote } //Context.Interaction.DeferAsync(); return(true); }
public override BaseComponent ReadJson(JsonReader reader, Type objectType, BaseComponent component, bool hasExistingValue, JsonSerializer serializer) { Console.WriteLine($"TokenType: " + reader.TokenType); if (reader.TokenType == JsonToken.StartObject) { ComponentBuilder builder = new ComponentBuilder(""); JObject @object = JObject.Load(reader); Console.WriteLine("Object: " + @object.ToString(Formatting.Indented)); if (@object.Has("text")) { builder = new ComponentBuilder(@object["text"].Value <string>()); } else if (@object.Has("translate")) { } if (@object.Has("color")) { builder.Color(TextColor.GetColor(@object["color"].Value <string>())); // component.Color = TextColor.GetColor(@object["color"].Value<string>()); //component.setColor(ChatColor.valueOf(@object["color"].getAsString().toUpperCase(Locale.ROOT))); } if (@object.Has("bold")) { builder.Bold(@object["bold"].Value <bool>()); //component.Bold = @object["bold"].Value<bool>(); } if (@object.Has("italic")) { builder.Italic(@object["italic"].Value <bool>()); //component.Italic = @object["italic"].Value<bool>(); } if (@object.Has("underlined")) { builder.Underlined(@object["underlined"].Value <bool>()); //component.Underlined = @object["underlined"].Value<bool>(); //component.setUnderlined(object.get("underlined").getAsBoolean()); } if (@object.Has("strikethrough")) { builder.Strikethrough(@object["strikethrough"].Value <bool>()); //component.Strikethrough = @object["strikethrough"].Value<bool>(); //component.setStrikethrough(object.get("strikethrough").getAsBoolean()); } if (@object.Has("obfuscated")) { builder.Obfuscated(@object["obfuscated"].Value <bool>()); // component.Obfuscated = @object["obfuscated"].Value<bool>(); //.setObfuscated(object.get("obfuscated").getAsBoolean()); } if (@object.Has("insertion")) { builder.Insertion(@object["insertion"].Value <string>()); //component.Insertion = @object["insertion"].Value<string>(); } if (@object.Has("extra")) { foreach (var extra in @object["extra"].Value <BaseComponent[]>()) { builder.Append(extra); //component.AddExtra(extra); } //component.setExtra(Arrays.<BaseComponent>asList(context.< BaseComponent[] > deserialize(@object.get("extra"), BaseComponent[].class ) ) ); } //Events if (@object.Has("clickEvent")) { var @event = @object["clickEvent"]; string rawAction = @event["action"].Value <string>(); string rawValue = @event["value"].Value <string>(); if (Enum.TryParse(rawAction, true, out ClickEvent.Action action)) { builder.ClickEvent(new ClickEvent(action, rawValue)); //component.ClickEvent = new ClickEvent(action, rawValue); } //ClickEvent e = @object.Value<ClickEvent>("clickComponent"); // e.value //ClickEvent.Action a = @event["action"].ToObject<ClickEvent.Action>(); //ClickEvent.Action a = @event["action"].tos<ClickEvent.Action>(); //string v = @event["value"].getAsString(); //component.ClickEvent = } if (@object.Has("hoverEvent")) { var @event = @object["hoverEvent"]; BaseComponent[] res; if (@event["value"].Type == JTokenType.Array) { res = @event["value"].Value <BaseComponent[]>(); } else { res = new BaseComponent[] { @event["value"].Value <BaseComponent>() }; } string rawAction = @event["action"].Value <string>(); if (Enum.TryParse(rawAction, true, out HoverEvent.Action action)) { builder.HoverEvent(new HoverEvent() { value = res, action = action }); /*component.HoverEvent = new HoverEvent() * { * value = res, * action = action * };*/ } //HoverEvent //component = he; //component = (new HoverEvent(HoverEvent.Action.valueOf( event.get("action").getAsString() // .toUpperCase(Locale.ROOT) ), res ) ); // component = builder.Create(); } component = builder.Create().First(); foreach (var c in builder.Create()) { Console.WriteLine($"{c}"); } Console.WriteLine($"Returning component: {component}"); return(component); } Console.WriteLine($"Returning null!"); // This should not happen. Perhaps better to throw exception at this point? return(null); }
public async Task <ButtonComponent> SelectButtonAsync(ComponentBuilder builder, string text = null, Embed embed = null, bool deleteWhenDone = false, TimeSpan?timeout = null, AllowedMentions allowedMentions = null) { if (string.IsNullOrWhiteSpace(text) && embed == null) { throw new ArgumentNullException($"One of {nameof(text)} or {nameof(embed)} must be non-null"); } var selectionSource = new TaskCompletionSource <ButtonComponent>(); var selectionTask = selectionSource.Task; var timeoutTask = Task.Delay(timeout ?? InteractivityService.DefaultTimeout); var components = builder.Build(); var message = await ReplyAsync(message : text, embed : embed, component : components, allowedMentions : allowedMentions).ConfigureAwait(false); async Task CheckButtonAsync(CallbackEventArgs e) { if (e.User.Id != Context.User.Id) { return; } var btn = getButton(components, e.ComponentId); selectionSource.SetResult(btn); } try { ComponentService.Register(message, CheckButtonAsync, doSave: false); var task_result = await Task.WhenAny(timeoutTask, selectionTask).ConfigureAwait(false); var result = task_result == selectionTask ? await selectionTask.ConfigureAwait(false) : null; if (deleteWhenDone) { await message.DeleteAsync().ConfigureAwait(false); } else { // disable the buttons instead var disabledBuilder = new ComponentBuilder(); int i = 0; foreach (var row in builder.ActionRows) { foreach (var btn in row.Components) { disabledBuilder.WithButton(btn.Label, btn.CustomId, btn.Style, btn.Emote, btn.Url, true, i); } i++; } await message.ModifyAsync(x => { x.Components = disabledBuilder.Build(); }); } return(result); } finally { ComponentService.Unregister(message); } }
public async Task Cdel(params string[] ags) { if (ags.Length == 0) { ags = new[] { Context.Channel.Id.ToString() } } ; var aaa = GetChannel(ags[0]); if (aaa == null) { await ReplyAsync("", false, new EmbedBuilder { Title = "Invalid channel", Description = $"`{ags}` could not be parsed as a channel!", Color = Color.Red }.WithCurrentTimestamp()); return; } var cros = Emote.Parse("<a:cros:859032986166362152>"); var tickk = Emote.Parse("<a:tick:782831523400908832>"); var gc = Guid.NewGuid(); var cb = new ComponentBuilder().WithButton("", $"{gc}Tick", ButtonStyle.Secondary, tickk) .WithButton("", $"{gc}Cros", ButtonStyle.Secondary, cros); var ram = await Context.Channel.SendMessageAsync( $"Are you sure you want to delete <#{aaa.Id}>?\nThis is a potentially destructive action.", component : cb.Build()); var cancelSource = new CancellationTokenSource(); cancelSource.CancelAfter(15000); var Interaction = await InteractionHandler.NextButtonAsync( k => k.Data.CustomId.Contains(gc.ToString()) && k.User.Id == Context.User.Id, cancelSource.Token); if (Interaction == null) { await Context.Channel.SendMessageAsync("No response received!"); } else { var isTick = Interaction.Data.CustomId.Contains("Tick"); await Interaction.AcknowledgeAsync(); if (!isTick) { await Context.Channel.SendMessageAsync("", false, new EmbedBuilder { Title = "Alright then...", Color = Blurple, ImageUrl = "https://i.imgur.com/RBC7KUt.png" }.WithCurrentTimestamp().Build()); return; } await aaa.DeleteAsync(); try { await Context.Channel.SendMessageAsync(embed : new EmbedBuilder { Title = "Deleted Channel Successfully", Description = $"Channel `#{aaa.Name}` was deleted!", Color = Blurple }.WithCurrentTimestamp().Build()); } catch { Console.WriteLine("Ch del'd"); } } } }
public static async Task <RestUserMessage> Send(this AbbybotCommandArgs arg, StringBuilder sb, ComponentBuilder comp) { return((sb != null)? await arg.channel.SendMessageAsync(text : sb.ToString(), components : comp?.Build()):null); }
public void Get_OverviewWithSingleItems() { //Arrange var request = new GetReleasesHttpRequestMessageBuilder().Build(); var now = DateTime.Now; var expectedPath = new ReleasePathBuilder().Build(); var expectedComponent = new ComponentBuilder().Build(); var expectedOverviewStage = new OverviewStageBuilder().ForReleasePath(expectedPath).Build(); var expectedOverviewStageDetails = new OverviewStageDetailsBuilder().ForOverviewStage(expectedOverviewStage).Build(); var dataModel = new OverviewDataModelBuilder() .WithLastRefresh(now) .WithReleasePath(expectedPath) .WithComponent(expectedComponent) .WithOverviewStage(expectedOverviewStage) .WithOverviewStageDetails(expectedOverviewStageDetails) .Build(); _releaseRepositoryMock.Setup((stub) => stub.GetReleaseOverviewData(It.IsAny<string>())) .Returns(dataModel); //Act dynamic result = _sut.Get(request); //Assert Assert.IsNotNull(result, "Unexpected result"); Assert.IsInstanceOfType(result.applications, typeof(List<dynamic>), "Unexpected type for applications collection"); List<dynamic> actualApplications = (List<dynamic>)result.applications; Assert.AreEqual(1, actualApplications.Count, "Unexpected number of releasePaths/applications"); AssertDynamicCollectionContainsReleasePath(actualApplications, expectedPath); var actualStage = actualApplications.First(); List<dynamic> actualStages = (List<dynamic>)actualApplications.First().stages; Assert.AreEqual(1, actualStages.Count, "Unexpected number of releasePaths/applications"); AssertDynamicCollectionContainsStage(actualStages, expectedOverviewStage); }
// Search Rotten Tomatoes for movies and create a selection public static async Task SearchRottenTomatoes(SocketSlashCommand command) { // Get our input from the interaction var search = command.Data.Options.ElementAt(0).Value.ToString(); // Make a list of results var resultItems = new List <SearchResultItem>(); // Get the website html var data = await WebUtils.DownloadString($"https://www.rottentomatoes.com/search?search={search}"); //If there's no result, tell the user and then stop. if (data.Contains("Sorry, no results found for")) { await command.FollowupAsync(embed : new EmbedBuilder() .WithTitle("Rotten Tomatoes Search") .WithDescription($"Sorry, no results were found for \"{search}\"\n\nTry reformatting your search if the title contains colons, hyphens, etc.") .WithColor(EmbedUtils.Red) .Build()); return; } // Slim down the data data = data .CutBefore( "<search-page-result slot=\"movie\" skeleton=\"panel\" type=\"movie\" data-qa=\"search-result\">") .CutBeforeAndAfter("<ul slot=\"list\">", "</ul>"); do { var temp = data.CutAfter("</search-page-media-row>"); resultItems.Add(new SearchResultItem(new Movie(temp))); data = data.CutBefore("</search-page-media-row>"); } while (data.Contains("search-page-media-row")); var buttons = new ComponentBuilder(); for (int i = 0; i < (resultItems.Count <= 5 ? resultItems.Count : 5); i++) { var text = $"{resultItems[i].Movie.CriticScore} {resultItems[i].Movie.Name} ({resultItems[i].Movie.Year})"; // Decode the HTML text = HttpUtility.HtmlDecode(text); // Button Labels can only be 80 characters if (text.Length > 80) { text = $"{text.Substring(0, 77)}..."; } var customId = resultItems[i].Movie.Url.CutBefore("/m/"); // Custom IDs can only be 100 characters (skip it otherwise) if (customId.Length > 100) { continue; } buttons.WithButton(text, customId: customId, ButtonStyle.Danger, row: i, emote: Emote.Parse(resultItems[i].Movie.CriticScoreIcon)); } await command.FollowupAsync("Please select a result or search again.", component : buttons.Build()); }
private async Task ActivityMessageReceivedAsync(IMessage message) { var command = message.Content.ToLower(); switch (command) { case "!швидка активність": { var builder = new EmbedBuilder() .WithColor(new Color(0xFFFFFF)) .WithDescription("Швидко зберіться у активність на найближчий час"); var menuBuilder = new SelectMenuBuilder() .WithPlaceholder("Оберіть активність") .WithCustomId("QuickActivitySelector") .WithMinValues(1).WithMaxValues(1) .WithOptions(Activity.QuickActivityTypes.Select(x => new SelectMenuOptionBuilder { Label = Translation.ActivityNames[x][0], Value = $"QuickActivity_{x}", Emote = Emote.Parse(CommonData.DiscordEmoji.Emoji.GetActivityEmoji(x)) }).ToList()); var component = new ComponentBuilder() .WithSelectMenu(menuBuilder); await message.Channel.SendMessageAsync(embed : builder.Build(), components : component.Build()); await ServiceCommandsManager.DeleteMessageAsync(message); } break; case "!швидкий рейд": { var builder = new EmbedBuilder() .WithColor(new Color(0xFFFFFF)) .WithDescription("Швидко зберіть рейд на найближчий час"); var menuBuilder = new SelectMenuBuilder() .WithPlaceholder("Оберіть рейд") .WithCustomId("QuickActivitySelector") .WithMinValues(1).WithMaxValues(1) .WithOptions(Activity.ActivityRaidTypes.Select(x => new SelectMenuOptionBuilder { Label = Translation.ActivityRaidTypes[x], Value = $"QuickRaid_{x}", Emote = Emote.Parse(CommonData.DiscordEmoji.Emoji.GetActivityRaidEmoji(x)) }).ToList()); var component = new ComponentBuilder() .WithSelectMenu(menuBuilder); await message.Channel.SendMessageAsync(embed : builder.Build(), components : component.Build()); await ServiceCommandsManager.DeleteMessageAsync(message); } break; case "!допомога": { var helpEmbeds = new BotCommands.SlashCommands.OrganizeActivity().HelpEmbeds; await message.Channel.SendMessageAsync(embeds : helpEmbeds); } break; case "!скасувати": { var msgId = message?.Reference?.MessageId.Value; if (msgId is not null) { await _activityManager.DisableActivityAsync(msgId.Value, message.Author.Id); await ServiceCommandsManager.DeleteMessageAsync(message); } } break; case string c when c.StartsWith("!передати"): { var msgId = message?.Reference?.MessageId.Value; if (msgId is not null && message.MentionedUserIds.Count == 2) { var receiverID = message.MentionedUserIds.Last(); await _activityManager.UserTransferPlaceAsync(msgId.Value, message.Author.Id, receiverID); await ServiceCommandsManager.DeleteMessageAsync(message); } } break; case string c when c.StartsWith("!перенести "): { var msgId = message?.Reference?.MessageId.Value; if (msgId is not null) { try { var date = DateTime.ParseExact(command.Replace("!перенести ", string.Empty), "d.M-H:m", CultureInfo.CurrentCulture); if (date < DateTime.Now) { date = date.AddYears(1); } await _activityManager.RescheduleActivityAsync(msgId.Value, message.Author.Id, date.ToUniversalTime()); await ServiceCommandsManager.DeleteMessageAsync(message); } catch { } } } break; case string c when c.StartsWith("!зарезервувати"): { var msgId = message?.Reference?.MessageId.Value; if (msgId is not null) { await _activityManager.UsersSubscribeAsync(msgId.Value, message.Author.Id, message.MentionedUserIds.Skip(1)); await ServiceCommandsManager.DeleteMessageAsync(message); } } break; case string c when c.StartsWith("!виключити"): { var msgId = message?.Reference?.MessageId.Value; if (msgId is not null) { await _activityManager.UsersUnSubscribeAsync(msgId.Value, message.Author.Id, message.MentionedUserIds.Skip(1)); await ServiceCommandsManager.DeleteMessageAsync(message); } } break; case string c when c.StartsWith("!змінити "): { var msgId = message?.Reference?.MessageId.Value; if (msgId is null) { return; } try { var action = message.Content[9..];
private async Task ActivitySelectMenuExecutedAsync(SocketMessageComponent component) { switch (component.Data.CustomId) { case "QuickActivitySelector": { var builder = new EmbedBuilder() .WithColor(new Color(0xFFFFFF)) .WithDescription("Оберіть зручний час"); var menuBuilder = new SelectMenuBuilder() .WithPlaceholder("Оберіть час") .WithCustomId(string.Join(',', component.Data.Values)) .WithMinValues(1).WithMaxValues(1); var startDate = DateTime.Now; var endDate = startDate.AddHours(12); var tmpDate = startDate.AddMinutes(30); while (tmpDate < endDate) { menuBuilder = menuBuilder.AddOption(tmpDate.ToString("dd.MM HH:mm"), tmpDate.ToString("dd.MM_HH:mm")); tmpDate = tmpDate.AddMinutes(30); } var componentBuilder = new ComponentBuilder() .WithSelectMenu(menuBuilder); await component.RespondAsync(embed : builder.Build(), components : componentBuilder.Build(), ephemeral : true); } break; case string c when c.StartsWith("QuickActivity_"): { var raid = new ActivityContainer() { ChannelID = component.Channel.Id, ActivityType = Enum.Parse <BungieSharper.Entities.Destiny.HistoricalStats.Definitions.DestinyActivityModeType>(c.Split('_')[1]), PlannedDate = DateTime.ParseExact(string.Join(',', component.Data.Values), "dd.MM_HH:mm", CultureInfo.CurrentCulture), ActivityName = null, Description = null, Users = new ulong[] { component.User.Id } }; await component.DeferAsync(); await InitActivityAsync(raid); } break; case string c when c.StartsWith("QuickRaid_"): { var raid = new ActivityContainer() { ChannelID = component.Channel.Id, ActivityType = BungieSharper.Entities.Destiny.HistoricalStats.Definitions.DestinyActivityModeType.Raid, PlannedDate = DateTime.ParseExact(string.Join(',', component.Data.Values), "dd.MM_HH:mm", CultureInfo.CurrentCulture), ActivityName = c.Split('_')[1], Description = null, Users = new ulong[] { component.User.Id } }; await component.DeferAsync(); await InitActivityAsync(raid); } break; default: break; } }
public static ComponentBuilder <TConfig, TTag> AddData <TConfig, TTag>(this ComponentBuilder <TConfig, TTag> builder, string name, string data) where TConfig : BootstrapConfig where TTag : Tag => builder.AddAttribute("data-" + name, data);
public static ComponentBuilder <TConfig, TComponent> RenderIf <TConfig, TComponent>(this ComponentBuilder <TConfig, TComponent> builder, bool condition) where TConfig : BootstrapConfig where TComponent : Component { builder.Component.Render = condition; return(builder); }
public async Task <CommandResponse> Process(IDiscordBotContext context) { if (context.Interaction is SocketSlashCommand slashCommand) { var settings = SettingsConfig.GetSettings(context.GuildChannel.Guild.Id); if (settings.SelfRoles.Count > 0) { var roles = context.GuildChannel.Guild.Roles.OrderByDescending(r => r.Position).Where(r => settings.SelfRoles.ContainsKey(r.Id)); var roleCount = roles.Count(); if (roleCount > SlashCommandBuilder.MaxOptionsCount) { await slashCommand.RespondAsync($"Too many roles to display in a menu. Complain to management. Max is {SlashCommandBuilder.MaxOptionsCount}.", ephemeral : true); } else if (roleCount > 0) { var menuBuilder = new SelectMenuBuilder() .WithPlaceholder("Select a role") .WithCustomId("role") .WithMinValues(0) .WithMaxValues(roleCount); foreach (var role in roles) { menuBuilder.AddOption(role.Name, role.Id.ToString(), null, string.IsNullOrEmpty(role.Emoji.Name) ? null : role.Emoji); } if (roleCount == 1) { menuBuilder.AddOption("[clear role]", "clear"); } var component = new ComponentBuilder().WithSelectMenu(menuBuilder).Build(); await slashCommand.RespondAsync("choose a role", components : component, ephemeral : true); } } else { await slashCommand.RespondAsync("No roles are self assignable", ephemeral : true); } return(new CommandResponse { IsHandled = true }); } if (context.Message.Channel is SocketGuildChannel guildChannel) { var settings = SettingsConfig.GetSettings(guildChannel.Guild.Id.ToString()); var roles = guildChannel.Guild.Roles.OrderByDescending(r => r.Position).Where(r => settings.SelfRoles.ContainsKey(r.Id)).Select(r => $"``{r.Name.Replace("`", @"\`")}``"); var multiText = new List <string>(); var sb = new StringBuilder(); sb.Append("The following roles are available to self-assign: "); foreach (var role in roles) { if (sb.Length + role.Length + 2 < DiscordConfig.MaxMessageSize) { sb.Append($"{role}, "); } else { multiText.Add(sb.ToString()); sb.Clear(); sb.Append($"{role}, "); } } multiText.Add(sb.ToString()); return(new CommandResponse { MultiText = multiText }); } return(new CommandResponse { Text = "role command does not work in private channels" }); }
public static TConfig GetConfig <TConfig, TComponent>(this ComponentBuilder <TConfig, TComponent> builder) where TConfig : BootstrapConfig where TComponent : Component { return(builder.Config); }
public async Task <(CommandResult commandResult, Invite?invite)> GetInvite(string[] arguments, int numberOfPlayers, ulong?inviteRole = null, bool?isInviteRolePositive = null, bool removeFromList = true) { IAsyncEnumerable <UserInGuild> asyncList = guildData.GetSortedList().ToAsyncEnumerable(); if (inviteRole is ulong roleId) { asyncList = asyncList.WhereAwait(async x => { var restGuildUser = await restClient.GetGuildUserAsync(guildId, x.UserId); var hasRole = restGuildUser.RoleIds.Contains(roleId); return(hasRole == isInviteRolePositive); }); } var list = await asyncList.ToListAsync(); if (list.Count < numberOfPlayers) { return(CommandResult.FromError($"Did not send invites. There are only {list.Count} players in the list."), null); } string message; try { message = string.Format(guildData.DMMessageFormat, arguments); } catch (Exception) { return(CommandResult.FromError("The arguments had the wrong format"), null); } var invite = new Invite { FormatData = arguments, Guild = guildData, InvitedUsers = new List <InvitedUser>(), InviteTime = DateTime.Now, NumberOfInvitedUsers = numberOfPlayers, InviteRole = inviteRole, IsInviteRolePositive = isInviteRolePositive }; dataContext.Invites.Add(invite); dataContext.SaveChanges(); StringBuilder warnings = new StringBuilder(); // Send invites for (int i = 0; i < numberOfPlayers; i++) { var player = list[i]; player.IsInWaitingList = false; player.PlayCount++; dataContext.Update(player); dataContext.SaveChanges(); var restGuildUser = await restClient.GetGuildUserAsync(guildId, player.UserId); try { ComponentBuilder componentBuilder = new ComponentBuilder(); componentBuilder.WithButton("Yes", customId: $"joinYes;{invite.Id}"); componentBuilder.WithButton("No", customId: $"joinNo;{invite.Id}"); var userMessage = await restGuildUser.SendMessageAsync($"Are you ready to join? You have 1 minute to respond.", component : componentBuilder.Build()); InvitedUser invitedUser = new InvitedUser { Invite = invite, InviteTime = DateTime.Now, DmQuestionMessageId = userMessage.Id, User = player }; dataContext.InvitedUsers.Add(invitedUser); } catch (Exception ex) { warnings.AppendLine($"Could not invite {restGuildUser?.Mention ?? player.Name}. Exception: {ex.Message}"); } } this.dataContext.Update(invite); await this.dataContext.SaveChangesAsync(); return(CommandResult.FromSuccess("Players have been invited." + (warnings.Length > 0 ? "\r\n" + warnings.ToString() : "")), invite); }
public static Component GetComponent(this ComponentBuilder builder) { return(builder.GetComponent()); }
protected override void OnStart(TextWriter writer) { // Set column classes if we're horizontal if (AutoColumns) { ComponentBuilder <BootstrapConfig, FormGroup> builder = GetBuilder(this); Form form = GetComponent <Form>(); if ((form != null && form.Horizontal && (!Horizontal.HasValue || Horizontal.Value)) || (Horizontal.HasValue && Horizontal.Value)) { int labelWidth = form == null ? Config.DefaultFormLabelWidth : form.DefaultLabelWidth; // Set label column class if (_label != null && !_label.CssClasses.Any(x => x.StartsWith("col-"))) { _label.SetColumnClass(Config, "col-md-", labelWidth); } // Add column classes to this (these will get moved to a wrapper later in this method) if (!CssClasses.Any(x => x.StartsWith("col-"))) { builder.SetMd(Config.GridColumns - labelWidth); // Also need to add an offset if no label if (_label == null) { builder.SetMdOffset(labelWidth); } } } else if (form != null && form.Horizontal) { // If the form is horizontal but we requested not to be, create a full-width column wrapper builder.SetMd(Config.GridColumns); _columnWrapperBeforeLabel = true; } } // Move any grid column classes to a container class if (CssClasses.Any(x => x.StartsWith("col-"))) { _columnWrapper = GetHelper().Element("div").AddCss(CssClasses.Where(x => x.StartsWith("col-")).ToArray()).Component; } CssClasses.RemoveWhere(x => x.StartsWith("col-")); base.OnStart(writer); // Write the column wrapper first if needed if (_columnWrapperBeforeLabel && _columnWrapper != null) { _columnWrapper.Start(writer); } // Write the label if (_label != null) { _label.StartAndFinish(writer); } // Write the column wrapper if (!_columnWrapperBeforeLabel && _columnWrapper != null) { _columnWrapper.Start(writer); } // Add the feedback icon as a final child of either this or the wrapper if (Icon != Icon.None) { Component icon = GetHelper().Icon(Icon).AddCss(Css.FormControlFeedback).Component; if (_columnWrapper == null) { AddChildAtEnd(icon); } else { _columnWrapper.AddChildAtEnd(icon); } } }
public static BootstrapHelper <TConfig, CanCreate> GetHelper <TConfig, TComponent>(this ComponentBuilder <TConfig, TComponent> builder) where TConfig : BootstrapConfig where TComponent : Component { return(builder.GetHelper()); }
public void Get_ShowComponentsHeaderIsTrue_ComponentReturned() { //Arrange var requestWithShowComponentsHeaderIsTrue = new GetReleasesHttpRequestMessageBuilder() .WithShowComponentsHeader(true) .Build(); var expectedRelease = new ReleaseBuilder().Build(); var expectedComponent = new ComponentBuilder().ForRelease(expectedRelease).Build(); var dataModel = new DataModelBuilder() .WithRelease(expectedRelease) .WithComponent(expectedComponent) .Build(); _releaseRepositoryMock.Setup((stub) => stub.GetReleaseData(It.IsAny<string>(), It.IsAny<int>())) .Returns(dataModel); //Act dynamic result = _sut.Get(requestWithShowComponentsHeaderIsTrue); //Assert Assert.IsNotNull(result, "Unexpected result"); var actualRelease = result.releases[0]; Assert.IsInstanceOfType(actualRelease.components, typeof(List<dynamic>), "Unexpected type for components collection"); Assert.AreEqual(1, actualRelease.components.Count, "Unexpected number of components for release"); Assert.AreEqual(expectedComponent.Build, actualRelease.components[0].build); }
private async Task OnMusicPlayerUpdateAsync(ulong?messageID) { if (messageID is null) { return; } IMessageChannel channel = _client.GetChannel(_musicChannelIDs[0]) as IMessageChannel; var queue = _musicPlayer.Queue.SkipWhile(x => !x.isCurrent).Take(4).Select(x => x.audio); var first = queue.FirstOrDefault(); if (first is null) { return; } var thumbnail = first.CoverURL; var fields = new List <EmbedFieldBuilder> { new EmbedFieldBuilder { IsInline = false, Name = "Зараз відтворюється", Value = $"[{first.Duration.GetAudioDuration()}] *{first.Title}*", } }; var next = queue.Skip(1); if (next.Count() > 0) { fields.Add(new EmbedFieldBuilder { IsInline = false, Name = "Далі у черзі", Value = $"{string.Join('\n', next.Select(x => $"[{x.Duration.GetAudioDuration()}] *{x.Title}*"))}" }); } (var custId, var emoji) = _musicPlayer.IsPlaying ? ("MusicPlayerPause", Emote.Parse(CommonData.DiscordEmoji.Emoji.MusicPause)) : ("MusicPlayerContinue", Emote.Parse(CommonData.DiscordEmoji.Emoji.MusicContinue)); var builder = new EmbedBuilder() .WithColor(0x3BA55D) .WithThumbnailUrl(thumbnail) .WithFields(fields); var component = new ComponentBuilder() .WithButton(customId: "MusicPlayerShuffle", style: ButtonStyle.Success, emote: Emote.Parse(CommonData.DiscordEmoji.Emoji.MusicShuffle)) .WithButton(customId: "MusicPlayerPrevious", style: ButtonStyle.Success, emote: Emote.Parse(CommonData.DiscordEmoji.Emoji.MusicPrevious)) .WithButton(customId: custId, style: ButtonStyle.Success, emote: emoji) .WithButton(customId: "MusicPlayerNext", style: ButtonStyle.Success, emote: Emote.Parse(CommonData.DiscordEmoji.Emoji.MusicNext)) .WithButton(customId: "MusicPlayerStop", style: ButtonStyle.Success, emote: Emote.Parse(CommonData.DiscordEmoji.Emoji.MusicStop)); try { await channel.ModifyMessageAsync(messageID.Value, msg => { msg.Embed = builder.Build(); msg.Components = component.Build(); }); } catch { } }