private async Task ClientOnReactionAdded(Cacheable <IUserMessage, ulong> cachedMessage, ISocketMessageChannel channel, SocketReaction reaction) { // Check if the starboard is locked if (IsLocked) { return; } IUserMessage reactedMessage = await cachedMessage.GetOrDownloadAsync(); SocketGuildUser user = ((SocketTextChannel)channel).Guild.GetUser(reaction.UserId); if (reaction.Emote.Name == "⭐" && reaction.UserId != client.CurrentUser.Id && channel is SocketTextChannel) { List <DatabaseService.StarredMessageRow> starredMessageEntries; IChannel starChannel = client.GetChannel(Convert.ToUInt64(config["stars:starboardChannelId"])); // Check if the user is banned from the starboard if (databaseService.GetStarBan(reaction.UserId.ToString()).Any()) { await(await user.GetOrCreateDMChannelAsync()).SendMessageAsync("You are banned from participating in the starboard."); return; } // Insert the star entry into the database, also accounting for there being reactions on the starboard post string messageIdToInsert; string channelIdOfStarredMessage; if (channel.Id == starChannel.Id) // Check if the user is trying to star the message form the starboard channel { starredMessageEntries = databaseService.GetStarboardMessageEntry(reactedMessage.Id.ToString(), false).ToList(); switch (starredMessageEntries.Count) { case 0: // The message is not in the database, delete it from the channel logger.LogError("User tried to react to message on the starboard that was not in the database"); await reactedMessage.DeleteAsync(); return; case 1: // Get the ID of the original post from the starboard entry and add a star entry using that messageIdToInsert = starredMessageEntries[0].OriginalMessageId; channelIdOfStarredMessage = starredMessageEntries[0].OriginalChannelId; break; default: // Somehow the post has been entered multiple times into the starboard logger.LogError($"Multiple starboard entries detected for message {reactedMessage.Id}"); return; } } else // Otherwise, we assume they are starring the actual message { messageIdToInsert = reactedMessage.Id.ToString(); channelIdOfStarredMessage = channel.Id.ToString(); } // Check if the channel is excluded if (config.GetSection("stars:excludedChannels").AsEnumerable().Any(x => x.Value == channelIdOfStarredMessage)) { return; } // Check if the user's role is excluded if (config.GetSection("stars:excludedRoles").AsEnumerable().Select(z => z.Value).Intersect(user.Roles.Select(y => y.Id.ToString())).Any()) { return; } // Check if user is attempting to star their own message IMessage message = await((ITextChannel)client.GetChannel(Convert.ToUInt64(channelIdOfStarredMessage))).GetMessageAsync(Convert.ToUInt64(messageIdToInsert)); if (message.Author.Id == reaction.UserId) { await(await user.GetOrCreateDMChannelAsync()).SendMessageAsync("You appear to have attempted to star your own message, you think too highly of yourself."); return; } bool insertionResult = databaseService.InsertStarEntry(user, messageIdToInsert); if (!insertionResult) { await(await user.GetOrCreateDMChannelAsync()).SendMessageAsync("You appear to have already starred the message you just attempted to star. Have you starred it in another channel?"); return; } // Get the number of star entries the post has int starEntryCount = databaseService.GetStarEntries(messageIdToInsert).Count; if (starEntryCount < Convert.ToInt32(config["stars:minimumThreshold"])) { // We don't post a message to the starboard unless a minimum specified in the config is reached to avoid it getting spammed up return; } // Get or create the starboard entry now that it is above the threshold, and post/update it in the starboard channel starredMessageEntries = databaseService.GetStarboardMessageEntry(messageIdToInsert, true).ToList(); switch (starredMessageEntries.Count) { case 0: // Make a starboard post and then create it in the database RestUserMessage sentMessage = await((ISocketMessageChannel)starChannel).SendMessageAsync($"{ ConvertStarCountToEmoji(starEntryCount) } **{ starEntryCount }** in channel <#{ channelIdOfStarredMessage }> for message (ID { messageIdToInsert })", embed: ConvertMessageToEmbed((IUserMessage)message)); await sentMessage.AddReactionAsync(new Emoji("⭐")); if (!databaseService.InsertStarboardMessageEntry(message.Id.ToString(), channel, message.Author.Id.ToString(), sentMessage)) { await sentMessage.DeleteAsync(); logger.LogError("Could not insert message so deleted post for it"); } break; case 1: // Get the ID of the existing starboard post and update the value DatabaseService.StarredMessageRow messageRow = starredMessageEntries.First(); await((IUserMessage)await((ISocketMessageChannel)starChannel).GetMessageAsync(Convert.ToUInt64(messageRow.StarboardMessageId))).ModifyAsync(x => { x.Content = $"{ConvertStarCountToEmoji(starEntryCount)} **{starEntryCount}** in channel <#{channelIdOfStarredMessage}> for message (ID {messageIdToInsert})"; }); break; default: // Somehow the post has been entered multiple times into the starboard logger.LogError($"Multiple starboard entries detected for message {messageIdToInsert}"); return; } } }
private async Task ClientOnReactionRemoved(Cacheable <IUserMessage, ulong> cachedMessage, ISocketMessageChannel channel, SocketReaction reaction) { // Check if the starboard is locked if (IsLocked) { return; } SocketGuildUser user = ((SocketTextChannel)channel).Guild.GetUser(reaction.UserId); // Check if the user is banned from the starboard if (databaseService.GetStarBan(reaction.UserId.ToString()).Any()) { await(await user.GetOrCreateDMChannelAsync()).SendMessageAsync("You are banned from participating in the starboard."); return; } IUserMessage reactedMessage = await cachedMessage.GetOrDownloadAsync(); if (reaction.Emote.Name == "⭐") { List <DatabaseService.StarredMessageRow> starredMessageEntries; IChannel starChannel = client.GetChannel(Convert.ToUInt64(config["stars:starboardChannelId"])); // Delete the star entry from the database, also accounting for there being reactions on the starboard post string messageIdToDelete; string channelIdOfStarredMessage; if (channel.Id == starChannel.Id) // Check if the user is trying to unstar the message form the starboard channel { starredMessageEntries = databaseService.GetStarboardMessageEntry(reactedMessage.Id.ToString(), false).ToList(); switch (starredMessageEntries.Count) { case 0: // The message is not in the database, delete it from the channel logger.LogError("User tried to unreact to message on the starboard that was not in the database"); await reactedMessage.DeleteAsync(); return; case 1: // Get the ID of the original post from the starboard entry and remove the star entry from that messageIdToDelete = starredMessageEntries[0].OriginalMessageId; channelIdOfStarredMessage = starredMessageEntries[0].OriginalChannelId; break; default: // Somehow the post has been entered multiple times into the starboard logger.LogError($"Multiple starboard entries detected for message {reactedMessage.Id}"); return; } } else // Otherwise, we assume they are unstarring the actual message { messageIdToDelete = reactedMessage.Id.ToString(); channelIdOfStarredMessage = channel.Id.ToString(); } // Check if the channel is excluded if (config.GetSection("stars:excludedChannels").AsEnumerable().Any(x => x.Value == channelIdOfStarredMessage)) { return; } // Check if the user's role is excluded if (config.GetSection("stars:excludedRoles").AsEnumerable().Select(z => z.Value).Intersect(user.Roles.Select(y => y.Id.ToString())).Any()) { return; } var entries = databaseService.GetStarEntry(reaction.UserId.ToString(), messageIdToDelete); if (entries.Count == 0) { await(await user.GetOrCreateDMChannelAsync()).SendMessageAsync("You have not starred the message you just tried to unstar. Have you already unstarred it in another channel?"); return; } else if (entries.Count > 1) { logger.LogError($"User { reaction.UserId } has multiple stars stored for message ID { messageIdToDelete }, deleting all"); } if (!databaseService.DeleteStarEntry(reaction.UserId.ToString(), messageIdToDelete)) { await(await user.GetOrCreateDMChannelAsync()).SendMessageAsync("There was an error unstarring the message you just tried to unstar."); } // Get or delete the starboard entry depending on star count, and delete/update it in the starboard channel int starEntryCount = databaseService.GetStarEntries(messageIdToDelete).Count; starredMessageEntries = databaseService.GetStarboardMessageEntry(messageIdToDelete, true).ToList(); switch (starredMessageEntries.Count) { case 0: // Entry is already missing somehow, don't do anything here because it should have already been handled break; case 1: // Get the ID of the existing starboard post and update the value DatabaseService.StarredMessageRow messageRow = starredMessageEntries.First(); IUserMessage message = (IUserMessage)await((ISocketMessageChannel)starChannel).GetMessageAsync(Convert.ToUInt64(messageRow.StarboardMessageId)); if (starEntryCount == 0) { await message.DeleteAsync(); } else { await message.ModifyAsync(x => { x.Content = $"{ConvertStarCountToEmoji(starEntryCount)} **{starEntryCount}** in channel <#{channelIdOfStarredMessage}> for message (ID {messageIdToDelete})"; }); } break; default: // Somehow the post has been entered multiple times into the starboard logger.LogError($"Multiple starboard entries detected for message {messageIdToDelete}"); return; } } }