/// <inheritdoc /> public async Task DeleteInfractionAsync(long infractionId) { AuthorizationService.RequireAuthenticatedUser(); AuthorizationService.RequireClaims(AuthorizationClaim.ModerationDelete); var infraction = await InfractionRepository.ReadSummaryAsync(infractionId); if (infraction == null) { throw new InvalidOperationException($"Infraction {infractionId} does not exist"); } await InfractionRepository.TryDeleteAsync(infraction.Id, AuthorizationService.CurrentUserId.Value); var guild = await GuildService.GetGuildAsync(infraction.GuildId); var subject = await UserService.GetGuildUserAsync(guild.Id, infraction.Subject.Id); switch (infraction.Type) { case InfractionType.Mute: await subject.RemoveRoleAsync( await GetOrCreateMuteRoleInGuildAsync(guild)); break; case InfractionType.Ban: await guild.RemoveBanAsync(subject); break; } }
/// <inheritdoc /> public async Task DeleteInfractionAsync(long infractionId) { AuthorizationService.RequireAuthenticatedUser(); AuthorizationService.RequireClaims(AuthorizationClaim.ModerationDeleteInfraction); var infraction = await InfractionRepository.ReadSummaryAsync(infractionId); if (infraction == null) { throw new InvalidOperationException($"Infraction {infractionId} does not exist"); } await RequireSubjectRankLowerThanModeratorRankAsync(infraction.GuildId, AuthorizationService.CurrentUserId.Value, infraction.Subject.Id); await InfractionRepository.TryDeleteAsync(infraction.Id, AuthorizationService.CurrentUserId.Value); var guild = await DiscordClient.GetGuildAsync(infraction.GuildId); switch (infraction.Type) { case InfractionType.Mute: if (await UserService.GuildUserExistsAsync(guild.Id, infraction.Subject.Id)) { var subject = await UserService.GetGuildUserAsync(guild.Id, infraction.Subject.Id); await subject.RemoveRoleAsync(await GetDesignatedMuteRoleAsync(guild)); } else { Log.Warning("Tried to unmute {User} while deleting mute infraction, but they weren't in the guild: {Guild}", infraction.Subject.Id, guild.Id); } break; case InfractionType.Ban: //If the infraction has already been rescinded, we don't need to actually perform the unmute/unban //Doing so will return a 404 from Discord (trying to remove a nonexistant ban) if (infraction.RescindAction == null) { await guild.RemoveBanAsync(infraction.Subject.Id); } break; } }
/// <inheritdoc /> public async Task <ServiceResult> DeleteInfractionAsync(long infractionId) { var authResult = AuthorizationService.CheckClaims(AuthorizationClaim.ModerationDeleteInfraction); if (authResult.IsFailure) { return(authResult); } var infraction = await InfractionRepository.ReadSummaryAsync(infractionId); if (infraction == null) { return(ServiceResult.FromError($"Infraction {infractionId} does not exist")); } var rankResult = await RequireSubjectRankLowerThanModeratorRankAsync(AuthorizationService.CurrentGuildId.Value, infraction.Subject.Id); if (rankResult.IsFailure) { return(rankResult); } await InfractionRepository.TryDeleteAsync(infraction.Id, AuthorizationService.CurrentUserId.Value); var guild = await DiscordClient.GetGuildAsync(infraction.GuildId); var subject = await UserService.GetGuildUserAsync(guild.Id, infraction.Subject.Id); switch (infraction.Type) { case InfractionType.Mute: await subject.RemoveRoleAsync( await GetDesignatedMuteRoleAsync(guild)); break; case InfractionType.Ban: await guild.RemoveBanAsync(subject); break; } return(ServiceResult.FromSuccess()); }
/// <inheritdoc /> public async Task DeleteInfractionAsync(long infractionId) { AuthorizationService.RequireAuthenticatedUser(); AuthorizationService.RequireClaims(AuthorizationClaim.ModerationDeleteInfraction); var infraction = await InfractionRepository.ReadSummaryAsync(infractionId); if (infraction == null) { throw new InvalidOperationException($"Infraction {infractionId} does not exist"); } await RequireSubjectRankLowerThanModeratorRankAsync(infraction.GuildId, infraction.Subject.Id); await InfractionRepository.TryDeleteAsync(infraction.Id, AuthorizationService.CurrentUserId.Value); var guild = await DiscordClient.GetGuildAsync(infraction.GuildId); switch (infraction.Type) { case InfractionType.Mute: if (await UserService.GuildUserExistsAsync(guild.Id, infraction.Subject.Id)) { var subject = await UserService.GetGuildUserAsync(guild.Id, infraction.Subject.Id); await subject.RemoveRoleAsync(await GetDesignatedMuteRoleAsync(guild)); } else { Log.Warning("Tried to unmute {User} while deleting mute infraction, but they weren't in the guild: {Guild}", infraction.Subject.Id, guild.Id); } break; case InfractionType.Ban: await guild.RemoveBanAsync(infraction.Subject.Id); break; } }
public Task <OperationResult <long> > CreateInfractionAsync(InfractionType type, ulong guildId, ulong subjectId, string reason, TimeSpan?duration) => Operation.Start // Validation .Require(!string.IsNullOrWhiteSpace(reason), () => new InfractionReasonMissingError()) .Require(reason.Length <= 1000, () => new InfractionReasonTooLongError(actualLength: reason.Length, maxLength: 1000)) // Authorization .ContinueOnSuccessAsync(() => AuthorizationService .RequireClaimsAsync(_requiredClaimsByInfractionType[type])) .ContinueOnSuccessAsync(() => AuthorizationService .RequireRankOverSubjectAsync(guildId, subjectId)) // Acquire Guild API .ContinueOnSuccessAsync(() => UserService .GetGuildUser(guildId, subjectId)) // Try perform mute .DoOnSuccessWhenAsync(type == InfractionType.Mute, guildUser => DesignatedRoleService // Retrieve mute role .SearchDesignatedRolesAsync(new DesignatedRoleMappingSearchCriteria() { GuildId = guildId, Type = DesignatedRoleType.ModerationMute, IsDeleted = false }) .AsSuccessAsync() .RequireOnSuccessAsync( roleMappings => roleMappings.Any(), () => new ModerationMuteRoleNotConfiguredError()) .RequireOnSuccessAsync( roleMappings => roleMappings.Count == 1, () => new ModerationMuteRoleMultipleConfigurationsError()) .ContinueOnSuccessAsync(roleMappings => roleMappings .First() .Role.Id .AsSuccess()) // Verify user is not muted .RequireOnSuccessAsync( roleId => !guildUser.RoleIds.Contains(roleId), () => new ModerationSubjectAlreadyMutedError()) // Discord API .ContinueOnSuccessAsync(roleId => guildUser .Guild .GetRole(roleId) .AsSuccess()) // Perform mute .BranchOnSuccessAsync(role => guildUser.AddRoleAsync(role))) // Try perform ban .DoOnSuccessWhenAsync(type == InfractionType.Ban, guildUser => guildUser.Guild .AsSuccess() // Verify user is not banned .DoOnSuccessAsync(guild => guild .GetBansAsync() .AsSuccessAsync() .RequireOnSuccessAsync(bans => !bans.Any(x => x.User.Id == guildUser.Id), () => new ModerationSubjectAlreadyBannedError())) // Perform ban .BranchOnSuccessAsync(guild => guild.AddBanAsync(guildUser.Id))) // Perform database operations .ContinueOnSuccessAsync(async() => { using (var deleteTransaction = await InfractionRepository.BeginDeleteTransactionAsync()) using (var createTransaction = await InfractionRepository.BeginCreateTransactionAsync()) { return(await Operation.Start // Delete existing active Mute/Ban infractions, if any, so we can create a new one .BranchWhenAsync((type == InfractionType.Mute) || (type == InfractionType.Ban), () => Operation.Start .ContinueAsync(InfractionRepository.SearchIdsAsync(new InfractionSearchCriteria() { GuildId = guildId, Types = new[] { type }, SubjectId = subjectId, IsRescinded = false, IsDeleted = false }).AsSuccessAsync()) .BranchOnSuccessWhenAsync(bans => bans.Any(), bans => InfractionRepository .TryDeleteAsync( bans, SelfUser.Id))) // Record new infraction .ContinueOnSuccessAsync(() => InfractionRepository.CreateAsync(new InfractionCreationData() { GuildId = guildId, Type = type, Reason = reason, Duration = duration, SubjectId = subjectId, CreatedById = AuthorizationService.CurrentUserId ?? SelfUser.Id })) .BranchOnSuccess(() => { deleteTransaction.Commit(); createTransaction.Commit(); })); } });