Exemplo n.º 1
0
        /// <inheritdoc />
        public async Task <ServiceResult> CreateInfractionAsync(InfractionType type, ulong subjectId, string reason, TimeSpan?duration)
        {
            var authResult = AuthorizationService.CheckClaims(_createInfractionClaimsByType[type]);

            if (authResult.IsFailure)
            {
                return(authResult);
            }

            var rankResult = await RequireSubjectRankLowerThanModeratorRankAsync(AuthorizationService.CurrentGuildId.Value, subjectId);

            if (rankResult.IsFailure)
            {
                return(rankResult);
            }

            var guild = await DiscordClient.GetGuildAsync(AuthorizationService.CurrentGuildId.Value);

            IGuildUser subject;

            if (!await UserService.GuildUserExistsAsync(guild.Id, subjectId))
            {
                subject = new EphemeralUser(subjectId, "[FORCED]", guild);
                await UserService.TrackUserAsync(subject);
            }
            else
            {
                subject = await UserService.GetGuildUserAsync(guild.Id, subjectId);
            }

            if (type == InfractionType.Notice || type == InfractionType.Warning)
            {
                if (string.IsNullOrWhiteSpace(reason))
                {
                    return(ServiceResult.FromError($"{type.ToString()} infractions require a reason to be given"));
                }
            }

            var lengthResult = new InvalidLengthResult("Reason", reason.Length, maximum: 1000);

            if (lengthResult.IsFailure)
            {
                return(lengthResult);
            }

            using (var transaction = await InfractionRepository.BeginCreateTransactionAsync())
            {
                if ((type == InfractionType.Mute) || (type == InfractionType.Ban))
                {
                    if (await InfractionRepository.AnyAsync(new InfractionSearchCriteria()
                    {
                        GuildId = guild.Id,
                        Types = new[] { type },
                        SubjectId = subject.Id,
                        IsRescinded = false,
                        IsDeleted = false
                    }))
                    {
                        return(ServiceResult.FromError($"Discord user {subjectId} already has an active {type} infraction"));
                    }
                }

                await InfractionRepository.CreateAsync(
                    new InfractionCreationData()
                {
                    GuildId     = guild.Id,
                    Type        = type,
                    SubjectId   = subjectId,
                    Reason      = reason,
                    Duration    = duration,
                    CreatedById = AuthorizationService.CurrentUserId.Value
                });

                transaction.Commit();
            }

            // TODO: Implement ModerationSyncBehavior to listen for mutes and bans that happen directly in Discord, instead of through bot commands,
            // and to read the Discord Audit Log to check for mutes and bans that were missed during downtime, and add all such actions to
            // the Infractions and ModerationActions repositories.
            // Note that we'll need to upgrade to the latest Discord.NET version to get access to the audit log.

            // Assuming that our Infractions repository is always correct, regarding the state of the Discord API.
            switch (type)
            {
            case InfractionType.Mute:
                await subject.AddRoleAsync(
                    await GetDesignatedMuteRoleAsync(guild));

                break;

            case InfractionType.Ban:
                await guild.AddBanAsync(subject, reason : reason);

                break;
            }

            return(ServiceResult.FromSuccess());
        }
Exemplo n.º 2
0
        [TestCase(10, 12, 12, ExpectedResult = false)] // Length != (Min == Max)  == failure
        public bool Constructor_WithValidParams_ReturnsCorrectResult(int length, int min, int max)
        {
            var result = new InvalidLengthResult("Test", length, min, max);

            return(result.IsSuccess);
        }