public async Task ExcludeChannel(CommandContext ctx, string command) { if (await Permissions.HandlePermissionsCheck(ctx) && command.Equals("list")) { // Check if there are even any excluded channels. if (Program.Settings.ExcludedChannels.Count > 0) { var stringBuilder = new StringBuilder(); stringBuilder.AppendJoin('\n', Program.Settings.ExcludedChannels.Select(a => Generics.GetChannelMention(a))); await ctx.RespondAsync( embed : Generics.GenericEmbedTemplate( color: Generics.NeutralColor, description: Generics.NeutralDirectResponseTemplate( mention: ctx.Member.Mention, body: $"here are the excluded channels:\n{stringBuilder.ToString()}"), thumbnail: Generics.URL_SPEECH_BUBBLE, title: @"Excluded channels")); } else { await ctx.RespondAsync( embed : Generics.GenericEmbedTemplate( color: Generics.NeutralColor, description: Generics.NeutralDirectResponseTemplate( mention: ctx.Member.Mention, body: @"there are no excluded channels."), thumbnail: Generics.URL_SPEECH_BUBBLE, title: @"Excluded channels")); } } }
// Note: not actually an embed internal static async Task RoleEmbedCreate(CommandContext ctx, DiscordChannel channel, string title, DiscordEmoji emoji, DiscordRole role) { if (title.Length > 0) { DiscordMessage roleMessage = await channel.SendMessageAsync( content : String.Format("{0}\n{1} {2}", arg0: title, arg1: EmojiConverter.GetEmojiString(emoji), arg2: role.Mention)); var a = roleMessage.CreateReactionAsync(emoji); var b = AddMessageToDatabase(roleMessage.Id, role, emoji); await Task.WhenAll(a, b); await ctx.RespondAsync( embed : Generics.GenericEmbedTemplate( color: Generics.NeutralColor, description: $"Tasks:\nCreate Reaction Success: {a.IsCompletedSuccessfully}\n" + $"Database Success: {a.IsCompletedSuccessfully}", title: @"Create new embed")); } else { await GenericResponses.HandleInvalidArguments(ctx); } }
/// <summary>Remove a reminder if it exists.</summary> public static async Task RemoveReminder(CommandContext ctx, Reminder reminder) { // It's a reminder, so let's remove it. // Let's build the command. using var command = new SqliteCommand(BotDatabase.Instance.DataSource) { CommandText = QQ_RemoveReminder }; SqliteParameter a = new SqliteParameter("$id", reminder.OriginalMessageId.ToString()) { DbType = DbType.String }; command.Parameters.Add(a); // Now that we have the old reminder, let's remove the old one from the database. await BotDatabase.Instance.ExecuteNonQuery(command); // Now let's respond. var discordEmbedBuilder = new DiscordEmbedBuilder(Generics.GenericEmbedTemplate( color: Generics.PositiveColor, description: Generics.PositiveDirectResponseTemplate( mention: ctx.Member.Mention, @"I able to remove the reminder you gave me!"), thumbnail: Generics.URL_REMINDER_DELETED, title: @"Removed reminder")); DateTimeOffset dto = DateTimeOffset.FromUnixTimeSeconds(reminder.Time * 60); // The reminder's DTO. TimeSpan remainingTime = dto.Subtract(DateTimeOffset.UtcNow); // The remaining time left for the reminder. string originalAuthorMention = Generics.GetMention(reminder.User); discordEmbedBuilder.AddField(@"User", originalAuthorMention, true); discordEmbedBuilder.AddField(@"Time (UTC)", dto.ToString(Generics.DateFormat), true); discordEmbedBuilder.AddField(@"Notification Identifier", reminder.OriginalMessageId.ToString(), false); if (GetUsersToNotify(reminder.UsersToNotify, out string mentionsString)) { discordEmbedBuilder.AddField(@"Users to mention", mentionsString, false); } discordEmbedBuilder.AddField(@"Remaining time", Generics.GetRemainingTime(dto), false); discordEmbedBuilder.AddField(@"Message", reminder.Text, false); // Send the response. await ctx.Channel.SendMessageAsync(embed : discordEmbedBuilder); }
internal static async Task RoleEmbedAppendRole(CommandContext ctx, DiscordChannel channel, ulong messageId, DiscordEmoji emoji, DiscordRole role) { var a = CheckEmoteMessageExists(messageId, emoji); var b = channel.GetMessageAsync(messageId); await Task.WhenAll(a, b); bool emoteExistsAlready = a.Result; DiscordMessage message = b.Result; // Check if that role is already on this message. if (!emoteExistsAlready) { // It does not, so let's continue. var c = message.ModifyAsync(String.Format("{0}\n{1} {2}", arg0: message.Content, arg1: EmojiConverter.GetEmojiString(emoji), arg2: role.Mention)); var d = message.CreateReactionAsync(emoji); var e = AddMessageToDatabase(messageId, role, emoji); await Task.WhenAll(c, d, e); await ctx.RespondAsync( embed : Generics.GenericEmbedTemplate( color: Generics.NeutralColor, description: $"Tasks:\nEdit Success: {c.IsCompletedSuccessfully}\n" + $"Create Reaction Success: {d.IsCompletedSuccessfully}\n" + $"Database Success: {e.IsCompletedSuccessfully}", title: @"Add new roles onto embed")); } else { await ctx.RespondAsync( embed : Generics.GenericEmbedTemplate( color: Generics.NegativeColor, description: Generics.NegativeDirectResponseTemplate( mention: ctx.Member.Mention, body: $"that message already has emote {EmojiConverter.GetEmojiString(emoji)} on it..."))); } }
public async Task GetUserInfo(CommandContext ctx, DiscordMember member) { const string RECENT_MSG = @"In the last minute..."; // Check if the user can use commands. if (await Permissions.HandlePermissionsCheck(ctx)) { await ctx.Channel.TriggerTypingAsync(); if (ctx.Guild.Members.ContainsKey(member.Id)) { // This member exists in the guild. // DEB! var deb = Generics.GenericEmbedTemplate( color: Generics.NeutralColor, description: Generics.NeutralDirectResponseTemplate( mention: ctx.Member.Mention, body: $"here's some info about that user!"), title: @"User Info", thumbnail: member.AvatarUrl); deb.AddField(@"Mention", member.Mention, true); deb.AddField(@"Username", $"{member.Username}#{member.Discriminator}", true); deb.AddField(@"Joined Discord", Generics.GetRemainingTime(GetJoinedDiscordTime(member.Id), false, RECENT_MSG, @"ago")); deb.AddField($"Joined {ctx.Guild.Name}", Generics.GetRemainingTime(member.JoinedAt, false, RECENT_MSG, @"ago")); await ctx.Channel.SendMessageAsync(embed : deb); } else { // This member does not exist in the guild. await ctx.Channel.SendMessageAsync( embed : Generics.GenericEmbedTemplate( color: Generics.NegativeColor, description: @"Unable to find that user...", thumbnail: member.AvatarUrl, title: @"Cannot get user info")); } // end else } // end if } // end method
internal static async Task RoleEmbedRemoveRole(CommandContext ctx, DiscordChannel channel, ulong messageId, DiscordEmoji emoji) { var a = channel.GetMessageAsync(messageId); var b = CheckEmoteMessageExists(messageId, emoji); await Task.WhenAll(a, b); DiscordMessage message = a.Result; bool messageHasEmote = b.Result; // Check if the message actually has that emote. if (messageHasEmote) { // It does, so let's query the database for everything that should be in the message. EmojiData emojiRemove = new EmojiData(emoji); RoleInfo[] roleInfos = await GetMessageEmotes(messageId); string botComments = String.Empty; var c = RemoveRow(messageId, emojiRemove.Value); await Task.WhenAll(c); // Let's check if this is the message's only react. if (roleInfos.Length == 1) { // It is, so let's delete the message as well. await message.DeleteAsync(); botComments = @"Additionally, the message was deleted because you deleted its only react."; } else { // It's not the only react, so let's rebuild the message string. // Get the first line of the content. var stringBuilder = new StringBuilder( new string(message.Content.TakeWhile(a => a != '\n').ToArray())); stringBuilder.Append('\n'); foreach (var roleInfo in roleInfos) { // Check if this is the emoji we want to remove. if (!roleInfo.EmojiData.Equals(emojiRemove)) { // It's not the emoji we want to remove, so let's add it to the stringbuilder. DiscordRole role = ctx.Guild.GetRole(roleInfo.RoleId); string emojiString = EmojiConverter.GetEmojiString( emoji: EmojiConverter.GetEmoji( cl: ctx.Client, data: roleInfo.EmojiData)); stringBuilder.AppendLine($"{role.Mention} {emojiString}"); } // end if } // end foreach var d = message.ModifyAsync(stringBuilder.ToString()); var e = message.DeleteReactionsEmojiAsync(emoji); await Task.WhenAll(d, e); await ctx.RespondAsync( embed : Generics.GenericEmbedTemplate( color: Generics.NeutralColor, description: $"Tasks:\nMessage Edit Success: {d.IsCompletedSuccessfully || e.IsCompletedSuccessfully}\n" + $"Database Check Success: {b.IsCompletedSuccessfully}\n" + $"Database Delete Success: {c.IsCompletedSuccessfully}" + (botComments.Length > 0 ? $"\n{botComments}" : String.Empty), title: @"Add new roles onto embed")); } // end else } // end if else { // It doesn't have the emote we want to remove, so let's notify the user. await ctx.RespondAsync( embed : Generics.GenericEmbedTemplate( color: Generics.NegativeColor, description: Generics.NegativeDirectResponseTemplate( mention: ctx.Member.Mention, body: $"that message doesn't have emote {EmojiConverter.GetEmojiString(emoji)} on it..."))); } }
public static async Task AddReminder(CommandContext ctx, string args) { // Firstly get all the matches. MatchCollection regexMatches = DateRegex.Matches(args); BitArray regexCoverage = new BitArray(args.Length); var dto = ctx.Message.CreationTimestamp; List <ulong> mentions = new List <ulong>(); // String processing - find the message and get the reminder end date. // To find what's not a date, we simply look for the first character that isn't in the boundaries of a Regex match. // // Structure of a possible string: // // Date String | Message String // DATE, DATE, DATE, DATE | message // // Beyond the Date String we want to stop processing time information as people may reference time in the message string, so we don't // erronously want that data added to the date string. // Populate the regexCoverage... foreach (Match match in regexMatches) { for (int i = match.Index; i < match.Index + match.Length; i++) { regexCoverage[i] = true; } } // So I want to explain what I'm about to do here. Every value in regexCoverage[] indicates if that's part of the initial time // string. We want to use it to determine if something is a message or a time value, so if at any point, we run into something that // isn't a time string, we want to set every instance thereafter as false so we know it's part of a message. if (regexMatches.Count > 0) { bool value = regexCoverage[0]; for (int k = 1; k < regexCoverage.Count; k++) { if (!IsWhitespace(args[k])) { if (!regexCoverage[k] && value) { value = false; } if (!value) { regexCoverage[k] = value; } } } } // We need to figure out where the date string ends. string messageString = String.Empty; int dateEndIndex = 0; bool messageFound = false; while (dateEndIndex < regexCoverage.Length && !messageFound) { char stringChar = args[dateEndIndex]; bool inRegexBoundaries = regexCoverage[dateEndIndex]; // This checks to see if the character is non-white-space and outside of any RegEx boundaries. messageFound = !IsWhitespace(stringChar) && !inRegexBoundaries; // If not found, continue; otherwise, keep incrementing. if (!messageFound) { dateEndIndex++; } } // If we aren't going out of bounds, let's set the string to this. if (dateEndIndex < regexCoverage.Length) { messageString = args.Substring(dateEndIndex); } // Get date information foreach (Match match in regexMatches) { // Only try to exclude Message String date information if a message string was found. if (!messageFound || (regexCoverage[match.Index] && regexCoverage[match.Index + match.Length - 1])) { InterpretTime(match.Groups[1].Value, match.Groups[2].Value, ref dto); } } // Get mentions foreach (DiscordUser user in ctx.Message.MentionedUsers) { ulong id = user.Id; if (!user.IsBot && !mentions.Contains(id)) { mentions.Add(id); } } // At this point, now we have the DateTimeOffset describing when this reminder needs to be set off, and we have a message string if // any. So now we just need to make sure it's within reasonable boundaries, set the reminder, and notify the user. DateTimeOffset maxtime = new DateTimeOffset(ctx.Message.CreationTimestamp.UtcDateTime).AddMonths(Program.Settings.MaxReminderTimeMonths); DiscordEmbedBuilder embed; bool sendErrorEmbed = false; if (dto.UtcTicks == ctx.Message.CreationTimestamp.UtcTicks) { // No time was added. embed = Generics.GenericEmbedTemplate( color: Generics.NegativeColor, description: Generics.NegativeDirectResponseTemplate( mention: ctx.Member.Mention, body: @"I was unable able to add the reminder you gave me. You didn't supply me a valid time..."), title: @"Unable to add reminder", thumbnail: Generics.URL_REMINDER_GENERIC ); sendErrorEmbed = true; } else if (dto.UtcTicks > maxtime.UtcTicks) { // More than our allowed time away. int maxMonths = Program.Settings.MaxReminderTimeMonths; embed = Generics.GenericEmbedTemplate( color: Generics.NegativeColor, description: Generics.NegativeDirectResponseTemplate( mention: ctx.Member.Mention, body: $"I was unable able to add the reminder you gave me. That's more than {maxMonths} month{(maxMonths > 0 ? @"s" : String.Empty)} away..."), title: @"Unable to add reminder", thumbnail: Generics.URL_REMINDER_GENERIC ); sendErrorEmbed = true; } else { // Everything is good in the world... except that the world is burning, but that's not something we're worried about here, for // now... embed = Generics.GenericEmbedTemplate( color: Generics.PositiveColor, description: Generics.PositiveDirectResponseTemplate( mention: ctx.Member.Mention, body: @"I added the reminder you gave me!"), title: @"Add reminder", thumbnail: Generics.URL_REMINDER_GENERIC ); Reminder reminder = new Reminder( originalMessageId: ctx.Message.Id.ToString(), text: messageString.Length.Equals(0) ? @"n/a" : messageString.ToString(), time: (int)(dto.ToUnixTimeSeconds() / 60), user: ctx.Member.Id, channel: ctx.Channel.Id, usersToNotify: mentions.Select(a => Generics.GetMention(a)).ToArray()); embed.AddField(@"User", ctx.Member.Mention, true); embed.AddField(@"Time (UTC)", dto.ToString(Generics.DateFormat), true); embed.AddField(@"Remaining time", Generics.GetRemainingTime(dto), true); embed.AddField(@"Notification Identifier", reminder.OriginalMessageId.ToString(), false); if (GetUsersToNotify(reminder.UsersToNotify, out string mentionsString)) { embed.AddField(@"Users to mention", mentionsString, false); } // Let's build the command. using var command = new SqliteCommand(BotDatabase.Instance.DataSource) { CommandText = QQ_AddReminder }; SqliteParameter a = new SqliteParameter("$id", reminder.OriginalMessageId.ToString()) { DbType = DbType.String }; SqliteParameter b = new SqliteParameter("$userid", reminder.User) { DbType = DbType.String }; SqliteParameter c = new SqliteParameter("$channelid", reminder.Channel) { DbType = DbType.String }; SqliteParameter d = new SqliteParameter("$message", reminder.Text) { DbType = DbType.String }; SqliteParameter e = new SqliteParameter("$time", reminder.Time) { DbType = DbType.Int32 }; var stringBuilder = new StringBuilder(); stringBuilder.AppendJoin(' ', reminder.UsersToNotify); SqliteParameter f = new SqliteParameter("$mention", stringBuilder.ToString()) { DbType = DbType.String }; command.Parameters.AddRange(new SqliteParameter[] { a, b, c, d, e, f }); await BotDatabase.Instance.ExecuteNonQuery(command); // Send the response. await ctx.Channel.SendMessageAsync(embed : embed); } if (sendErrorEmbed) { var a = ctx.Channel.SendMessageAsync(embed: embed); var b = GenericResponses.HandleInvalidArguments(ctx); await Task.WhenAll(a, b); } }
/// <summary>List all the reminders</summary> public static async Task ListReminders(CommandContext ctx) { Reminder[] reminders = await ReadTable(); // Check if there are any notifications. If there are none, let the user know. if (reminders.Length > 0) { // There are reminders. var interactivity = Program.BotClient.GetInteractivity(); List <Page> pages = new List <Page>(); var deb = new DiscordEmbedBuilder(); int count = 0; int curPage = 1; // Paginate all the results. const int REMINDERS_PER_PAGE = 5; for (int i = 0; i < reminders.Length; i++) { Reminder reminder = reminders[i]; var dto = DateTimeOffset.FromUnixTimeSeconds(reminder.Time * 60); var valueStringBuilder = new StringBuilder(); valueStringBuilder.Append($"{Generics.GetMention(reminder.User)}: {reminder.Text}\n"); if (GetUsersToNotify(reminder.UsersToNotify, out string mentionsString)) { valueStringBuilder.Append($"**Users to mention:** {mentionsString}\n"); } valueStringBuilder.Append($"**Id:** {reminder.OriginalMessageId}\n"); valueStringBuilder.Append($"**Remaining time:** {Generics.GetRemainingTime(dto)}"); #region a bunny // .". // / | // / / // / ," // .-------.--- / // "._ __.-/ o. o\ // " ( Y ) // ) / // / ( // / Y // .-" | // / _ \ \ // / `. ". ) /' ) // Y )( / /(,/ // ,| / ) // ( | / / // " \_ (__ (__ [nabis] // "-._,)--._,) // o < bunny poopy l0l // ------------------------------------------------ // This ASCII pic can be found at // https://asciiart.website/index.php?art=animals/rabbits #endregion a bunny string name = dto.ToString(Generics.DateFormat); deb.AddField(name, valueStringBuilder.ToString()); count++; if (count == REMINDERS_PER_PAGE || i == reminders.Length - 1) { // Create a new page. deb.WithDescription(Generics.NeutralDirectResponseTemplate( mention: ctx.User.Mention, body: $"Hello {ctx.Member.Mention}, please note you are the only one who can react to this message.\n\n" + $"**Showing {count} reminders out of a total of {reminders.Length}.**")); deb.WithTitle($"Reminders Page {curPage}/{Math.Ceiling((float)reminders.Length / (float)REMINDERS_PER_PAGE)}"); deb.WithColor(Generics.NeutralColor); deb.WithThumbnail(Generics.URL_REMINDER_GENERIC); pages.Add(new Page(embed: deb)); count = 0; curPage++; deb = new DiscordEmbedBuilder(); } // end if } // end for await interactivity.SendPaginatedMessageAsync(ctx.Channel, ctx.User, pages, emojis : Generics.DefaultPaginationEmojis); } else { // There are no reminders. await ctx.Channel.SendMessageAsync( embed : Generics.GenericEmbedTemplate( color: Generics.NeutralColor, description: Generics.NeutralDirectResponseTemplate( mention: ctx.Member.Mention, body: "there are no reminders."), thumbnail: Generics.URL_SPEECH_BUBBLE, title: "Reminders")); } }