private async Task GuildMemberUpdated(SocketGuildUser oldUser, SocketGuildUser newUser, ulong guildId) { if (oldUser.IsBot) { return; } var applicationInfo = await Client.GetApplicationInfoAsync(); var newRoles = newUser.Roles.Except(oldUser.Roles); try { Model.GuildInactivityRole.TryGetValue(guildId, out var inactiveRoleId); var inactiveRole = newUser.Guild.GetRole(inactiveRoleId); if (newRoles.Any(r => r.Name.Equals(inactiveRole.Name, StringComparison.OrdinalIgnoreCase))) { CultureInfo culture = BaseService.GetGuildCulture(guildId); Logger.Debug($"Searching audit logs for the user {newUser.Username}"); var asyncAuditLogs = newUser.Guild.GetAuditLogsAsync(10, actionType: ActionType.MemberRoleUpdated) .Where(a => a.Any(l => ((MemberRoleAuditLogData)l.Data).Target.Id == newUser.Id)); await foreach (var auditLogs in asyncAuditLogs) { if (auditLogs.Count <= 0) { Logger.Debug($"No audit logs were found."); return; } var auditLog = auditLogs.First(); if (auditLog.User.IsBot) { Logger.Debug($"The user {newUser.Username} was set inactive by the bot."); return; } Logger.Debug($"The user {newUser.Username} was set inactive by {auditLog.User.Username}"); List <string> raids = new List <string>(); Model.GuildRaidRoles.TryGetValue(guildId, out var guildRoles); if (guildRoles != null) { var raidIds = newUser.Roles.Where(r => guildRoles.Contains(r.Id)).Select(r => r.Id); raids = newUser.Guild.Roles.Where(r => raidIds.Contains(r.Id)).Select(r => r.Mention).ToList(); } Model.GuildDestinationChannel.TryGetValue(guildId, out var channelId); if (newUser.Guild.GetChannel(channelId) is ITextChannel channel) { string description = string.Format(culture, Inactivity.Inactivity_Forced, newUser.Mention, auditLog.User.Mention); var embedBuilder = new EmbedBuilder(); embedBuilder .WithAuthor(newUser) .WithTitle(Inactivity.Inactivity_Embed_Title) .WithDescription(description) .WithCurrentTimestamp() .WithColor(Color.LightGrey); if (raids.Count > 0) { embedBuilder.AddField(Inactivity.Inactivity_Embed_Raids, string.Join(" ", raids)); } await channel.SendMessageAsync(text : string.Join(" ", raids), embed : embedBuilder.Build()).ConfigureAwait(false); } } } } catch (Exception ex) { Logger.Error(ex, "An exception occured!"); await applicationInfo.Owner.SendMessageAsync($"Exception Message: {ex.Message}\nException: {ex}"); } }
private async Task ReactionAdded(Cacheable <IUserMessage, ulong> cachedMessage, ISocketMessageChannel channel, SocketReaction reaction, ulong guildId) { Logger.Debug("Reaction added"); CultureInfo culture = BaseService.GetGuildCulture(guildId); BaseService.Model.GuildWaitTime.TryGetValue(guildId, out TimeSpan waitTime); if (waitTime == null) { // incase the guild did not set a custom wait time, set a default one with 15 Minutes. waitTime = new TimeSpan(0, 15, 0); } // Get the message where the reaction was added. var message = await cachedMessage.GetOrDownloadAsync(); if (message == null) { Logger.Error("Could not find the cached message"); } // Get the user. IUser user = reaction.User.Value; // If the User object is not set or a bot reacted to the message, don't do anything and just return. if (user == null || user.IsBot) { string warningMessage = user == null ? "The user object was not set" : $"The bot {user.Username} reacted to the message"; Logger.Warning(warningMessage); return; } // Check if the reaction was added to the inactivity message. Model.GuildInactivityMessage.TryGetValue(guildId, out var messageId); if (messageId > 0 && message.Id == messageId) { if (OngoingUsers.Contains(user.Id)) { Logger.Information($"User with Id {user.Id} reacted to the message again too soon."); await message.RemoveReactionAsync(reaction.Emote, user).ConfigureAwait(false); return; } Logger.Debug($"The user {user.Username} wants to set themself inactive."); OngoingUsers.Add(user.Id); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed Task.Run(async() => { var applicationInfo = await Client.GetApplicationInfoAsync(); try { var emoji = new Emoji(reaction.Emote.Name); await message.RemoveReactionAsync(reaction.Emote, user).ConfigureAwait(false); Model.GuildInactiveEmoji.TryGetValue(guildId, out var inactiveEmoji); Model.GuildActiveEmoji.TryGetValue(guildId, out var activeEmoji); Model.GuildInactivityRole.TryGetValue(guildId, out var inacRoleId); Model.GuildDestinationChannel.TryGetValue(guildId, out var destChannelId); var guildUser = user as IGuildUser; if (emoji.Name == inactiveEmoji) { var dmChannel = await user.GetOrCreateDMChannelAsync().ConfigureAwait(false); SocketMessage accountName = null; await dmChannel.SendMessageAsync(Inactivity.Inactivity_AccountName); bool regexMatch = false; do { if (accountName != null) { await dmChannel.SendMessageAsync(Inactivity.AccountName_Incorrect); Logger.Information($"The User {user.Username} provided an incorrect account name; The provided account name: {accountName}"); } accountName = await HelperMethods.GetNextMessage(Client, user, waitTime).ConfigureAwait(false); if (accountName != null) { regexMatch = Regex.IsMatch(accountName.Content, @"[a-zA-Z]+\.\d{4}$"); } }while (accountName != null && !regexMatch); if (accountName == null) { await dmChannel.SendMessageAsync(Inactivity.Timeout); OngoingUsers.Remove(user.Id); Logger.Information($"User {user.Username} provided no account name"); return; } Logger.Information($"Account Name: {accountName} from User: {user.Username}"); await dmChannel.SendMessageAsync(Inactivity.Inactivity_Duration); var inactivityPeriod = await HelperMethods.GetNextMessage(Client, user, waitTime).ConfigureAwait(false); if (inactivityPeriod == null) { await dmChannel.SendMessageAsync(Inactivity.Timeout); OngoingUsers.Remove(user.Id); Logger.Information($"User {user.Username} provided no inactivity period"); return; } Logger.Information($"Inactivity Period: {inactivityPeriod} from User: {user.Username}"); await dmChannel.SendMessageAsync(Inactivity.Inactivity_Reason); var reason = await HelperMethods.GetNextMessage(Client, user, waitTime).ConfigureAwait(false); if (reason == null) { await dmChannel.SendMessageAsync(Inactivity.Missing_Reason); OngoingUsers.Remove(user.Id); Logger.Information($"User {user.Username} provided no reason"); return; } Logger.Information($"Reason: {reason} from User: {user.Username}"); List <string> raids = new List <string>(); Model.GuildRaidRoles.TryGetValue(guildId, out var guildRoles); if (guildRoles != null) { var raidIds = guildUser.RoleIds.Where(r => guildRoles.Contains(r)); raids = guildUser.Guild.Roles.Where(r => raidIds.Contains(r.Id)).Select(r => r.Mention).ToList(); } Model.GuildDestinationChannel.TryGetValue(guildId, out var channelId); if (await guildUser.Guild.GetChannelAsync(channelId) is ITextChannel channel) { await dmChannel.SendMessageAsync(Inactivity.Inactive_Success); var embedBuilder = new EmbedBuilder(); embedBuilder .WithAuthor(user) .AddField(Inactivity.Inactivity_Embed_AccountName, accountName.Content) .AddField(Inactivity.Inactivity_Embed_Period, inactivityPeriod.Content) .AddField(Inactivity.Inactivity_Embed_Reason, reason.Content) .WithColor(Color.LightGrey) .WithCurrentTimestamp() .WithTitle(Inactivity.Inactivity_Embed_Title) .WithDescription(user.Mention); if (raids.Count > 0) { embedBuilder.AddField(Inactivity.Inactivity_Embed_Raids, string.Join(" ", raids)); } if (inacRoleId > 0) { var inactivityRole = guildUser.Guild.Roles.Single(r => r.Id == inacRoleId); if (inactivityRole != null) { await guildUser.AddRoleAsync(inactivityRole); embedBuilder.WithFooter(Inactivity.InactivityRole_Added); Logger.Debug($"Added Role {inactivityRole} to user {user.Username}"); } } await channel.SendMessageAsync(text: string.Join(" ", raids), embed: embedBuilder.Build()).ConfigureAwait(false); Logger.Debug("Successfully created the Inactivity Embed"); } else { await dmChannel.SendMessageAsync(string.Format(culture, Inactivity.Error, applicationInfo.Owner.Mention, InactivityError.MissingChannel)); } } else if (emoji.Name == activeEmoji) { if (inacRoleId > 0 && guildUser.RoleIds.Contains(inacRoleId)) { var role = guildUser.Guild.Roles.Single(r => r.Id == inacRoleId); await guildUser.RemoveRoleAsync(role).ConfigureAwait(false); await guildUser.SendMessageAsync(Inactivity.Inactivity_Active).ConfigureAwait(false); if (await guildUser.Guild.GetChannelAsync(destChannelId) is ITextChannel channel) { await channel.SendMessageAsync(string.Format(culture, Inactivity.Inactivity_Active_Lead, user.Mention)).ConfigureAwait(false); } } } OngoingUsers.Remove(user.Id); } catch (Exception ex) { Logger.Error(ex.ToString()); await applicationInfo.Owner.SendMessageAsync($"Exception Message: {ex.Message}\nException: {ex}"); } finally { Logger.Debug($"Released user {user.Username} ({user.Id})"); OngoingUsers.Remove(user.Id); } }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } }