Exemplo n.º 1
0
    public async Task <Result> ShowCharacterAsync([AutocompleteProvider("character::any")] Character character)
    {
        // NSFW check
        var getChannel = await _channelAPI.GetChannelAsync(_context.ChannelID, this.CancellationToken);

        if (!getChannel.IsSuccess)
        {
            return(Result.FromError(getChannel));
        }

        var channel = getChannel.Entity;

        if ((channel.IsNsfw.IsDefined(out var isNsfw) || !isNsfw) && character.IsNSFW)
        {
            return(new UserError("That character is NSFW, but the channel is not... naughty!"));
        }

        var createEmbed = await CreateCharacterInfoEmbedAsync(character);

        if (!createEmbed.IsSuccess)
        {
            return(Result.FromError(createEmbed));
        }

        var send = await _feedback.SendContextualEmbedAsync(createEmbed.Entity, ct : this.CancellationToken);

        return(send.IsSuccess
            ? Result.FromSuccess()
            : Result.FromError(send));
    }
        /// <inheritdoc />
        public async ValueTask <Result> CheckAsync(RequireContextAttribute attribute, CancellationToken ct)
        {
            var getChannel = await _channelAPI.GetChannelAsync(_context.ChannelID, ct);

            if (!getChannel.IsSuccess)
            {
                return(Result.FromError(getChannel));
            }

            var channel = getChannel.Entity;

            return(attribute.Context switch
            {
                ChannelContext.DM => channel.Type is DM
                    ? Result.FromSuccess()
                    : new ConditionNotSatisfiedError("This command can only be used in a DM."),
                ChannelContext.GroupDM => channel.Type is GroupDM
                    ? Result.FromSuccess()
                    : new ConditionNotSatisfiedError("This command can only be used in a group DM."),
                ChannelContext.Guild =>
                channel.Type is GuildText or GuildVoice or GuildCategory or GuildNews or GuildStore
                        ? Result.FromSuccess()
                        : new ConditionNotSatisfiedError("This command can only be used in a guild."),
                _ => throw new ArgumentOutOfRangeException(nameof(attribute))
            });
Exemplo n.º 3
0
        /// <inheritdoc />
        public override async ValueTask <Result <IRole> > TryParse(string value, CancellationToken ct)
        {
            if (!Snowflake.TryParse(value.Unmention(), out var roleID))
            {
                return(new ParsingError <IRole>(value.Unmention()));
            }

            var getChannel = await _channelAPI.GetChannelAsync(_context.ChannelID, ct);

            if (!getChannel.IsSuccess)
            {
                return(Result <IRole> .FromError(new GenericError("Failed to get a valid channel."), getChannel));
            }

            var channel = getChannel.Entity;

            if (!channel.GuildID.HasValue)
            {
                return(new GenericError("You're not in a guild channel, so I can't get any roles."));
            }

            var getRoles = await _guildAPI.GetGuildRolesAsync(channel.GuildID.Value, ct);

            if (!getRoles.IsSuccess)
            {
                return(Result <IRole> .FromError(new GenericError("Failed to get the guild's roles."), getRoles));
            }

            var roles = getRoles.Entity;
            var role  = roles.FirstOrDefault(r => r.ID.Equals(roleID));

            return(role is not null
                ? Result <IRole> .FromSuccess(role)
                : new GenericError("No role with that ID could be found."));
        }
Exemplo n.º 4
0
        public async Task <bool> IsThreadChannelAsync(Snowflake channelId, CancellationToken ct = default)
        {
            var channel = await _channelApi.GetChannelAsync(channelId, ct);

            var isThread = channel.Entity !.ThreadMetadata.HasValue;

            return(isThread);
        }
Exemplo n.º 5
0
        /// <inheritdoc />
        public override async ValueTask <Result <IChannel> > TryParse(string value, CancellationToken ct)
        {
            if (!Snowflake.TryParse(value.Unmention(), out var channelID))
            {
                return(new ParsingError <IChannel>(value.Unmention()));
            }

            return(await _channelAPI.GetChannelAsync(channelID.Value, ct));
        }
Exemplo n.º 6
0
    /// <inheritdoc />
    public async Task <Result> RespondAsync(IMessageCreate ev, CancellationToken ct = default)
    {
        // return if the message has no screenshot;
        if (ev.Attachments.Count == 0 ||
            ev.Author.IsBot.HasValue && ev.Author.IsBot.Value ||
            ev.Author.IsSystem.HasValue && ev.Author.IsSystem.Value ||
            !ev.GuildID.HasValue
            )
        {
            return(Result.FromSuccess());
        }

        var getChannelNameResult = await _channelApi.GetChannelAsync(ev.ChannelID, ct);

        if (!getChannelNameResult.IsSuccess)
        {
            return(Result.FromError(getChannelNameResult));
        }

        var channelName = getChannelNameResult.Entity.Name;

        if (!channelName.HasValue)
        {
            return(new PropertyMissingOrNullError("Channel in which a potential application was sent has no name."));
        }

        // return if the message isn't in #member-apps;
        if (!channelName.Value.Equals(_discordSettings.ChannelNames.MemberApps))
        {
            return(Result.FromSuccess());
        }

        var createMemberAppResult = await _mediator.Send(
            new CreateFromDiscordMessage.Command {
            DiscordMessageCreatedEvent = ev
        }, ct);

        if (createMemberAppResult.IsSuccess)
        {
            _logger.LogInformation($"Added a new application for message: {ev.ID}");
        }
        else
        {
            return(createMemberAppResult);
        }

        var sendConfirmationResult = await _channelApi.CreateMessageAsync(ev.ChannelID,
                                                                          "Your application has been submitted and you will be pinged once it has been processed.",
                                                                          messageReference : new MessageReference(ev.ID), ct : ct);

        return(sendConfirmationResult.IsSuccess
            ? Result.FromSuccess()
            : Result.FromError(sendConfirmationResult.Error));
    }
        protected override async Task Handle(TcpRequest <GenericCommandResult> request, CancellationToken cancellationToken)
        {
            var msg = request.Message;
            // we want an exception if failed, as the handler can't proceed if failed, hence Parse instead of TryParse;
            var parsedId         = ulong.Parse(request.Message.DiscordChannelId);
            var channelSnowflake = new Snowflake(parsedId);
            var getChannelResult = await _channelApi.GetChannelAsync(channelSnowflake, cancellationToken);

            if (!getChannelResult.IsSuccess || getChannelResult.Entity is null)
            {
                throw new Exception(getChannelResult.Error?.Message ?? $"Could not get channel with ID {parsedId}");
            }

            // because why would ColorTranslator use the established pattern of TryParse
            // when it can have only one method that throws if it fails to parse instead
            // FFS
            Color colour;

            try
            {
                colour = ColorTranslator.FromHtml(request.Message.Colour);
            }
            catch
            {
                colour = _colourPalette.Blue;
            }

            var sendCmdExecutedNotificationResult = await _channelApi.CreateMessageAsync(
                channelSnowflake,
                content : $"[{msg.ServerId}] Command `{msg.Command}` executed!",
                ct : cancellationToken);

            if (!sendCmdExecutedNotificationResult.IsSuccess)
            {
                _logger.LogError("Error while sending command output embed: {Error}",
                                 sendCmdExecutedNotificationResult.Error.Message);
            }

            var embeds = new List <Embed>();
            var output = msg.CommandOutput
                         .Chunk(1024)
                         .Select(chars => new string(chars.ToArray()))
                         .ToList();

            embeds
            .AddRange(output
                      .Select((str, i) => new Embed
            {
                Title  = $"[{i + 1}/{output.Count}] Command `{msg.Command}`'s output",
                Fields = new List <EmbedField>
                {
                    new("Output message", string.IsNullOrEmpty(str) ? "*No output*" : str !, false)
                },
Exemplo n.º 8
0
        /// <inheritdoc />
        public override async ValueTask <RetrieveEntityResult <IChannel> > TryParse(string value, CancellationToken ct)
        {
            if (!Snowflake.TryParse(value.Unmention(), out var channelID))
            {
                return(RetrieveEntityResult <IChannel> .FromError($"Failed to parse \"{value}\" as a channel ID."));
            }

            var getEntity = await _channelAPI.GetChannelAsync(channelID.Value, ct);

            return(!getEntity.IsSuccess
                ? RetrieveEntityResult <IChannel> .FromError(getEntity)
                : RetrieveEntityResult <IChannel> .FromSuccess(getEntity.Entity));
        }
    public async Task <Result> RespondAsync(IMessageReactionAdd ev, CancellationToken ct = default)
    {
        if (ev.ChannelID.Value != _discordSettings.FeedbackChannelId ||
            !ev.GuildID.HasValue ||
            !ev.Member.HasValue ||
            ev.Member.Value.User.HasValue && ev.Member.Value.User.Value.IsBot.HasValue &&
            ev.Member.Value.User.Value.IsBot.Value ||
            !ev.Emoji.Name.HasValue ||
            ev.Emoji.Name.Value is null ||
            !_protectedEmojis.Contains(ev.Emoji.Name.Value)
            )
        {
            return(Result.FromSuccess());
        }

        var getChannelResult = await _channelApi.GetChannelAsync(ev.ChannelID, ct);

        if (!getChannelResult.IsSuccess)
        {
            return(Result.FromError(getChannelResult));
        }

        var getGuildRolesResult = await _guildApi.GetGuildRolesAsync(ev.GuildID.Value, ct);

        if (!getGuildRolesResult.IsSuccess)
        {
            return(Result.FromError(getGuildRolesResult));
        }

        var channel      = getChannelResult.Entity;
        var guildRoles   = getGuildRolesResult.Entity;
        var everyoneRole = guildRoles.FirstOrDefault(r => r.ID == ev.GuildID.Value);

        if (everyoneRole is null)
        {
            return(new NotFoundError("No @everyone role found."));
        }

        var memberRoles         = guildRoles.Where(r => ev.Member.Value.Roles.Contains(r.ID)).ToList();
        var computedPermissions = channel.PermissionOverwrites.HasValue
            ? DiscordPermissionSet.ComputePermissions(ev.UserID, everyoneRole, memberRoles,
                                                      channel.PermissionOverwrites.Value)
            : DiscordPermissionSet.ComputePermissions(ev.UserID, everyoneRole, memberRoles);

        return(computedPermissions.HasPermission(DiscordPermission.Administrator) ||
               computedPermissions.HasPermission(DiscordPermission.BanMembers)
            ? Result.FromSuccess()
            : await _channelApi.DeleteUserReactionAsync(ev.ChannelID, ev.MessageID, ev.Emoji.Name.Value, ev.UserID,
                                                        ct));
    }
Exemplo n.º 10
0
    /// <inheritdoc />
    public async Task <Result> RespondAsync(IMessageUpdate ev, CancellationToken ct = default)
    {
        if (!ev.Attachments.HasValue ||
            ev.Attachments.Value.Count == 0 ||
            !ev.ID.HasValue ||
            !ev.Author.HasValue ||
            ev.Author.Value.IsBot.HasValue && ev.Author.Value.IsBot.Value ||
            !ev.GuildID.HasValue ||
            !ev.ChannelID.HasValue
            )
        {
            return(Result.FromSuccess());
        }

        var getChannelNameResult = await _channelApi.GetChannelAsync(ev.ChannelID.Value, ct);

        if (!getChannelNameResult.IsSuccess)
        {
            return(Result.FromError(getChannelNameResult));
        }

        var channelName = getChannelNameResult.Entity.Name;

        if (!channelName.HasValue)
        {
            return(new PropertyMissingOrNullError("Channel in which a potential application was sent has no name."));
        }

        // return if the message isn't in #member-apps;
        if (!channelName.Value.Equals(_discordSettings.ChannelNames.MemberApps))
        {
            return(Result.FromSuccess());
        }

        var res = await _mediator.Send(
            new UpdateFromDiscordMessage.Command {
            DiscordMessageUpdatedEvent = ev
        }, ct);

        if (res.IsSuccess)
        {
            _logger.LogInformation($"Updated the application for the message: {ev.ID.Value}");
        }

        return(res);
    }
Exemplo n.º 11
0
        /// <inheritdoc />
        public async ValueTask <DetermineConditionResult> CheckAsync(RequireContextAttribute attribute, CancellationToken ct)
        {
            var getChannel = await _channelAPI.GetChannelAsync(_context.ChannelID, ct);

            if (!getChannel.IsSuccess)
            {
                return(DetermineConditionResult.FromError(getChannel));
            }

            var channel = getChannel.Entity;

            switch (attribute.Context)
            {
            case ChannelContext.DM:
            {
                return(channel.Type is DM
                        ? DetermineConditionResult.FromSuccess()
                        : DetermineConditionResult.FromError("This command can only be used in a DM."));
            }

            case ChannelContext.GroupDM:
            {
                return(channel.Type is GroupDM
                        ? DetermineConditionResult.FromSuccess()
                        : DetermineConditionResult.FromError("This command can only be used in a group DM."));
            }

            case ChannelContext.Guild:
            {
                return(channel.Type is GuildText or GuildVoice or GuildCategory or GuildNews or GuildStore
                        ? DetermineConditionResult.FromSuccess()
                        : DetermineConditionResult.FromError("This command can only be used in a guild."));
            }

            default:
            {
                throw new ArgumentOutOfRangeException();
            }
            }
        }
Exemplo n.º 12
0
            protected override async Task Handle(TcpRequest <GenericCommandResult> request, CancellationToken cancellationToken)
            {
                var msg = request.Message;
                // we want an exception if failed, as the handler can't proceed if failed, hence Parse instead of TryParse;
                var parsedId         = ulong.Parse(request.Message.DiscordChannelId);
                var channelSnowflake = new Snowflake(parsedId);
                var getChannelResult = await _channelApi.GetChannelAsync(channelSnowflake, cancellationToken);

                if (!getChannelResult.IsSuccess || getChannelResult.Entity is null)
                {
                    throw new Exception(getChannelResult.Error?.Message ?? $"Could not get channel with ID {parsedId}");
                }

                // because why would ColorTranslator use the established pattern of TryParse
                // when it can have only one method that throws if it fails to parse instead
                // FFS
                Color colour;

                try
                {
                    colour = ColorTranslator.FromHtml(request.Message.Colour);
                }
                catch
                {
                    colour = _colourPalette.Blue;
                }

                var embeds = new List <Embed>
                {
                    new()
                    {
                        Title  = $"Command `{msg.Command}` executed!",
                        Fields = new List <EmbedField>
                        {
                            new("Server", msg.ServerId, false)
                        },
                        Timestamp = DateTimeOffset.UtcNow,
                        Colour    = colour
                    }
                };
Exemplo n.º 13
0
        /// <inheritdoc />
        public override async ValueTask <Result <IRole> > TryParse(string value, CancellationToken ct)
        {
            var getChannel = await _channelAPI.GetChannelAsync(_context.ChannelID, ct);

            if (!getChannel.IsSuccess)
            {
                return(Result <IRole> .FromError(getChannel));
            }

            var channel = getChannel.Entity;

            if (!channel.GuildID.HasValue)
            {
                return(new InvalidOperationError("You're not in a guild channel, so I can't get any roles."));
            }

            var getRoles = await _guildAPI.GetGuildRolesAsync(channel.GuildID.Value, ct);

            if (!getRoles.IsSuccess)
            {
                return(Result <IRole> .FromError(getRoles));
            }

            var roles = getRoles.Entity;

            if (!Snowflake.TryParse(value.Unmention(), out var roleID))
            {
                // Try a name-based lookup
                var roleByName = roles.FirstOrDefault(r => r.Name.Equals(value, StringComparison.OrdinalIgnoreCase));
                return(roleByName is not null
                    ? Result <IRole> .FromSuccess(roleByName)
                    : new ParsingError <IRole>(value.Unmention()));
            }

            var role = roles.FirstOrDefault(r => r.ID.Equals(roleID));

            return(role is not null
                ? Result <IRole> .FromSuccess(role)
                : new ParsingError <IRole>("No role with that ID could be found."));
        }
        /// <inheritdoc />
        public override async ValueTask <RetrieveEntityResult <IGuildMember> > TryParse(string value, CancellationToken ct)
        {
            if (!Snowflake.TryParse(value.Unmention(), out var guildMemberID))
            {
                return(RetrieveEntityResult <IGuildMember> .FromError
                       (
                           $"Failed to parse \"{value}\" as a guild member ID."
                       ));
            }

            var getChannel = await _channelAPI.GetChannelAsync(_context.ChannelID, ct);

            if (!getChannel.IsSuccess)
            {
                return(RetrieveEntityResult <IGuildMember> .FromError(getChannel));
            }

            var channel = getChannel.Entity;

            if (!channel.GuildID.HasValue)
            {
                return(RetrieveEntityResult <IGuildMember> .FromError
                       (
                           "You're not in a guild channel, so I can't get any guild members."
                       ));
            }

            var getGuildMember = await _guildAPI.GetGuildMemberAsync(channel.GuildID.Value, guildMemberID.Value, ct);

            if (!getGuildMember.IsSuccess)
            {
                return(RetrieveEntityResult <IGuildMember> .FromError(getGuildMember));
            }

            return(getGuildMember.IsSuccess
                ? RetrieveEntityResult <IGuildMember> .FromSuccess(getGuildMember.Entity)
                : RetrieveEntityResult <IGuildMember> .FromError("No guild member with that ID could be found."));
        }
Exemplo n.º 15
0
    public async Task <Result <FeedbackMessage> > SassAsync()
    {
        var getChannel = await _channelAPI.GetChannelAsync(_context.ChannelID, this.CancellationToken);

        if (!getChannel.IsSuccess)
        {
            return(Result <FeedbackMessage> .FromError(getChannel));
        }

        var channel = getChannel.Entity;

        var isNsfwChannel = channel.IsNsfw.IsDefined(out var isNsfw) && isNsfw;
        var getSassResult = await _sass.GetSassAsync(isNsfwChannel);

        if (!getSassResult.IsSuccess)
        {
            return(Result <FeedbackMessage> .FromError(getSassResult));
        }

        var sass = getSassResult.Entity;

        return(new FeedbackMessage(sass, _feedback.Theme.Secondary));
    }
Exemplo n.º 16
0
        /// <inheritdoc />
        public override async ValueTask <Result <IGuildMember> > TryParse(string value, CancellationToken ct)
        {
            if (!Snowflake.TryParse(value.Unmention(), out var guildMemberID))
            {
                return(new ParsingError <IGuildMember>(value));
            }

            var getChannel = await _channelAPI.GetChannelAsync(_context.ChannelID, ct);

            if (!getChannel.IsSuccess)
            {
                return(Result <IGuildMember> .FromError(getChannel));
            }

            var channel = getChannel.Entity;

            if (!channel.GuildID.HasValue)
            {
                return(new InvalidOperationError("You're not in a guild channel, so I can't get any guild members."));
            }

            return(await _guildAPI.GetGuildMemberAsync(channel.GuildID.Value, guildMemberID.Value, ct));
        }
Exemplo n.º 17
0
        public async Task Execute(IJobExecutionContext context)
        {
            var failures = await _dbContext.CheckHistory
                           .Include(x => x.Notification)
                           .Where(x => !x.Success && x.Notification == null)
                           .ToListAsync();

            if (failures.Count == 0)
            {
                return;
            }

            if (_config.Value == null)
            {
                throw new Exception("Missing or invalid Discord configuration, cannot dispatch failure notifications");
            }

            // Don't bother if we haven't configured a channel to use
            if (_config.Value.FailureChannel == null)
            {
                return;
            }

            // Get channel, check it exists
            var channelRequest = await _channelAPI.GetChannelAsync(new Snowflake(_config.Value.FailureChannel.Value));

            if (!channelRequest.IsSuccess || channelRequest.Entity == null)
            {
                throw new Exception("Failed to get Discord channel to dispatch parse failure notifications into.");
            }

            var notified = new List <NotifiedFailure>();
            var channel  = channelRequest.Entity;

            foreach (var failure in failures)
            {
                // Attach text content of response where available
                FileData fileData      = null;
                var      messageSuffix = "The content of the response was missing or empty.";
                if (failure.ResponseContent != null)
                {
                    var dataStream = new MemoryStream();
                    var writer     = new StreamWriter(dataStream);
                    await writer.WriteAsync(failure.ResponseContent);

                    dataStream.Seek(0, SeekOrigin.Begin);
                    fileData      = new FileData("response_content.txt", dataStream);
                    messageSuffix = "The content of the response is attached to this message.";
                }

                var message = new StringBuilder();
                if (_config.Value.FailureMention.HasValue)
                {
                    message.Append($"<@{_config.Value.FailureMention}> ");
                }
                message.Append(
                    $"Failed to parse bans for {failure.Parser} at <t:{failure.Failed.Value.ToUnixTimeSeconds()}>, exception is as follows... ```");

                // Ensure that our length fits
                var currLength = message.Length + failure.Exception.Length + messageSuffix.Length + 3;
                message.Append(currLength > 2000
                    ? $"{failure.Exception[0..^(currLength - 2000 + 4)]}...```"
Exemplo n.º 18
0
        /// <inheritdoc />
        public async ValueTask <Result> CheckHasRequiredPermission(
            DiscordPermission permission,
            Snowflake channelId,
            IUser userToCheck,
            CancellationToken ct = default
            )
        {
            var getChannel = await _channelApi.GetChannelAsync(channelId, ct);

            if (!getChannel.IsSuccess)
            {
                return(Result.FromError(getChannel));
            }

            var channel = getChannel.Entity;

            if (!channel.GuildID.HasValue)
            {
                return(new ConditionNotSatisfiedError(
                           "Command requires a guild permission but was executed outside of a guild."));
            }

            var guildId = channel.GuildID.Value;

            var getGuildMember = await _guildApi.GetGuildMemberAsync(guildId, userToCheck.ID, ct);

            if (!getGuildMember.IsSuccess)
            {
                return(Result.FromError(getGuildMember));
            }

            var getGuildRoles = await _guildApi.GetGuildRolesAsync(guildId, ct);

            if (!getGuildRoles.IsSuccess)
            {
                return(Result.FromError(getGuildRoles));
            }

            var guildRoles   = getGuildRoles.Entity;
            var everyoneRole = guildRoles.FirstOrDefault(r => r.Name.Equals("@everyone"));

            if (everyoneRole is null)
            {
                return(new NotFoundError("No @everyone role found."));
            }

            var user = getGuildMember.Entity;

            if (user is null)
            {
                return(new NotFoundError("Executing user not found"));
            }

            var getGuild = await _guildApi.GetGuildAsync(guildId, ct : ct);

            if (!getGuild.IsSuccess)
            {
                return(Result.FromError(getGuild));
            }

            var guildOwnerId = getGuild.Entity.OwnerID;

            // succeed if the user is the Owner of the guild
            if (guildOwnerId.Equals(userToCheck.ID))
            {
                return(Result.FromSuccess());
            }

            var memberRoles = guildRoles.Where(r => user.Roles.Contains(r.ID)).ToList();
            IDiscordPermissionSet computedPermissions;

            if (channel.PermissionOverwrites.HasValue)
            {
                computedPermissions = DiscordPermissionSet.ComputePermissions(
                    userToCheck.ID,
                    everyoneRole,
                    memberRoles,
                    channel.PermissionOverwrites.Value
                    );
            }
            else
            {
                computedPermissions = DiscordPermissionSet.ComputePermissions(
                    userToCheck.ID,
                    everyoneRole,
                    memberRoles
                    );
            }

            // succeed if the user is an Administrator of the guild
            if (computedPermissions.HasPermission(DiscordPermission.Administrator))
            {
                return(Result.FromSuccess());
            }

            var hasPermission = computedPermissions.HasPermission(permission);

            return(!hasPermission
                ? new ConditionNotSatisfiedError(
                       $"Guild User requesting the command does not have the required {permission.ToString()} permission")
                : Result.FromSuccess());
        }
Exemplo n.º 19
0
    /// <summary>
    /// Starts the given roleplay in the current channel, or the dedicated channel if one exists.
    /// </summary>
    /// <param name="currentChannelID">The current channel.</param>
    /// <param name="roleplay">The roleplay.</param>
    /// <returns>A modification result which may or may not have succeeded.</returns>
    public async Task <Result> StartRoleplayAsync(Snowflake currentChannelID, Roleplay roleplay)
    {
        var getDedicatedChannelResult = DedicatedChannelService.GetDedicatedChannel(roleplay);

        // Identify the channel to start the RP in. Preference is given to the roleplay's dedicated channel.
        var channelID  = getDedicatedChannelResult.IsSuccess ? getDedicatedChannelResult.Entity : currentChannelID;
        var getChannel = await _channelAPI.GetChannelAsync(channelID);

        if (!getChannel.IsSuccess)
        {
            return(Result.FromError(getChannel));
        }

        var channel = getChannel.Entity;

        if (roleplay.IsNSFW && !(channel.IsNsfw.HasValue && channel.IsNsfw.Value))
        {
            return(new UserError
                   (
                       "This channel is not marked as NSFW, while your roleplay is... naughty!"
                   ));
        }

        var getHasActiveRoleplay = await HasActiveRoleplayAsync(channelID);

        if (!getHasActiveRoleplay.IsSuccess)
        {
            return(Result.FromError(getHasActiveRoleplay));
        }

        if (getHasActiveRoleplay.Entity)
        {
            var currentRoleplayResult = await GetActiveRoleplayAsync(channelID);

            if (!currentRoleplayResult.IsSuccess)
            {
                return(Result.FromError(currentRoleplayResult));
            }

            var currentRoleplay   = currentRoleplayResult.Entity;
            var timeOfLastMessage = currentRoleplay.Messages.Last().Timestamp;
            var currentTime       = DateTimeOffset.UtcNow;

            if (timeOfLastMessage < currentTime.AddHours(-4))
            {
                currentRoleplay.IsActive = false;
            }
            else
            {
                return(new UserError("There's already a roleplay active in this channel."));
            }
        }

        var start = await _roleplays.StartRoleplayAsync(roleplay, channelID);

        if (!start.IsSuccess)
        {
            return(start);
        }

        // If the channel in question is the roleplay's dedicated channel, enable it
        if (!roleplay.DedicatedChannelID.HasValue)
        {
            return(Result.FromSuccess());
        }

        var enableChannel = await _dedicatedChannels.UpdateParticipantPermissionsAsync(roleplay);

        if (!enableChannel.IsSuccess)
        {
            return(enableChannel);
        }

        var joinedUsers = roleplay.JoinedUsers.Select
                          (
            u => $"<@{u.User.DiscordID}>"
                          );

        var participantList = joinedUsers.Humanize();

        var send = await _channelAPI.CreateMessageAsync
                   (
            roleplay.ActiveChannelID !.Value,
            $"Calling {participantList}!"
                   );

        return(!send.IsSuccess
            ? Result.FromError(send)
            : Result.FromSuccess());
    }
Exemplo n.º 20
0
    /// <inheritdoc />
    public async ValueTask <Result> CheckHasRequiredPermission(
        DiscordPermission permission,
        Snowflake channelId,
        IUser userToCheck,
        CancellationToken ct = default
        )
    {
        var getChannel = await _channelApi.GetChannelAsync(channelId, ct);

        if (!getChannel.IsSuccess)
        {
            return(Result.FromError(getChannel));
        }

        var channel = getChannel.Entity;

        if (!channel.GuildID.HasValue)
        {
            return(new ConditionNotSatisfiedError(
                       "Command requires a guild permission but was executed outside of a guild."));
        }

        var guildId = channel.GuildID.Value;

        var getGuildMember = await _guildApi.GetGuildMemberAsync(guildId, userToCheck.ID, ct);

        if (!getGuildMember.IsSuccess)
        {
            return(Result.FromError(getGuildMember));
        }

        var getGuildRoles = await _guildApi.GetGuildRolesAsync(guildId, ct);

        if (!getGuildRoles.IsSuccess)
        {
            return(Result.FromError(getGuildRoles));
        }

        var guildRoles   = getGuildRoles.Entity;
        var everyoneRole = guildRoles.FirstOrDefault(r => r.Name.Equals("@everyone"));

        if (everyoneRole is null)
        {
            return(new NotFoundError("No @everyone role found."));
        }

        var user = getGuildMember.Entity;

        if (user is null)
        {
            return(new NotFoundError("Executing user not found"));
        }

        var getGuild = await _guildApi.GetGuildAsync(guildId, ct : ct);

        if (!getGuild.IsSuccess)
        {
            return(Result.FromError(getGuild));
        }

        var guildOwnerId = getGuild.Entity.OwnerID;

        // succeed if the user is the Owner of the guild
        if (guildOwnerId.Equals(userToCheck.ID))
        {
            return(Result.FromSuccess());
        }

        var memberRoles         = guildRoles.Where(r => user.Roles.Contains(r.ID)).ToList();
        var computedPermissions = channel.PermissionOverwrites switch
        {
            { HasValue : true, Value : { } overwrites } => DiscordPermissionSet.ComputePermissions(