public async Task BotInfoAsync(ICommandContext ctx) { var embed = new EmbedBuilder { Title = "Status", Color = Color.Purple }; embed.AddField("Latest version", Utils.ToDiscordTimestamp(new FileInfo(Assembly.GetEntryAssembly().Location).LastWriteTimeUtc, Utils.TimestampInfo.None), true); embed.AddField("Last command received", Utils.ToDiscordTimestamp(StaticObjects.LastMessage, Utils.TimestampInfo.TimeAgo), true); embed.AddField("Uptime", Utils.ToDiscordTimestamp(StaticObjects.Started, Utils.TimestampInfo.TimeAgo), true); embed.AddField("Guild count", StaticObjects.Client.Guilds.Count, true); var options = new ComponentBuilder(); if (StaticObjects.IsBotOwner(ctx.User)) { options.WithSelectMenu("delCache", StaticObjects.AllGameNames.Select(x => new SelectMenuOptionBuilder(x, StaticObjects.Db.GetCacheName(x))).ToList(), placeholder: "Select a game cache to delete (require bot restart)"); } options.WithButton("Show Global Stats", "globalStats"); await ctx.ReplyAsync(embed : embed.Build(), components : options.Build(), ephemeral : true); embed.AddField("Useful links", #if NSFW_BUILD " - [Source Code](https://github.com/Xwilarg/Sanara)\n" + " - [Website](https://sanara.zirk.eu/)\n" + #endif " - [Invitation Link](https://discord.com/api/oauth2/authorize?client_id=" + StaticObjects.ClientId + "&scope=bot%20applications.commands)\n" #if NSFW_BUILD + " - [Support Server](https://discordapp.com/invite/H6wMRYV)\n" + " - [Top.gg](https://discordbots.org/bot/329664361016721408)" #endif ); embed.AddField("Credits", "Programming: [Zirk#0001](https://zirk.eu/)\n" + "With the help of [TheIndra](https://theindra.eu/)\n" #if NSFW_BUILD + "Profile Picture: [Uikoui](https://www.pixiv.net/en/users/11608780)" #endif // TODO: Can prob use current pfp for SFW version ); #if NSFW_BUILD // Get latests commits StringBuilder str = new(); var json = JsonConvert.DeserializeObject <JArray>(await StaticObjects.HttpClient.GetStringAsync("https://api.github.com/repos/Xwilarg/Sanara/commits?per_page=5")); foreach (var elem in json) { var time = Utils.ToDiscordTimestamp(DateTime.ParseExact(elem["commit"]["author"]["date"].Value <string>(), "MM/dd/yyyy HH:mm:ss", CultureInfo.InvariantCulture), Utils.TimestampInfo.None); str.AppendLine($"{time}: [{elem["commit"]["message"].Value<string>()}](https://github.com/Xwilarg/Sanara/commit/{elem["sha"].Value<string>()})"); } embed.AddField("Latest changes", str.ToString()); await ctx.ReplyAsync(embed : embed.Build(), components : options.Build()); #endif }
/// <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); }
/// <summary> /// Precondition to disable the source of an interaction. /// </summary> /// <param name="context"></param> /// <param name="commandInfo"></param> /// <param name="services"></param> /// <returns></returns> public override async Task <PreconditionResult> CheckRequirementsAsync(IInteractionContext context, ICommandInfo commandInfo, IServiceProvider services) { if (context.Interaction is not IComponentInteraction messageComponent) { return(PreconditionResult.FromError("This attribute does not work for application commands!")); } var builder = new ComponentBuilder(); var rows = ComponentBuilder.FromMessage(messageComponent.Message).ActionRows; for (int i = 0; i < rows.Count; i++) { foreach (var component in rows[i].Components) { switch (component) { case ButtonComponent button: builder.WithButton(button.ToBuilder() .WithDisabled(!button.CustomId.StartsWith("delete-message-")), i); break; case SelectMenuComponent menu: builder.WithSelectMenu(menu.ToBuilder() .WithDisabled(true), i); break; } } } try { await messageComponent.Message.ModifyAsync(x => x.Components = builder.Build()); return(PreconditionResult.FromSuccess()); } catch (Exception ex) { return(PreconditionResult.FromError(ex)); } }