/// <summary> /// Handles simple Http-apis for "reaction" commands /// /// The incoming argument 0 from context is a collection of IMember, but for later purposes /// that type is not required, as we simply use IUser's Mention property, as such converting /// down to the lower interface acceptable to allow for implicit targetting /// </summary> /// <param name="context"></param> public static async Task DoReaction(DiscordCommandContext context) { var client = context.Services.GetRequiredService <HttpClient>(); List <IUser> users = ((IUser?[])context.Arguments[0]).Where(x => x != null).ToList() !; var embed = (new LocalEmbed()) .WithColor(Program.Color); var builder = new LocalMessage(); var apiCommand = Program.ApiCommands[context.Command.Name]; // if no members are specified allow for implicit targeting via the reply system if (users.Count == 0 && context.Message.ReferencedMessage.HasValue && context.Message.ReferencedMessage.Value != null && context.Message.ReferencedMessage.Value.Author != null) { users.Add(context.Message.ReferencedMessage.Value.Author); } // prepare reaction text if needed string?text = null; if (apiCommand.Actions.Ranges.Count > 0) { text = apiCommand.Actions.GetValue(users.Count)?.Random(); } // insert the author as the first "mention" users = users.Prepend(context.Author).ToList(); // insert mentions if (text != null) { // ReSharper disable once CoVariantArrayConversion text = string.Format(text, users.Select(x => x.Mention).ToArray()); embed.WithDescription(text); } var response = await client.GetAsync(apiCommand.Url); if (response.StatusCode != HttpStatusCode.OK) { await new DiscordResponseCommandResult(context, builder.WithEmbed(embed.WithDescription("An error occurred while fetching reaction!"))); return; } // decode the json response, nothing else is supported for the time being // we also only care for one level of the response as of now. var decoded = JsonConvert.DeserializeObject <Dictionary <string, string> >(await response.Content.ReadAsStringAsync()); embed.WithImageUrl(apiCommand.GetFixedImageUrl(decoded[apiCommand.Path])); await new DiscordResponseCommandResult(context, (new LocalMessage()).WithEmbed(embed)); }
public async Task Help() { var embeds = new List <LocalEmbed>(); // normal proper commands var commands = new Dictionary <string, List <Tuple <Command, Dictionary <Type, Attribute> > > >(); // section splits var sections = new Dictionary <string, SectionAttribute>(); // extremely simple commands which will not display a description // and share a single row for display var simpleCommands = new Dictionary <SectionAttribute, List <Command> >(); // what we'll be collecting from commands var searchAttributes = new List <Type>() { typeof(SectionAttribute), typeof(SimpleCommandAttribute) }; // categorize commands by section first foreach (var command in _commands.GetAllCommands()) { var attrs = new Dictionary <Type, Attribute>(); var copy = new List <Type>(searchAttributes); var attrLists = new List <List <Attribute> >() { command.Attributes.ToList(), command.Module.Attributes.ToList() }; var hideCommand = false; foreach (var list in attrLists) { foreach (var attr in list) { if (attr.GetType() == typeof(HiddenCommandAttribute)) { hideCommand = true; break; } for (int i = copy.Count - 1; i > -1; i--) { var item = copy[i]; if (attr.GetType() == item) { attrs.Add(item, attr); copy.RemoveAt(i); } } } if (hideCommand) { break; } } if (hideCommand || !attrs.TryGetValue(typeof(SectionAttribute), out var temp)) { continue; // invalid or hidden command? } // re-cast SectionAttribute section = (SectionAttribute)temp; if (!commands.ContainsKey(section.Name)) { commands.Add(section.Name, new List <Tuple <Command, Dictionary <Type, Attribute> > >()); sections.Add(section.Name, section); } if (!attrs.ContainsKey(typeof(SimpleCommandAttribute))) { commands[section.Name].Add(new Tuple <Command, Dictionary <Type, Attribute> >(command, attrs)); } else { if (!simpleCommands.ContainsKey(section)) { simpleCommands.Add(section, new List <Command>()); } simpleCommands[section].Add(command); } } var last = sections.Last(); foreach (var attributePair in sections) { var embed = GetEmbed() .WithTitle(attributePair.Value.Name); var description = "\n"; if (attributePair.Value.Description != null) { description = attributePair.Value.Description + "\n\n=======================\n\n"; } // normal commands if (commands[attributePair.Value.Name].Count > 0) { foreach (var tuple in commands[attributePair.Value.Name]) { var name = "**" + tuple.Item1.FullAliases[0] + "**"; description += name + " " + string.Join(' ', tuple.Item1.Parameters.Select <Parameter, string>(FormatParameter) ) + "\n" + (string.IsNullOrEmpty(tuple.Item1.Description) ? "" : "> " + tuple.Item1.Description + "\n\n"); } } // simple commands if (simpleCommands.TryGetValue(attributePair.Value, out var simpleList)) { // show 7 commands in each line foreach (var batch in simpleList.Batch(7)) { description += "> " + string.Join(" ", batch.Select(x => x.FullAliases[0])) + "\n\n"; } } if (attributePair.Equals(last)) { embed.WithFooter("Made by Ly#3449, original concept by zappin#1312, version " + Program.Version); } else { // remove last newlines description = description.Substring(0, description.Length - 1); } embeds.Add(embed.WithDescription(description)); } var builder = new LocalMessage(); var lastEmbed = embeds.Last(); var addedReaction = false; foreach (var embed in embeds) { try { await Context.Author.SendMessageAsync(builder.WithEmbed(embed)); if (!embed.Equals(lastEmbed)) { await Task.Delay(500); } if (!addedReaction) { await Context.Message.AddReactionAsync(new LocalEmoji("✅")); } } catch (Exception) // in case someone has blocked dms { await EmbedReply("You seem to have dms disabled or other error occurred!"); return; } }