public async Task CheckBanAction(RuleExceedCheckCommand command) { var suspensionsForUser = await suspensionRepository.GetSuspensionsForUser(command.TwitchUsername).ConfigureAwait(false); if (suspensionsForUser.Count == 0) { return; } var userReport = new UserReport(command.TwitchUsername, suspensionsForUser); var channels = await channelRepository.GetChannels().ConfigureAwait(false); foreach (var channel in channels.Where(x => x.ChannelRules.Count > 0)) { foreach (var rule in channel.ChannelRules.Where(x => x.ActionOnTrigger == ChannelRuleAction.Ban)) { if (userReport.Exceeds(rule)) { if (channel.SystemIsModerator && channel.ShouldListen) { await SendBanCommandFor(command.TwitchUsername, channel.ChannelName, rule.RuleName).ConfigureAwait(false); } else { logger.LogInformation("Channel Rule triggered ban, but channel does not have moderation / listening enabled for: {arg}", channel.ChannelName); } } } } }
private async Task MarkActiveSuspensionsForUserAsUndone(string username, string undoneBy, DateTime timeOfSuspension, IMessageDispatcher messageDispatcher) { var suspensionsForUser = await suspensionRepository.GetSuspensionsForUser(username).ConfigureAwait(false); foreach (var activeSuspension in suspensionsForUser.Where(x => x.IsActive(timeOfSuspension))) { activeSuspension.MarkSuspensionAsUndone(undoneBy); await suspensionRepository.Save(activeSuspension).ConfigureAwait(false); await messageDispatcher.Publish(new SuspensionUpdatedEvent { ChannelOfOrigin = activeSuspension.ChannelOfOrigin, SuspensionId = activeSuspension.SuspensionId }).ConfigureAwait(false); } }
public async Task <IResult <Suspension> > UpdateAuditState(Guid suspensionId, bool audited, IApplicationContext context) { var fetch = await RetrieveSuspensionAndCheckAccess(suspensionId, context).ConfigureAwait(false); if (fetch.State != ResultState.Success) { return(fetch); } var suspension = fetch.Data; if (suspension.SuspensionType == SuspensionType.Ban) { var suspensionsForUser = await suspensionRepository.GetSuspensionsForUser(suspension.Username).ConfigureAwait(false); foreach (var ban in suspensionsForUser.Where(x => x.SuspensionType == SuspensionType.Ban && x.Audited && string.Equals(x.ChannelOfOrigin, suspension.ChannelOfOrigin, StringComparison.OrdinalIgnoreCase)).ToList()) { if (ban.Timestamp < suspension.Timestamp && !ban.InvalidSuspension) { ban.UpdateValidity(true, "Invalid because a new ban overwrites", context, datetimeProvider.UtcNow); await suspensionRepository.Save(ban).ConfigureAwait(false); await PublishSuspensionUpdatedEvent(ban).ConfigureAwait(false); } } } suspension.UpdateAuditedState(audited, context, datetimeProvider.UtcNow); await suspensionRepository.Save(suspension).ConfigureAwait(false); if (suspension.Audited && !suspension.InvalidSuspension) { await PublishSuspensionAuditedEvent(suspension).ConfigureAwait(false); } await PublishSuspensionUpdatedEvent(suspension).ConfigureAwait(false); return(Result <Suspension> .Succeeded(suspension)); }
public async Task IssueBanFor(string username, string channelToBanFrom, string systemReason) { var suspensionsForUser = await suspensionRepository.GetSuspensionsForUser(username).ConfigureAwait(false); var suspensionsForUserInChannel = suspensionsForUser.Where(x => string.Equals(x.ChannelOfOrigin, channelToBanFrom, StringComparison.OrdinalIgnoreCase)); if (suspensionsForUserInChannel.Any(x => x.SuspensionType == SuspensionType.Ban && !x.InvalidSuspension && x.Audited)) { logger.LogInformation("{arg} has already been banned from {arg2}", username, channelToBanFrom); return; } client.BanUser(username, channelToBanFrom, systemReason); }
public async Task <IResult <List <UserRulesExceeded> > > GetUsersWhoExceedsRules(string channelName, IApplicationContext context) { var suspensionsForSystem = await suspensionRepository.GetSuspensions(datetimeProvider.UtcNow.AddYears(-1)).ConfigureAwait(false); var usersFromSuspensions = suspensionsForSystem.Select(x => x.Username); var channel = await channelRepository.GetChannel(channelName).ConfigureAwait(false); if (!context.HaveAccessTo(channel)) { return(Result <List <UserRulesExceeded> > .Unauthorized()); } var allSuspensionsForChannel = await suspensionRepository.GetSuspensionsForChannel(channelName).ConfigureAwait(false); var allValidAuditedSuspensionForChannel = allSuspensionsForChannel.Where(x => !x.InvalidSuspension && x.Audited); var usersWhoExceeded = new List <UserRulesExceeded>(); foreach (var user in usersFromSuspensions.Distinct(StringComparer.OrdinalIgnoreCase)) { // If we already have a ban if (allValidAuditedSuspensionForChannel.Any(x => string.Equals(x.Username, user, StringComparison.OrdinalIgnoreCase) && x.SuspensionType == SuspensionType.Ban)) { continue; } var suspensionsForUser = await suspensionRepository.GetSuspensionsForUser(user).ConfigureAwait(false); var report = new UserReport(user, suspensionsForUser); foreach (var rule in channel.ChannelRules.Where(x => x.ActionOnTrigger == ChannelRuleAction.Ban)) { if (report.Exceeds(rule)) { var userRulesExceeded = usersWhoExceeded.Find(x => string.Equals(x.Username, user, StringComparison.OrdinalIgnoreCase)) ?? new UserRulesExceeded { Username = user }; usersWhoExceeded.Remove(userRulesExceeded); userRulesExceeded.RulesBroken.Add(rule); usersWhoExceeded.Add(userRulesExceeded); } } } return(Result <List <UserRulesExceeded> > .Succeeded(usersWhoExceeded)); }
public async Task <IResult <UserReport> > GetUserReportFor(string username) { var suspensionsForUser = await suspensionRepository.GetSuspensionsForUser(username).ConfigureAwait(false); if (suspensionsForUser.Count == 0) { return(Result <UserReport> .NoContentFound()); } var userReport = new UserReport(username, suspensionsForUser); if (userReport.Suspensions.Count == 0) { return(Result <UserReport> .NoContentFound()); } return(Result <UserReport> .Succeeded(userReport)); }
public async Task SendNotification(string username, string channelOfOrigin, Guid ruleId) { var channel = await channelRepository.GetChannel(channelOfOrigin).ConfigureAwait(false); var ruleThatWasBroken = channel.ChannelRules.FirstOrDefault(x => x.RuleId == ruleId); var suspensionsForUser = await suspensionRepository.GetSuspensionsForUser(username).ConfigureAwait(false); if (UserHasActiveBanInTheChannel()) { logger.LogInformation($"{username} already has active bans in {channelOfOrigin}, no need to send notification to discord"); return; } var ownerOfChannel = await userRepository.GetByTwitchUsername(channel.ChannelName).ConfigureAwait(false); if (ownerOfChannel?.DiscordEnabled == true) { logger.LogInformation($"Sent discord notification to {ownerOfChannel.TwitchUsername} (Owner of channel)"); await discordMessageClient.SendDmToUser(ownerOfChannel.DiscordUserId, $"{username}, has been spotted in your channel, they have exceeded the rule: {ruleThatWasBroken.RuleName}").ConfigureAwait(false); } foreach (var mod in channel.Moderators) { var user = await userRepository.GetByTwitchUsername(mod).ConfigureAwait(false); if (user?.DiscordEnabled == true) { logger.LogInformation($"Sent discord notification to {user.TwitchUsername}"); await discordMessageClient.SendDmToUser(user.DiscordUserId, $"{username}, has been spotted in {channel.ChannelName}, they have exceeded the rule: {ruleThatWasBroken.RuleName}").ConfigureAwait(false); } } bool UserHasActiveBanInTheChannel() { return(suspensionsForUser.Any(x => string.Equals(x.ChannelOfOrigin, channelOfOrigin, StringComparison.OrdinalIgnoreCase) && x.SuspensionType == SuspensionType.Ban && x.Audited && !x.InvalidSuspension)); } }